Bernt Christian Egeland 1 месяц назад
Родитель
Сommit
71f6d5f530
100 измененных файлов с 5820 добавлено и 872 удалено
  1. 11 0
      init-db.sh
  2. 11 1
      messages/de/audit.json
  3. 3 3
      messages/de/billing.json
  4. 16 3
      messages/de/calendar.json
  5. 24 0
      messages/de/common.json
  6. 396 0
      messages/de/inspections.json
  7. 29 2
      messages/de/messages.json
  8. 2 3
      messages/de/navigation.json
  9. 31 1
      messages/de/pdf.json
  10. 76 0
      messages/de/scheduledMessages.json
  11. 57 45
      messages/de/settings.json
  12. 47 1
      messages/de/share.json
  13. 9 8
      messages/de/statusReport.json
  14. 2 2
      messages/de/vehicles.json
  15. 11 1
      messages/en/audit.json
  16. 16 3
      messages/en/calendar.json
  17. 24 0
      messages/en/common.json
  18. 396 0
      messages/en/inspections.json
  19. 29 2
      messages/en/messages.json
  20. 2 3
      messages/en/navigation.json
  21. 31 1
      messages/en/pdf.json
  22. 76 0
      messages/en/scheduledMessages.json
  23. 14 2
      messages/en/settings.json
  24. 47 1
      messages/en/share.json
  25. 8 7
      messages/en/statusReport.json
  26. 3 3
      messages/en/vehicles.json
  27. 11 1
      messages/es/audit.json
  28. 32 32
      messages/es/auth.json
  29. 4 4
      messages/es/billing.json
  30. 16 3
      messages/es/calendar.json
  31. 29 5
      messages/es/common.json
  32. 396 0
      messages/es/inspections.json
  33. 29 2
      messages/es/messages.json
  34. 2 3
      messages/es/navigation.json
  35. 31 1
      messages/es/pdf.json
  36. 76 0
      messages/es/scheduledMessages.json
  37. 233 221
      messages/es/settings.json
  38. 47 1
      messages/es/share.json
  39. 9 8
      messages/es/statusReport.json
  40. 59 59
      messages/es/vehicles.json
  41. 11 1
      messages/fr/audit.json
  42. 3 3
      messages/fr/billing.json
  43. 16 3
      messages/fr/calendar.json
  44. 24 0
      messages/fr/common.json
  45. 396 0
      messages/fr/inspections.json
  46. 29 2
      messages/fr/messages.json
  47. 2 3
      messages/fr/navigation.json
  48. 31 1
      messages/fr/pdf.json
  49. 76 0
      messages/fr/scheduledMessages.json
  50. 262 250
      messages/fr/settings.json
  51. 47 1
      messages/fr/share.json
  52. 9 8
      messages/fr/statusReport.json
  53. 3 3
      messages/fr/vehicles.json
  54. 11 1
      messages/it/audit.json
  55. 4 4
      messages/it/billing.json
  56. 16 3
      messages/it/calendar.json
  57. 24 0
      messages/it/common.json
  58. 396 0
      messages/it/inspections.json
  59. 29 2
      messages/it/messages.json
  60. 2 3
      messages/it/navigation.json
  61. 31 1
      messages/it/pdf.json
  62. 76 0
      messages/it/scheduledMessages.json
  63. 15 3
      messages/it/settings.json
  64. 47 1
      messages/it/share.json
  65. 9 8
      messages/it/statusReport.json
  66. 2 2
      messages/it/vehicles.json
  67. 11 1
      messages/lt/audit.json
  68. 4 4
      messages/lt/billing.json
  69. 16 3
      messages/lt/calendar.json
  70. 24 0
      messages/lt/common.json
  71. 396 0
      messages/lt/inspections.json
  72. 29 2
      messages/lt/messages.json
  73. 2 3
      messages/lt/navigation.json
  74. 31 1
      messages/lt/pdf.json
  75. 76 0
      messages/lt/scheduledMessages.json
  76. 14 2
      messages/lt/settings.json
  77. 47 1
      messages/lt/share.json
  78. 1 0
      messages/lt/statusReport.json
  79. 3 3
      messages/lt/vehicles.json
  80. 11 1
      messages/nb/audit.json
  81. 3 3
      messages/nb/billing.json
  82. 16 3
      messages/nb/calendar.json
  83. 24 0
      messages/nb/common.json
  84. 396 0
      messages/nb/inspections.json
  85. 29 2
      messages/nb/messages.json
  86. 2 3
      messages/nb/navigation.json
  87. 31 1
      messages/nb/pdf.json
  88. 76 0
      messages/nb/scheduledMessages.json
  89. 49 37
      messages/nb/settings.json
  90. 47 1
      messages/nb/share.json
  91. 9 8
      messages/nb/statusReport.json
  92. 44 44
      messages/nb/vehicles.json
  93. 11 1
      messages/nl/audit.json
  94. 4 4
      messages/nl/billing.json
  95. 16 3
      messages/nl/calendar.json
  96. 24 0
      messages/nl/common.json
  97. 396 0
      messages/nl/inspections.json
  98. 29 2
      messages/nl/messages.json
  99. 2 3
      messages/nl/navigation.json
  100. 31 1
      messages/nl/pdf.json

+ 11 - 0
init-db.sh

@@ -28,5 +28,16 @@ if ! npx prisma migrate deploy 2>/dev/null; then
 fi
 echo "Migrations applied successfully!"
 
+# Photo embedding is the one thing here that depends on a native module, and
+# sharp's prebuilt binaries need an x86-64-v2 CPU. Some virtualised hosts do not
+# advertise one — Proxmox's default kvm64 processor model, for instance, reports
+# a baseline x86-64 even on modern hardware. Report it at boot rather than
+# leaving it to be found when a certificate comes out without its photos.
+# Never fatal: everything else in the app works without it.
+if ! sharp_error=$(node -e "require('sharp')" 2>&1); then
+  echo "WARNING: sharp could not be loaded. Inspection certificates will render without photos."
+  echo "$sharp_error" | sed 's/^/  /'
+fi
+
 echo "Starting application..."
 exec $cmd

+ 11 - 1
messages/de/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Webhook erstellt",
     "webhook_update": "Webhook aktualisiert",
     "webhook_delete": "Webhook gelöscht",
-    "webhook_rotateSecret": "Webhook-Schlüssel rotiert"
+    "webhook_rotateSecret": "Webhook-Schlüssel rotiert",
+    "inspection_reopen": "Inspektion wieder geöffnet",
+    "inspectionTemplate_import": "Inspektionsvorlage importiert",
+    "scheduled_message_create": "Geplante Nachricht erstellt",
+    "scheduled_message_update": "Geplante Nachricht aktualisiert",
+    "scheduled_message_delete": "Geplante Nachricht gelöscht",
+    "scheduled_message_cancel": "Geplante Nachricht abgebrochen",
+    "scheduled_message_send_now": "Geplante Nachricht gesendet",
+    "settings_applyTaxRate": "Steuersatz angewendet",
+    "settings_convertToExclusive": "Preise auf netto umgestellt",
+    "settings_convertToInclusive": "Preise auf brutto umgestellt"
   }
 }

+ 3 - 3
messages/de/billing.json

@@ -80,8 +80,8 @@
     "processed": "{count} Rechnung(en) verarbeitet",
     "failedProcess": "Verarbeitung fehlgeschlagen",
     "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "resume": "Fortsetzen",
+    "delete": "Löschen",
+    "removeRow": "Zeile entfernen"
   }
 }

+ 16 - 3
messages/de/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Aufträge",
     "reminders": "Erinnerungen",
-    "quotes": "Angebote"
+    "quotes": "Angebote",
+    "messages": "Nachrichten"
   },
   "selectVehicle": "Fahrzeug für Arbeitsauftrag auswählen",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} weitere",
+  "monthTotal": "{count} Termine in diesem Monat",
+  "contextMenu": {
+    "newWorkOrder": "Neuer Arbeitsauftrag",
+    "newReminder": "Neue Erinnerung",
+    "newQuote": "Neues Angebot",
+    "openEvent": "Öffnen ({count})",
+    "hint": "Tipp: Rechtsklick auf einen Tag zeigt Aktionen",
+    "scheduleMessage": "Nachricht planen"
+  },
   "events": {
     "status": {
       "completed": "Abgeschlossen",
@@ -54,12 +64,15 @@
       "draft": "Entwurf",
       "done": "Erledigt",
       "overdue": "Überfällig",
-      "upcoming": "Bevorstehend"
+      "upcoming": "Bevorstehend",
+      "failed": "Fehlgeschlagen",
+      "queued": "In Warteschlange"
     },
     "type": {
       "service": "Service",
       "reminder": "Erinnerung",
-      "quote": "Angebot"
+      "quote": "Angebot",
+      "message": "Nachricht"
     },
     "noEvents": "Keine Ereignisse",
     "selectDay": "Wählen Sie einen Tag mit Ereignissen oder erstellen Sie einen neuen Arbeitsauftrag."

+ 24 - 0
messages/de/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice wurde auf {version} aktualisiert",
     "whatsNew": "Neuigkeiten ansehen",
     "dismiss": "Schließen"
+  },
+  "pagination": {
+    "showing": "{start}–{end} von {total}",
+    "perPage": "pro Seite",
+    "pageOf": "Seite {page} von {pages}",
+    "first": "Erste Seite",
+    "previous": "Vorherige Seite",
+    "next": "Nächste Seite",
+    "last": "Letzte Seite"
+  },
+  "shared": {
+    "close": "Schließen",
+    "viewPlans": "Tarife ansehen",
+    "manageLicense": "Lizenz verwalten",
+    "installOwn": "Eigene Instanz installieren",
+    "install": "Installieren",
+    "installApp": "App installieren",
+    "installTorqvoice": "Torqvoice installieren",
+    "dismiss": "Schließen",
+    "useCamera": "Kamera verwenden",
+    "enterManually": "Manuell eingeben",
+    "enterBarcode": "Barcode eingeben…",
+    "scanHint": "Richten Sie die Kamera auf einen Barcode oder geben Sie ihn manuell ein",
+    "iosInstallHint": "Auf Teilen > Zum Home-Bildschirm tippen"
   }
 }

+ 396 - 0
messages/de/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Kein Mangel",
+      "attention": "Geringer Mangel",
+      "fail": "Erheblicher Mangel",
+      "dangerous": "Gefährlicher Mangel",
+      "not_inspected": "Nicht geprüft"
+    },
+    "basic": {
+      "pass": "Bestanden",
+      "attention": "Achtung",
+      "fail": "Durchgefallen",
+      "dangerous": "Gefährlich",
+      "not_inspected": "Nicht geprüft"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Gering",
+      "fail": "Erheblich",
+      "dangerous": "Gefährlich",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Erfüllt die Anforderungen. Nichts zu melden.",
+      "attention": "Ohne wesentliche Auswirkung auf die Sicherheit. Fahrzeug besteht; bei Gelegenheit beheben.",
+      "fail": "Kann die Sicherheit beeinträchtigen oder die Umwelt belasten. Fahrzeug besteht nicht; beheben und nachprüfen lassen.",
+      "dangerous": "Unmittelbare Gefahr für die Verkehrssicherheit. Das Fahrzeug darf nicht gefahren werden.",
+      "not_inspected": "Dieser Prüfpunkt wurde nicht durchgeführt."
+    }
+  },
+  "results": {
+    "pass": "Bestanden",
+    "pass_minor": "Bestanden mit geringen Mängeln",
+    "fail": "Nicht bestanden — erhebliche Mängel",
+    "fail_dangerous": "Nicht bestanden — gefährliche Mängel",
+    "incomplete": "Nicht abgeschlossen",
+    "detail": {
+      "pass": "Es wurden keine Mängel festgestellt.",
+      "pass_minor": "Das Fahrzeug hat bestanden. Beheben Sie die geringen Mängel ohne unnötige Verzögerung.",
+      "fail": "Das Fahrzeug hat nicht bestanden. Die Mängel müssen behoben und das Fahrzeug erneut geprüft werden.",
+      "fail_dangerous": "Das Fahrzeug darf bis zur Behebung der gefährlichen Mängel nicht im öffentlichen Straßenverkehr genutzt werden.",
+      "incomplete": "Diese Prüfung läuft noch."
+    }
+  },
+  "page": {
+    "back": "Inspektionen",
+    "statusInProgress": "Läuft",
+    "statusCompleted": "Abgeschlossen",
+    "complete": "Abschließen",
+    "reopen": "Wieder öffnen",
+    "share": "Teilen",
+    "save": "Speichern",
+    "saving": "Speichert…",
+    "savedAt": "Gespeichert {time}",
+    "savesAsYouGo": "Speichert laufend",
+    "saveFailed": "Einige Änderungen wurden nicht gespeichert",
+    "allSaved": "Alle Änderungen sind gespeichert",
+    "moreActions": "Weitere Aktionen",
+    "downloadCertificate": "Prüfbericht herunterladen",
+    "manageTemplates": "Vorlagen verwalten",
+    "delete": "Löschen",
+    "createWorkOrder": "Auftrag anlegen",
+    "viewWorkOrder": "Auftrag anzeigen",
+    "createQuote": "Angebot anlegen",
+    "viewQuote": "Angebot anzeigen",
+    "needsDefect": "Verfügbar, sobald ein Mangel erfasst ist",
+    "workOrderRaised": "Auftrag {number} am {date} aus dieser Inspektion angelegt",
+    "open": "Öffnen",
+    "quoteCreated": "Angebot von {name} am {date} angelegt",
+    "quoteRequested": "Der Kunde hat ein Angebot zu {count} Prüfpunkt(en) angefragt",
+    "stillToGrade": "{count} von {total} Prüfpunkten sind noch zu bewerten.",
+    "progress": "Fortschritt",
+    "checksGraded": "Prüfpunkte bewertet",
+    "progressLabel": "{graded} von {total} Prüfpunkten bewertet: {pass} kein Mangel, {attention} gering, {fail} erheblich, {dangerous} gefährlich.",
+    "sections": "Gruppen",
+    "graded": "{graded}/{total} bewertet",
+    "vehicle": "Fahrzeug",
+    "vessel": "Wasserfahrzeug",
+    "customer": "Kunde",
+    "plate": "Kennzeichen",
+    "registration": "Registrierung",
+    "template": "Vorlage",
+    "scaleEu": "Bewertet nach der EU-Mängelskala aus Richtlinie 2014/45/EU.",
+    "scaleBasic": "Bewertet bestanden / Achtung / durchgefallen.",
+    "country": "Land: {code}.",
+    "manageInspectionTemplates": "Inspektionsvorlagen verwalten",
+    "readMore": "Mehr erfahren",
+    "odometer": "Kilometerstand",
+    "engineHours": "Betriebsstunden",
+    "completeTitle": "Diese Inspektion abschließen?",
+    "completeBody": "Die Prüfpunkte werden mit dem Abschluss gesperrt, und das Ergebnis lautet dann „{result}“.",
+    "completeBlocked": "{count} von der Vorlage als Pflicht markierte Prüfpunkte sind offen.",
+    "completeUngraded": "{count} Prüfpunkt(e) wurden nicht bewertet.",
+    "completeDangerous": "{count} gefährliche(r) Mangel erfasst. Das Fahrzeug darf nicht am öffentlichen Verkehr teilnehmen.",
+    "reopenTitle": "Diese Inspektion wieder öffnen?",
+    "reopenBody": "Die Prüfpunkte werden wieder bearbeitbar und das Ergebnis geht zurück auf laufend. Prüfer, Bescheinigungsnummer und nächster Prüftermin bleiben erhalten.",
+    "reopenShared": "Der Kundenlink bleibt aktiv und zeigt, wie sich das Ergebnis während Ihrer Bearbeitung ändert. Ein bereits heruntergeladener Prüfbericht behält das alte Ergebnis.",
+    "deleteTitle": "Diese Inspektion löschen?",
+    "deleteBody": "Damit werden die Inspektion, ihre Bewertungen, Notizen und Fotos dauerhaft gelöscht. Das lässt sich nicht rückgängig machen.",
+    "cancel": "Abbrechen",
+    "completed": "Inspektion abgeschlossen",
+    "reopened": "Inspektion wieder geöffnet",
+    "deleted": "Inspektion gelöscht",
+    "completeFailed": "Inspektion konnte nicht abgeschlossen werden",
+    "reopenFailed": "Inspektion konnte nicht wieder geöffnet werden",
+    "deleteFailed": "Inspektion konnte nicht gelöscht werden",
+    "quoteFailed": "Angebot konnte nicht angelegt werden",
+    "workOrderFailed": "Auftrag konnte nicht angelegt werden"
+  },
+  "item": {
+    "required": "(Pflicht)",
+    "saving": "Speichert",
+    "addNote": "Notiz hinzufügen",
+    "hideNote": "Notiz ausblenden",
+    "addPhoto": "Foto oder Video zu {name} hinzufügen",
+    "notesFor": "Notizen zu {name}",
+    "describeDefect": "Mangel beschreiben — erscheint im Bericht",
+    "optionalNote": "Notiz hinzufügen (optional)",
+    "notesRequired": "Beschreiben Sie den Mangel, bevor diese Bewertung gespeichert wird.",
+    "photoRequired": "Hier ist ein Foto des Mangels erforderlich. Die Inspektion kann erst abgeschlossen werden, wenn eines angehängt ist.",
+    "reading": "Messwert",
+    "readingUnit": "Messwert ({unit})",
+    "limit": "Grenzwert: {range}",
+    "recordedValue": "Erfasster Wert",
+    "answer": "Antwort",
+    "selectAnswer": "Antwort wählen",
+    "viewPhoto": "Foto {index} von {name} in voller Größe ansehen",
+    "photoAlt": "{name}, Foto {index}",
+    "removePhoto": "Foto {index} von {name} entfernen",
+    "clearTitle": "Diese Bewertung entfernen?",
+    "clearBody": "Die zu „{name}“ erfasste Notiz wird entfernt und der Prüfpunkt geht zurück auf nicht geprüft.",
+    "clear": "Entfernen",
+    "cancel": "Abbrechen",
+    "saveFailed": "Dieser Prüfpunkt konnte nicht gespeichert werden",
+    "uploadFailed": "Upload fehlgeschlagen",
+    "uploadFailedFor": "{name} konnte nicht hochgeladen werden"
+  },
+  "suggestions": {
+    "title": "Häufige Mängel",
+    "add": "„{text}“ hinzufügen und als {grade} bewerten",
+    "more": "Weitere ({count})",
+    "search": "Mängeltext suchen",
+    "empty": "Kein passender Text.",
+    "source": {
+      "workshop": "Ihre Werkstatt",
+      "history": "Schon verwendet",
+      "regulation": "Richtlinie 2014/45/EU",
+      "general": "Allgemein"
+    }
+  },
+  "media": {
+    "viewer": "Bild {index} von {total}: {caption}",
+    "close": "Bildansicht schließen",
+    "previous": "Vorheriges Bild",
+    "next": "Nächstes Bild"
+  },
+  "certificate": {
+    "title": "Angaben zum Prüfbericht",
+    "description": "Nach Richtlinie 2014/45/EU, Anhang IV, auf einem Prüfbericht erforderlich.",
+    "inspector": "Prüfer",
+    "notRecorded": "Nicht erfasst",
+    "addTechnician": "Mechaniker hinzufügen…",
+    "recordedAs": "Erfasst als {name}",
+    "vehicleCategory": "Fahrzeugklasse",
+    "mileageAtTest": "{label} zum Zeitpunkt der Prüfung",
+    "reportReference": "Berichtsreferenz",
+    "reportReferenceHelp": "Ihre eigene Referenz für diesen Bericht. Wenn Sie als anerkannte Prüfstelle einen amtlichen Prüfbericht ausstellen, tragen Sie hier dessen Nummer ein, damit beide übereinstimmen. Andernfalls lassen Sie das Feld leer.",
+    "optional": "Optional",
+    "placeOfTest": "Prüfort",
+    "placeholderAddress": "Prüfstelle oder Werkstattadresse",
+    "fromSettings": "Aus Ihren Werkstatteinstellungen.",
+    "change": "Ändern",
+    "differsFromWorkshop": "Weicht von Ihrer Werkstattadresse ab.",
+    "useWorkshopAddress": "Werkstattadresse verwenden",
+    "noWorkshopAddress": "Es ist keine Werkstattadresse hinterlegt.",
+    "addOne": "Eine hinterlegen",
+    "nextTestDue": "Nächste Prüfung fällig",
+    "notSet": "Nicht gesetzt",
+    "intervalGroup": "Nächsten Prüftermin ab dem Datum dieser Prüfung setzen",
+    "intervalHelp": "Gerechnet ab dem Datum dieser Prüfung. Zwei Jahre ist der EU-Ausgangswert für Pkw und leichte Nutzfahrzeuge; prüfen Sie das in Ihrem Land geltende Intervall.",
+    "months6": "6 Monate",
+    "years1": "1 Jahr",
+    "years2": "2 Jahre",
+    "years3": "3 Jahre",
+    "years4": "4 Jahre",
+    "unsaved": "Nicht gespeicherte Änderungen",
+    "saveDetails": "Angaben speichern",
+    "saved": "Angaben gespeichert",
+    "saveFailed": "Die Angaben konnten nicht gespeichert werden",
+    "addTechnicianTitle": "Mechaniker hinzufügen",
+    "addTechnicianBody": "Die Person kommt in die Werkstattliste und kann sowohl Arbeiten als auch Inspektionen zugewiesen bekommen.",
+    "technicianName": "Name",
+    "technicianPlaceholder": "z. B. Anna Berg",
+    "addAndSelect": "Hinzufügen und auswählen",
+    "technicianAdded": "{name} hinzugefügt und ausgewählt",
+    "technicianFailed": "Der Mechaniker konnte nicht hinzugefügt werden",
+    "cancel": "Abbrechen"
+  },
+  "templates": {
+    "title": "Inspektionsvorlagen",
+    "description": "Die Prüflisten, die Ihre Mechaniker durchgehen. Legen Sie eine je Land, je Fahrzeugtyp oder je angebotener Leistung an.",
+    "import": "Importieren",
+    "browse": "Prüflisten durchsuchen",
+    "new": "Neue Vorlage",
+    "restoreBanner": "{count} fertige Prüflisten wurden aus Ihrer Liste entfernt. Sie können sie zurückholen.",
+    "restore": "Zurückholen",
+    "restored": "{count} Prüfliste(n) zurückgeholt",
+    "allPresent": "Alle Prüflisten sind bereits vorhanden",
+    "restoreFailed": "Die Prüflisten konnten nicht hinzugefügt werden",
+    "emptyTitle": "Noch keine Vorlagen",
+    "emptyBody": "Die fertigen Prüflisten, einschließlich der periodischen EU-Fahrzeugprüfung, wurden alle entfernt. Holen Sie sie zurück oder bauen Sie Ihre eigene von Grund auf.",
+    "restoreChecklists": "Prüflisten zurückholen",
+    "buildMyOwn": "Eigene bauen",
+    "default": "Standard",
+    "actionsFor": "Aktionen für {name}",
+    "edit": "Bearbeiten",
+    "duplicate": "Duplizieren",
+    "export": "Exportieren…",
+    "delete": "Löschen",
+    "sections": "{count} Gruppe(n)",
+    "checks": "{count} Prüfpunkt(e)",
+    "measured": "{count} gemessen",
+    "euScale": "EU-Mängelskala",
+    "basicScale": "Bestanden / Achtung / durchgefallen",
+    "deleteTitle": "„{name}“ löschen?",
+    "deleteBody": "Damit wird die Vorlage dauerhaft gelöscht. Bereits durchgeführte Inspektionen behalten ihre eigene Kopie der Prüfliste und sind nicht betroffen.",
+    "deleted": "Vorlage gelöscht",
+    "deleteFailed": "Vorlage konnte nicht gelöscht werden",
+    "duplicated": "Vorlage dupliziert",
+    "duplicateFailed": "Vorlage konnte nicht dupliziert werden",
+    "cancel": "Abbrechen",
+    "srSections": "Gruppen",
+    "srChecks": "Prüfpunkte",
+    "srMeasurements": "Messwerte"
+  },
+  "presets": {
+    "title": "Mit einer Vorlage beginnen",
+    "description": "Jede Vorlage wird als normale Vorlage in Ihre Werkstatt kopiert. Benennen Sie Gruppen um, verschieben Sie Prüfpunkte und ändern Sie jeden Grenzwert passend zu Ihrem Land und Ihrer Ausrüstung.",
+    "search": "Nach Name, Land oder Standard suchen",
+    "searchLabel": "Vorlagen suchen",
+    "inYourList": "In Ihrer Liste",
+    "counts": "{sections} Gruppen · {checks} Prüfpunkte",
+    "noMatch": "Keine Vorlage passt zu „{query}“.",
+    "warning": "Die gesetzlichen Vorlagen enthalten die üblichen EU-Grenzwerte. Prüfen Sie sie gegen Ihre nationalen Vorschriften, bevor Sie einen Prüfbericht ausstellen.",
+    "cancel": "Abbrechen",
+    "add": "Vorlage hinzufügen",
+    "added": "Vorlage hinzugefügt. Passen Sie sie an Ihre Werkstatt an.",
+    "addFailed": "Vorlage konnte nicht hinzugefügt werden",
+    "group": {
+      "regulatory": "Gesetzlich",
+      "workshop": "Werkstatt",
+      "specialist": "Spezialisiert"
+    },
+    "groupDescription": {
+      "regulatory": "Prüflisten für die periodische Fahrzeugprüfung auf Basis der Richtlinie 2014/45/EU.",
+      "workshop": "Allgemeine Service- und Verkaufsprüflisten ohne Bezug zu einer Vorschrift.",
+      "specialist": "Prüflisten für Antriebe und Wasserfahrzeuge, die ein eigenes Verfahren brauchen."
+    },
+    "euScale": "EU-Mängelskala",
+    "basicScale": "Bestanden / Achtung / durchgefallen"
+  },
+  "builder": {
+    "newTitle": "Neue Vorlage",
+    "editTitle": "Vorlage bearbeiten",
+    "description": "Bauen Sie die Prüfliste, die Ihre Werkstatt tatsächlich verwendet. Ziehen Sie zum Umsortieren und richten Sie jeden Prüfpunkt so ein, dass er eine Bewertung, einen Messwert, eine geschriebene Notiz oder eine feste Antwort erfasst.",
+    "name": "Name",
+    "namePlaceholder": "z. B. Periodische Fahrzeugprüfung",
+    "templateDescription": "Beschreibung",
+    "descriptionPlaceholder": "Wofür diese Prüfliste da ist und wann sie verwendet wird.",
+    "country": "Land",
+    "notCountrySpecific": "Nicht länderspezifisch",
+    "countryHelp": "Wird im Bericht vermerkt, damit eine grenzüberschreitend tätige Werkstatt ihre Prüflisten auseinanderhalten kann.",
+    "defectScale": "Mängelskala",
+    "scaleEu": "Gering / erheblich / gefährlich (EU)",
+    "scaleBasic": "Bestanden / Achtung / durchgefallen",
+    "scaleEuHelp": "Die Kategorien aus Artikel 7 Absatz 2 der Richtlinie 2014/45/EU. Ein Fahrzeug mit ausschließlich geringen Mängeln besteht weiterhin.",
+    "scaleBasicHelp": "Eine einfache dreistufige Skala für Serviceprüflisten, die keine gesetzliche Untersuchung sind.",
+    "defaultTemplate": "Standardvorlage",
+    "defaultHelp": "Vorausgewählt, wenn ein Mechaniker eine neue Inspektion beginnt.",
+    "summary": "{sections} Gruppe(n) · {checks} Prüfpunkt(e)",
+    "renumber": "Referenzen neu nummerieren",
+    "renumberHelp": "Nummeriert jede Gruppe und jeden Prüfpunkt der Reihe nach: 1, 1.1, 1.2, 2. Neue Zeilen werden beim Hinzufügen nummeriert, das hier brauchen Sie also nur nach dem Verschieben.",
+    "renumberWarning": "Diese Prüfliste verwendet Verweise auf Vorschriften wie 1.1.13. Eine Neunummerierung ersetzt sie.",
+    "addSection": "Gruppe hinzufügen",
+    "addCheck": "Prüfpunkt hinzufügen",
+    "ref": "Ref.",
+    "sectionName": "Gruppenname, z. B. Bremsanlage",
+    "sectionNote": "Optionaler Hinweis über den Prüfpunkten dieser Gruppe",
+    "checkName": "Name des Prüfpunkts, z. B. Bremsbeläge",
+    "reorderSection": "Gruppe {name} umsortieren",
+    "reorderCheck": "Prüfpunkt {name} umsortieren",
+    "removeSection": "Gruppe {name} entfernen",
+    "removeCheck": "Prüfpunkt {name} entfernen",
+    "duplicateCheck": "Prüfpunkt {name} duplizieren",
+    "configure": "{name} einrichten",
+    "hideSettings": "Einstellungen für {name} ausblenden",
+    "howRecorded": "Wie wird es erfasst?",
+    "guidance": "Hinweis für den Mechaniker",
+    "guidancePlaceholder": "Wird im Inspektionsformular unter dem Namen des Prüfpunkts angezeigt.",
+    "measurement": "Messwert",
+    "unit": "Einheit",
+    "minimum": "Minimum",
+    "maximum": "Maximum",
+    "outOfRange": "Mangel außerhalb des Bereichs",
+    "rangeHelp": "Lassen Sie eine Grenze leer für eine einseitige Vorgabe, etwa ein Minimum von 1,6 mm ohne Maximum. Messwerte außerhalb des Bereichs werden automatisch bewertet.",
+    "answers": "Antworten",
+    "answersHelp": "Trennen Sie die Antworten mit Kommas.",
+    "mustComplete": "Muss ausgefüllt werden",
+    "photoRequired": "Foto erforderlich, wenn ein Mangel erfasst wird",
+    "commonWording": "Häufige Mängeltexte",
+    "commonWordingHelp": "Eine Formulierung pro Zeile. Diese werden hier zuerst angeboten, wenn ein Mechaniker einen Mangel erfasst, noch vor den eingebauten Texten, damit sich Ihre Werkstatt auf eine Beschreibung einigen kann.",
+    "inputType": {
+      "condition": "Mängelbewertung",
+      "measurement": "Messwert",
+      "text": "Freitext",
+      "choice": "Auswahl"
+    },
+    "inputHint": {
+      "condition": "Der Mechaniker bewertet den Prüfpunkt nach der Mängelskala.",
+      "measurement": "Erfasst eine Zahl mit Einheit, automatisch gegen einen Bereich bewertet.",
+      "text": "Erfasst eine schriftliche Beobachtung, etwa eine Reifenmarke oder einen Fehlercode.",
+      "choice": "Der Mechaniker wählt eine Antwort aus einer festen Liste."
+    },
+    "cancel": "Abbrechen",
+    "create": "Vorlage anlegen",
+    "saveChanges": "Änderungen speichern",
+    "created": "Vorlage angelegt",
+    "updated": "Vorlage aktualisiert",
+    "saveFailed": "Vorlage konnte nicht gespeichert werden",
+    "severityAttention": "Geringer Mangel",
+    "severityFail": "Erheblicher Mangel",
+    "severityDangerous": "Gefährlicher Mangel",
+    "answersPlaceholder": "Vollständig, Teilweise, Keine"
+  },
+  "packages": {
+    "exportTitle": "„{name}“ exportieren",
+    "exportDescription": "Lädt die gesamte Prüfliste als Datei herunter: Gruppen, Prüfpunkte, Einheiten und Grenzwerte. Jeder, der Torqvoice betreibt, kann sie importieren.",
+    "includeWording": "Eigene Mängeltexte einbeziehen",
+    "includeWordingHelp": "Die Formulierungen, die Ihre Werkstatt zu den Prüfpunkten ergänzt hat. Nützlich für den Empfänger, aber es ist Freitext, der an der Werkbank getippt wurde, und kann einen Kunden, eine Kollegin oder eine örtliche Absprache benennen. Aus, sofern Sie sie nicht gelesen haben.",
+    "attributeTo": "Zuschreiben an (optional)",
+    "attributePlaceholder": "z. B. Egeland Auto",
+    "attributeHelp": "Wird in die Datei geschrieben, damit der Installierende sieht, woher sie stammt. Aus Ihrem Konto wird nichts übernommen.",
+    "download": "Herunterladen",
+    "exported": "Vorlage exportiert",
+    "exportFailed": "Diese Vorlage konnte nicht exportiert werden",
+    "importTitle": "Prüfliste importieren",
+    "importDescription": "Fügt eine Prüfliste aus einer Torqvoice-Paketdatei hinzu. Sie kommt als normale, bearbeitbare Vorlage an und ersetzt niemals eine vorhandene.",
+    "chooseFile": "Paketdatei wählen",
+    "chooseAnother": "Andere Datei wählen",
+    "unreadable": "Die Datei konnte nicht gelesen werden. Ein Torqvoice-Paket ist eine aus einer Vorlage exportierte .json-Datei.",
+    "from": "Von {author}",
+    "limitsWarning": "Die Grenzwerte einer geteilten Prüfliste sind die, die ihr Autor gesetzt hat. Prüfen Sie sie gegen Ihre nationalen Vorschriften, bevor Sie etwas daraus ausstellen.",
+    "import": "Importieren",
+    "imported": "{count} Vorlage(n) importiert",
+    "importFailed": "Dieses Paket konnte nicht importiert werden",
+    "cancel": "Abbrechen"
+  },
+  "list": {
+    "tabAll": "Alle",
+    "tabInProgress": "Läuft",
+    "tabCompleted": "Abgeschlossen",
+    "search": "Inspektionen suchen…",
+    "new": "Neue Inspektion",
+    "empty": "Keine Inspektionen gefunden.",
+    "vehicle": "Fahrzeug",
+    "template": "Vorlage",
+    "progress": "Fortschritt",
+    "status": "Status",
+    "date": "Datum",
+    "statusInProgress": "Läuft",
+    "statusCompleted": "Abgeschlossen"
+  },
+  "new": {
+    "title": "Neue Inspektion",
+    "vehicle": "Fahrzeug",
+    "searchVehicles": "Fahrzeuge suchen…",
+    "loadingVehicles": "Fahrzeuge werden geladen…",
+    "noVehicles": "Keine Fahrzeuge gefunden.",
+    "template": "Vorlage",
+    "selectTemplate": "Vorlage wählen",
+    "manageTemplates": "Vorlagen verwalten",
+    "cancel": "Abbrechen",
+    "create": "Inspektion anlegen",
+    "created": "Inspektion angelegt",
+    "createFailed": "Inspektion konnte nicht angelegt werden"
+  },
+  "shareDialog": {
+    "title": "Inspektion teilen",
+    "description": "Teilen Sie eine schreibgeschützte Ansicht dieser Inspektion mit Ihrem Kunden.",
+    "copyLink": "Link kopieren",
+    "copied": "Link in die Zwischenablage kopiert",
+    "generated": "Freigabelink erstellt",
+    "revoked": "Freigabelink zurückgezogen"
+  }
+}

+ 29 - 2
messages/de/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "SMS-Nachrichten",
-    "featureDescription": "Senden und empfangen Sie SMS-Nachrichten mit Ihren Kunden direkt über Torqvoice."
+    "featureDescription": "Senden und empfangen Sie SMS-Nachrichten mit Ihren Kunden direkt über Torqvoice.",
+    "tabs": {
+      "inbox": "Posteingang",
+      "scheduled": "Geplant"
+    },
+    "smsNotConfiguredTitle": "SMS ist nicht eingerichtet",
+    "smsNotConfiguredHint": "Verbinden Sie einen SMS-Anbieter, um hier Nachrichten zu senden und zu empfangen. Geplante E-Mails funktionieren auch ohne.",
+    "goToSmsSettings": "Zu den SMS-Einstellungen"
   },
   "notConfigured": {
     "title": "SMS nicht konfiguriert",
@@ -20,7 +27,10 @@
     "deleted": "Unterhaltung gelöscht",
     "deleteError": "Unterhaltung konnte nicht gelöscht werden",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Unterhaltungen durchsuchen",
+    "noSearchResults": "Keine Unterhaltung passt zur Suche",
+    "now": "jetzt"
   },
   "conversation": {
     "noPhone": "Keine Telefonnummer für {name} hinterlegt. Fügen Sie eine Telefonnummer hinzu, um Nachrichten zu senden.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS gesendet",
     "sentTo": "{label} wurde an {name} ({phone}) gesendet",
     "sendError": "SMS konnte nicht gesendet werden"
+  },
+  "compose": {
+    "newMessage": "Neue Nachricht",
+    "title": "Neue Nachricht",
+    "searchPlaceholder": "Kunden nach Name oder Nummer suchen",
+    "noMatches": "Keine Kunden passen zur Suche",
+    "noRecipients": "Keine Kunden mit Telefonnummer",
+    "noRecipientsHint": "Hinterlegen Sie eine Telefonnummer, um zu schreiben.",
+    "changeRecipient": "Andere Person wählen",
+    "messageLabel": "Nachricht",
+    "messagePlaceholder": "Nachricht an {name} ...",
+    "segments": "{chars} Zeichen · {segments} SMS",
+    "send": "Senden",
+    "scheduleInstead": "Stattdessen planen",
+    "sent": "An {name} gesendet",
+    "sendError": "Nachricht konnte nicht gesendet werden",
+    "templates": "Vorlagen"
   }
 }

+ 2 - 3
messages/de/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Suchen...",
   "shortcut": "Ctrl+K",
+  "readMore": "Mehr erfahren",
   "newWorkOrder": "Neuer Arbeitsauftrag",
   "quickCreate": {
     "title": "Hinzufügen",
@@ -77,7 +78,6 @@
     "clients": "Kunden",
     "customers": "Kunden",
     "messages": "Nachrichten",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Werkstatt",
     "vehicles": "Fahrzeuge",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "z.B. Müllers Autowerkstatt",
     "cancel": "Abbrechen",
     "createCompany": "Unternehmen erstellen",
-    "lightMode": "Heller Modus",
-    "darkMode": "Dunkler Modus",
+    "theme": "Design",
     "signOut": "Abmelden",
     "more": "Mehr",
     "auditLog": "Aktivitätsprotokoll",

+ 31 - 1
messages/de/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Hinweise",
     "footerText": "Fahrzeuginspektion — {shopName}",
     "viewPortal": "Ihr Portal ansehen: {url}",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "euPass": "Kein Mangel",
+    "euAttention": "Geringer Mangel",
+    "euFail": "Erheblicher Mangel",
+    "euDangerous": "Gefährlicher Mangel",
+    "basicPass": "Bestanden",
+    "basicAttention": "Achtung",
+    "basicFail": "Durchgefallen",
+    "basicDangerous": "Gefährlich",
+    "resultPass": "Bestanden",
+    "resultPassMinor": "Bestanden mit geringen Mängeln",
+    "resultFail": "Nicht bestanden — erhebliche Mängel",
+    "resultFailDangerous": "Nicht bestanden — gefährliche Mängel",
+    "resultIncomplete": "Nicht abgeschlossen",
+    "testDetails": "Prüfdaten",
+    "testDate": "Prüfdatum",
+    "testLocation": "Prüfort",
+    "inspector": "Prüfer",
+    "certificateNumber": "Bescheinigungsnummer",
+    "vehicleCategory": "Fahrzeugklasse",
+    "nextTestDue": "Nächste Prüfung fällig",
+    "limit": "Grenzwert",
+    "overallResult": "Prüfergebnis",
+    "deficiencies": "Festgestellte Mängel",
+    "reading": "Messwert",
+    "noDeficiencies": "Es wurden keine Mängel erfasst.",
+    "resultDetailPass": "Es wurden keine Mängel festgestellt.",
+    "resultDetailPassMinor": "Das Fahrzeug hat bestanden. Beheben Sie die geringen Mängel ohne unnötige Verzögerung.",
+    "resultDetailFail": "Das Fahrzeug hat nicht bestanden. Die Mängel müssen behoben und das Fahrzeug erneut geprüft werden.",
+    "resultDetailFailDangerous": "Das Fahrzeug darf bis zur Behebung der gefährlichen Mängel nicht im öffentlichen Straßenverkehr genutzt werden.",
+    "resultDetailIncomplete": "Diese Prüfung läuft noch."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "SERVICEHISTORIE",

+ 76 - 0
messages/de/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Nachricht planen",
+    "editTitle": "Geplante Nachricht bearbeiten",
+    "channelLabel": "Senden per",
+    "channels": {
+      "email": "E-Mail",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "Notiz in der App"
+    },
+    "repeatLabel": "Wiederholen",
+    "frequencies": {
+      "once": "Einmal",
+      "daily": "Täglich",
+      "weekly": "Wöchentlich",
+      "biweekly": "Alle 2 Wochen",
+      "monthly": "Monatlich",
+      "yearly": "Jährlich"
+    },
+    "customerLabel": "Kunde",
+    "selectCustomer": "Kunde auswählen",
+    "none": "Keiner",
+    "recipientEmail": "E-Mail-Adresse",
+    "recipientPhone": "Telefonnummer",
+    "recipientChat": "Telegram-Chat-ID",
+    "recipientOverride": "Stattdessen an eine andere Adresse",
+    "recipientHintCustomer": "Leer lassen, um die hinterlegten Daten zu nutzen.",
+    "recipientHintDirect": "Kunde wählen oder Ziel eintragen.",
+    "subjectLabel": "Betreff",
+    "subjectPlaceholder": "z. B. Ihr Auto ist fertig",
+    "messageLabel": "Nachricht",
+    "messagePlaceholder": "Was möchten Sie sagen?",
+    "characters": "{count} / {max} Zeichen",
+    "dateLabel": "Datum",
+    "timeLabel": "Uhrzeit",
+    "endDateLabel": "Wiederholen bis",
+    "endDateHint": "Leer lassen, um weiter zu wiederholen.",
+    "schedule": "Planen",
+    "scheduled": "Nachricht geplant",
+    "updated": "Geplante Nachricht aktualisiert",
+    "saveError": "Nachricht konnte nicht gespeichert werden"
+  },
+  "list": {
+    "scheduleMessage": "Nachricht planen",
+    "scheduleForCustomer": "Nachricht planen",
+    "filters": {
+      "upcoming": "Anstehend",
+      "sent": "Gesendet",
+      "failed": "Fehlgeschlagen",
+      "cancelled": "Abgebrochen",
+      "all": "Alle"
+    },
+    "status": {
+      "scheduled": "Geplant",
+      "sent": "Gesendet",
+      "failed": "Fehlgeschlagen",
+      "cancelled": "Abgebrochen"
+    },
+    "empty": "Nichts geplant",
+    "emptyHint": "Rechtsklick auf einen Tag im Kalender, oder Nachricht planen.",
+    "noRecipient": "Kein Empfänger",
+    "sentCount": "{count}x gesendet",
+    "rowMenu": "Nachrichtenmenü",
+    "sendNow": "Jetzt senden",
+    "cancel": "Senden abbrechen",
+    "sentNow": "Nachricht gesendet",
+    "sendError": "Nachricht konnte nicht gesendet werden",
+    "cancelled": "Senden abgebrochen",
+    "cancelError": "Nachricht konnte nicht abgebrochen werden",
+    "deleted": "Nachricht gelöscht",
+    "deleteError": "Nachricht konnte nicht gelöscht werden",
+    "deleteTitle": "Diese Nachricht löschen?",
+    "deleteDescription": "Die geplante Nachricht wird endgültig entfernt. Bereits Gesendetes bleibt in der Unterhaltung."
+  }
+}

+ 57 - 45
messages/de/settings.json

@@ -184,12 +184,12 @@
     "profileUpdated": "Profil aktualisiert",
     "failedUpdateProfile": "Profil konnte nicht aktualisiert werden",
     "failedUpdateEmail": "E-Mail konnte nicht aktualisiert werden",
-    "changePasswordTitle": "Passwort andern",
+    "changePasswordTitle": "Passwort ändern",
     "changePasswordDescription": "Geben Sie Ihr aktuelles Passwort ein und wahlen Sie ein neues.",
     "currentPassword": "Aktuelles Passwort",
     "newPassword": "Neues Passwort",
     "confirmNewPassword": "Neues Passwort bestatigen",
-    "changePassword": "Passwort andern",
+    "changePassword": "Passwort ändern",
     "passwordChanged": "Passwort geandert",
     "passwordsNoMatch": "Passworter stimmen nicht uberein",
     "passwordMinLength": "Passwort muss mindestens 8 Zeichen lang sein",
@@ -218,7 +218,7 @@
     "back": "Zuruck",
     "verify": "Verifizieren",
     "enterCodeError": "Bitte geben Sie den Code aus Ihrer Authenticator-App ein",
-    "invalidCode": "Ungueltiger Code. Bitte versuchen Sie es erneut.",
+    "invalidCode": "Ungültiger Code. Bitte versuchen Sie es erneut.",
     "verificationFailed": "Verifizierung fehlgeschlagen",
     "backupCodesTitle": "Backup-Codes speichern",
     "backupCodesDescription": "Bewahren Sie diese Codes an einem sicheren Ort auf. Sie konnen sie verwenden, um sich anzumelden, wenn Sie den Zugang zu Ihrer Authenticator-App verlieren. Jeder Code kann nur einmal verwendet werden.",
@@ -228,21 +228,21 @@
     "savedBackupCodes": "Ich habe meine Backup-Codes gespeichert",
     "twoFactorEnabledSuccess": "Zwei-Faktor-Authentifizierung aktiviert",
     "dangerZone": "Gefahrenzone",
-    "deleteContentTitle": "Inhalte loschen",
-    "deleteContentDescription": "Organisationsdaten wie Fahrzeuge, Kunden, Angebote oder Inventar selektiv loschen. Ihr Konto und Ihre Einstellungen bleiben erhalten.",
-    "deleteContentButton": "Inhalte loschen",
-    "deleteAccountTitle": "Konto loschen",
-    "deleteAccountDescription": "Loschen Sie Ihr Konto und alle zugehorigen Daten dauerhaft, einschliesslich Fahrzeuge, Servicedaten, Arbeitsauftrage, Rechnungen, Kunden, Dateien und Zahlungen. Diese Aktion kann nicht ruckgangig gemacht werden.",
-    "deleteAccountButton": "Konto loschen",
-    "deleteAccountDialogTitle": "Konto loschen",
-    "deleteAccountDialogDescription": "Dies loscht Ihr Konto und alle zugehorigen Daten dauerhaft. Diese Aktion ist unwiderruflich. Alle Ihre Fahrzeuge, Servicedaten, Arbeitsauftrage, Angebote, Kunden, Dateien und Zahlungshistorie werden dauerhaft entfernt.",
+    "deleteContentTitle": "Inhalte löschen",
+    "deleteContentDescription": "Organisationsdaten wie Fahrzeuge, Kunden, Angebote oder Inventar selektiv löschen. Ihr Konto und Ihre Einstellungen bleiben erhalten.",
+    "deleteContentButton": "Inhalte löschen",
+    "deleteAccountTitle": "Konto löschen",
+    "deleteAccountDescription": "Löschen Sie Ihr Konto und alle zugehörigen Daten dauerhaft, einschließlich Fahrzeuge, Servicedaten, Arbeitsaufträge, Rechnungen, Kunden, Dateien und Zahlungen. Diese Aktion kann nicht rückgängig gemacht werden.",
+    "deleteAccountButton": "Konto löschen",
+    "deleteAccountDialogTitle": "Konto löschen",
+    "deleteAccountDialogDescription": "Dies löscht Ihr Konto und alle zugehörigen Daten dauerhaft. Diese Aktion ist unwiderruflich. Alle Ihre Fahrzeuge, Servicedaten, Arbeitsaufträge, Angebote, Kunden, Dateien und Zahlungshistorie werden dauerhaft entfernt.",
     "deleteAccountConfirmPhrase": "delete me",
     "deleteAccountConfirmPrompt": "Geben Sie <bold>delete me</bold> zur Bestatigung ein",
-    "permanentlyDelete": "Dauerhaft loschen",
+    "permanentlyDelete": "Dauerhaft löschen",
     "deleting": "Wird geloscht...",
     "failedDeleteAccount": "Konto konnte nicht geloscht werden",
-    "deleteContentDialogTitle": "Inhalte loschen",
-    "deleteContentDialogDescription": "Wahlen Sie die Inhalte aus, die Sie dauerhaft loschen mochten. Diese Aktion kann nicht ruckgangig gemacht werden.",
+    "deleteContentDialogTitle": "Inhalte löschen",
+    "deleteContentDialogDescription": "Wählen Sie die Inhalte aus, die Sie dauerhaft löschen möchten. Diese Aktion kann nicht rückgängig gemacht werden.",
     "contentVehicles": "Fahrzeuge",
     "contentVehiclesDescription": "Alle Fahrzeuge und deren Servicedaten, Notizen, Erinnerungen, Kraftstoffprotokolle und wiederkehrende Rechnungen",
     "contentCustomers": "Kunden",
@@ -265,7 +265,7 @@
     "contentCustomFieldsDescription": "Alle benutzerdefinierten Felddefinitionen und Werte",
     "deleteContentConfirmPhrase": "delete my data",
     "deleteContentConfirmPrompt": "Geben Sie <bold>delete my data</bold> zur Bestatigung ein",
-    "deleteSelected": "{count} ausgewahlte loschen",
+    "deleteSelected": "{count} ausgewählte löschen",
     "contentDeleted": "Ausgewahlte Inhalte wurden dauerhaft geloscht",
     "failedDeleteContent": "Inhalte konnten nicht geloscht werden",
     "passkey": {
@@ -323,7 +323,7 @@
     "invite": "Einladen",
     "invited": "Mitglied erfolgreich eingeladen.",
     "userNotFoundTitle": "Benutzer nicht gefunden",
-    "userNotFoundDescription": "Kein Konto fur \"{email}\" gefunden. Eine Einladungs-E-Mail senden, um sich anzumelden und Ihrem Team beizutreten?",
+    "userNotFoundDescription": "Kein Konto für \"{email}\" gefunden. Eine Einladungs-E-Mail senden, um sich anzumelden und Ihrem Team beizutreten?",
     "sendInvitation": "Einladung senden",
     "invitationSentTitle": "Einladung gesendet",
     "invitationSentDescription": "Eine Einladungs-E-Mail wurde an {email} gesendet.",
@@ -350,21 +350,21 @@
     "roleCreated": "Rolle erstellt",
     "roleUpdated": "Rolle aktualisiert",
     "failedSaveRole": "Rolle konnte nicht gespeichert werden",
-    "deleteRole": "Rolle loschen",
-    "deleteRoleDescription": "Die Rolle \"{name}\" loschen? Mitglieder mit dieser Rolle verlieren ihre benutzerdefinierten Berechtigungen.",
+    "deleteRole": "Rolle löschen",
+    "deleteRoleDescription": "Die Rolle \"{name}\" löschen? Mitglieder mit dieser Rolle verlieren ihre benutzerdefinierten Berechtigungen.",
     "roleDeleted": "Rolle geloscht",
     "failedDeleteRole": "Rolle konnte nicht geloscht werden",
     "fullAccess": "Voller Zugriff",
     "permissionCount": "{count} Berechtigung",
     "permissionCountPlural": "{count} Berechtigungen",
-    "noCustomRoles": "Noch keine benutzerdefinierten Rollen. Erstellen Sie eine, um granulare Berechtigungen fur Teammitglieder zu definieren.",
+    "noCustomRoles": "Noch keine benutzerdefinierten Rollen. Erstellen Sie eine, um granulare Berechtigungen für Teammitglieder zu definieren.",
     "presetAll": "Alle",
     "presetViewOnly": "Nur Ansicht",
     "presetWriteAll": "Lesen & Schreiben",
     "presetNone": "Keine",
     "builtInRoles": "Integrierte Rollen",
     "ownerLabel": "Eigentumer",
-    "ownerDescription": "Voller Zugriff. Kann Mitglieder verwalten, Rollen andern und die Organisation loschen.",
+    "ownerDescription": "Voller Zugriff. Kann Mitglieder verwalten, Rollen ändern und die Organisation löschen.",
     "adminLabel": "Administrator",
     "adminDescription": "Kann Mitglieder einladen/entfernen und gemeinsame Daten verwalten.",
     "memberLabel": "Mitglied",
@@ -391,9 +391,9 @@
       "customFields": "Benutzerdefinierte Felder"
     },
     "invoiceNumberFormat": "Rechnungsnummernformat",
-    "invoiceNumberFormatHint": "Verwenden Sie <code>{year}</code> fur das aktuelle Jahr. Vorschau: <bold>{preview}</bold>",
+    "invoiceNumberFormatHint": "Verwenden Sie <code>{year}</code> für das aktuelle Jahr. Vorschau: <bold>{preview}</bold>",
     "quoteNumberFormat": "Angebotsnummernformat",
-    "quoteNumberFormatHint": "Verwenden Sie <code>{year}</code> fur das aktuelle Jahr. Vorschau: <bold>{preview}</bold>",
+    "quoteNumberFormatHint": "Verwenden Sie <code>{year}</code> für das aktuelle Jahr. Vorschau: <bold>{preview}</bold>",
     "quoteValidDays": "Angebotsgültigkeit (Tage)",
     "quoteValidDaysHint": "Neue Angebote erhalten ein Gültig-bis-Datum so viele Tage im Voraus. 0 deaktiviert dies.",
     "sectionInvoices": "Rechnungen",
@@ -413,7 +413,7 @@
     "organizationNumber": "Organisationsnummer",
     "organizationNumberHint": "Org.-Nr. im Rechnungskopf anzeigen",
     "customFooter": "Benutzerdefinierte Rechnungsfusszeile",
-    "footerPlaceholder": "Vielen Dank fur Ihren Auftrag!",
+    "footerPlaceholder": "Vielen Dank für Ihren Auftrag!",
     "footerHint": "Dieser Text erscheint am Ende jeder Rechnung",
     "partsMarkupTitle": "Teile-Aufschlag",
     "partsMarkupDescription": "Aufschlag auf den Einkaufspreis beim Hinzufügen von Teilen. Nur intern — der Kunde sieht weder Kosten noch Aufschlag, nur den Endpreis.",
@@ -502,7 +502,7 @@
       "layout": "Layout"
     },
     "presets": "Vorlagen-Presets",
-    "primaryColor": "Primarfarbe",
+    "primaryColor": "Primärfarbe",
     "fontAndLayout": "Schrift & Layout",
     "fontFamily": "Schriftfamilie",
     "helveticaDefault": "Helvetica (Standard)",
@@ -514,8 +514,8 @@
     "compact": "Kompakt",
     "modern": "Modern",
     "preview": "{name} Vorschau",
-    "billTo": "Rechnungsempfanger",
-    "preparedFor": "Erstellt fur",
+    "billTo": "Rechnungsempfänger",
+    "preparedFor": "Erstellt für",
     "vehicle": "Fahrzeug",
     "part": "Teil",
     "qty": "Menge",
@@ -538,8 +538,8 @@
     "quotationTemplateSaved": "Angebotsvorlageneinstellungen gespeichert",
     "failedSave": "Einstellungen konnten nicht gespeichert werden",
     "smsTemplates": "SMS-Nachrichtenvorlagen",
-    "smsTemplatesDescription": "Passen Sie die Textnachrichten an Kunden an. Verwenden Sie Variablen wie <code>'{companyName}'</code>, um dynamische Werte einzufugen.",
-    "reset": "Zurucksetzen",
+    "smsTemplatesDescription": "Passen Sie die Textnachrichten an Kunden an. Verwenden Sie Variablen wie <code>'{companyName}'</code>, um dynamische Werte einzufügen.",
+    "reset": "Zurücksetzen",
     "invoiceReady": "Rechnung bereit",
     "invoiceReadyDescription": "Wird gesendet, wenn eine Rechnung mit einem Kunden geteilt wird.",
     "quoteReady": "Angebot bereit",
@@ -555,7 +555,7 @@
     "statusCompleted": "Status: Abgeschlossen",
     "statusCompletedDescription": "Wird gesendet, wenn der Arbeitsauftragsstatus auf Abgeschlossen wechselt.",
     "paymentReceived": "Zahlung eingegangen",
-    "paymentReceivedDescription": "Wird gesendet, wenn eine Zahlung fur eine Rechnung verbucht wird.",
+    "paymentReceivedDescription": "Wird gesendet, wenn eine Zahlung für eine Rechnung verbucht wird.",
     "saveSmsTemplates": "SMS-Vorlagen speichern",
     "smsTemplateSaved": "SMS-Vorlageneinstellungen gespeichert",
     "smsDefaults": {
@@ -590,7 +590,7 @@
     "detailsDescription": "Bankkonto und Zahlungsbedingungen auf Rechnungen.",
     "bankAccount": "Bankkonto (IBAN)",
     "bankAccountPlaceholder": "NO93 8601 1117 947",
-    "bankAccountHint": "Ihre Bankkontonummer oder IBAN fur den Zahlungsempfang",
+    "bankAccountHint": "Ihre Bankkontonummer oder IBAN für den Zahlungsempfang",
     "paymentTerms": "Zahlungsbedingungen",
     "paymentTermsPlaceholder": "Netto 14 Tage",
     "paymentTermsHint": "Zahlungsbedingungen auf Rechnungen (z.B. \"Netto 14 Tage\", \"Zahlbar bei Erhalt\")",
@@ -657,7 +657,7 @@
   },
   "currency": {
     "title": "Wahrung & Steuer",
-    "description": "Standardwahrung und Steuersatz fur Rechnungen und Servicedaten.",
+    "description": "Standardwährung und Steuersatz für Rechnungen und Servicedaten.",
     "currencyLabel": "Wahrung",
     "searchCurrency": "Währung suchen...",
     "noCurrencyFound": "Keine Währung gefunden.",
@@ -809,7 +809,7 @@
     "defaultLaborRate": "Standard-Stundensatz",
     "laborRatePlaceholder": "75,00",
     "unitsTitle": "Einheiten",
-    "unitsDescription": "Wahlen Sie zwischen metrisch (km, Liter) und imperial (Meilen, Gallonen).",
+    "unitsDescription": "Wählen Sie zwischen metrisch (km, Liter) und imperial (Meilen, Gallonen).",
     "unitSystem": "Einheitensystem",
     "metric": "Metrisch (km, Liter)",
     "imperial": "Imperial (Meilen, Gallonen)",
@@ -856,8 +856,18 @@
   "appearance": {
     "title": "Darstellung",
     "description": "Passen Sie das Erscheinungsbild von Torqvoice an.",
-    "darkMode": "Dunkler Modus",
-    "darkModeHint": "Zwischen hellem und dunklem Design wechseln",
+    "themeLabel": "Design",
+    "themeHint": "Wählen Sie das Farbschema der App. Die Auswahl wird auf diesem Gerät gespeichert.",
+    "themes": {
+      "light": "Hell",
+      "dark": "Dunkel",
+      "graphite": "Graphit",
+      "ocean": "Ozean",
+      "forest": "Wald",
+      "midnight": "Mitternacht",
+      "carbon": "Karbon",
+      "system": "System"
+    },
     "dateTimeTitle": "Datum & Uhrzeit",
     "dateTimeDescription": "Konfigurieren Sie, wie Datum und Uhrzeit in der Anwendung angezeigt werden.",
     "dateFormat": "Datumsformat",
@@ -879,7 +889,7 @@
     "title": "Datenverwaltung",
     "description": "Exportieren Sie Ihre Daten als Backup oder importieren Sie eine zuvor exportierte Datei.",
     "exportTitle": "Daten exportieren",
-    "exportDescription": "Laden Sie Ihre Daten als ZIP-Datei herunter. Wahlen Sie die Kategorien fur das Backup aus.",
+    "exportDescription": "Laden Sie Ihre Daten als ZIP-Datei herunter. Wählen Sie die Kategorien für das Backup aus.",
     "includeInBackup": "Im Backup enthalten:",
     "selectAll": "Alle auswahlen",
     "deselectAll": "Alle abwahlen",
@@ -901,6 +911,8 @@
     "optAuditLogsDesc": "Aktivitäts- und Änderungsverlauf",
     "optSmsMessages": "SMS-Nachrichten",
     "optSmsMessagesDesc": "Gesendete und empfangene SMS-Nachrichten",
+    "optScheduledMessages": "Geplante Nachrichten",
+    "optScheduledMessagesDesc": "Wartende und wiederkehrende Nachrichten, die noch gesendet werden",
     "optNotifications": "Benachrichtigungen",
     "optNotificationsDesc": "Systembenachrichtigungen",
     "optCustomFields": "Benutzerdefinierte Felder",
@@ -914,14 +926,14 @@
     "exportFailed": "Export fehlgeschlagen",
     "exportFailedMessage": "Ihre Daten konnten nicht exportiert werden. Bitte versuchen Sie es erneut.",
     "importTitle": "Daten importieren",
-    "importWarning": "Der Import wird <bold>alle vorhandenen Daten ersetzen</bold> durch den Inhalt der Backup-Datei. Diese Aktion kann nicht ruckgangig gemacht werden.",
+    "importWarning": "Der Import wird <bold>alle vorhandenen Daten ersetzen</bold> durch den Inhalt der Backup-Datei. Diese Aktion kann nicht rückgängig gemacht werden.",
     "importFileHint": "Unterstutzt sowohl .zip (v2) als auch .json (v1) Backup-Dateien.",
     "uploadRestore": "Hochladen & Wiederherstellen",
     "importComplete": "Import abgeschlossen",
     "importCompleteMessage": "Alle Daten wurden aus der Backup-Datei wiederhergestellt.",
     "importFailed": "Import fehlgeschlagen",
     "importFromOther": "Von anderen Diensten importieren",
-    "importFromOtherDescription": "Migrieren Sie Ihre Daten von einer anderen Plattform. Wahlen Sie einen Dienst, um zu beginnen.",
+    "importFromOtherDescription": "Migrieren Sie Ihre Daten von einer anderen Plattform. Wählen Sie einen Dienst, um zu beginnen.",
     "lubelogTitle": "Von LubeLog importieren",
     "lubelogExportSteps": "So exportieren Sie Ihre LubeLog-Daten:",
     "lubelogStep1": "Offnen Sie Ihre LubeLog-Instanz",
@@ -968,16 +980,16 @@
     "active": "Aktiv",
     "inactive": "Inaktiv",
     "lastChecked": "Zuletzt gepruft: {date}",
-    "enterLicenseKey": "Lizenzschlussel eingeben",
+    "enterLicenseKey": "Lizenzschlüssel eingeben",
     "validate": "Validieren",
     "validated": "Lizenz erfolgreich validiert",
-    "invalid": "Ungueltiger Lizenzschlussel",
+    "invalid": "Ungültiger Lizenzschlüssel",
     "failedValidate": "Lizenz konnte nicht validiert werden",
-    "keyHint": "Jeder Lizenzschlussel ist an diese Organisation gebunden und kann nicht fur mehrere Organisationen verwendet werden."
+    "keyHint": "Jeder Lizenzschlüssel ist an diese Organisation gebunden und kann nicht für mehrere Organisationen verwendet werden."
   },
   "about": {
     "title": "Uber Torqvoice",
-    "description": "Torqvoice ist Ihre komplette Losung fur die Fahrzeug-Serviceverwaltung. Verfolgen Sie Servicehistorie, Reparaturen und mehr.",
+    "description": "Torqvoice ist Ihre komplette Lösung für die Fahrzeug-Serviceverwaltung. Verfolgen Sie Servicehistorie, Reparaturen und mehr.",
     "version": "Version",
     "website": "Website",
     "documentation": "Dokumentation",
@@ -1054,9 +1066,9 @@
     "fromName": "Absendername",
     "fromNamePlaceholder": "Ihre Werkstatt",
     "tlsConnection": "TLS-Verbindung (Port 465)",
-    "tlsConnectionHint": "Aktivieren fur implizites TLS. Deaktivieren fur STARTTLS (Port 587/25).",
+    "tlsConnectionHint": "Aktivieren für implizites TLS. Deaktivieren für STARTTLS (Port 587/25).",
     "verifyTlsCerts": "TLS-Zertifikate verifizieren",
-    "verifyTlsCertsHint": "Deaktivieren, um selbstsignierte Zertifikate zuzulassen (nicht fur Produktion empfohlen)",
+    "verifyTlsCertsHint": "Deaktivieren, um selbstsignierte Zertifikate zuzulassen (nicht für Produktion empfohlen)",
     "requireTlsUpgrade": "TLS-Upgrade erzwingen",
     "requireTlsUpgradeHint": "TLS-Upgrade bei STARTTLS-Verbindungen erzwingen",
     "apiKey": "API-Schlussel",
@@ -1084,7 +1096,7 @@
   },
   "sms": {
     "title": "SMS-Anbieter",
-    "description": "Konfigurieren Sie Ihren SMS-Anbieter fur bidirektionale Nachrichten mit Kunden. Jede Organisation verwendet ihren eigenen SMS-Anbieter und ihre eigene Telefonnummer.",
+    "description": "Konfigurieren Sie Ihren SMS-Anbieter für bidirektionale Nachrichten mit Kunden. Jede Organisation verwendet ihren eigenen SMS-Anbieter und ihre eigene Telefonnummer.",
     "enableLabel": "SMS-Nachrichten aktivieren",
     "enableHint": "SMS-Nachrichten mit Kunden senden und empfangen",
     "disabledInfo": "SMS-Nachrichten sind deaktiviert. Aktivieren Sie sie, um Textnachrichten mit Ihren Kunden zu senden und zu empfangen.",
@@ -1179,7 +1191,7 @@
   },
   "ai": {
     "title": "KI-Assistent",
-    "readMore": "Read More",
+    "readMore": "Mehr erfahren",
     "description": "Konfigurieren Sie KI, um automatisch Servicenotizen zu erstellen und Fahrzeughistorien zusammenzufassen.",
     "enableLabel": "KI aktivieren",
     "enableHint": "KI-gestutzte Funktionen in der gesamten Anwendung nutzen",

+ 47 - 1
messages/de/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "PDF herunterladen",
     "notes": "Hinweise",
     "quoteCancelled": "Angebotsanfrage storniert",
-    "cancelFailed": "Anfrage konnte nicht storniert werden"
+    "cancelFailed": "Anfrage konnte nicht storniert werden",
+    "eu": {
+      "pass": "Kein Mangel",
+      "attention": "Geringer Mangel",
+      "fail": "Erheblicher Mangel",
+      "dangerous": "Gefährlicher Mangel",
+      "not_inspected": "Nicht geprüft"
+    },
+    "basic": {
+      "pass": "Bestanden",
+      "attention": "Achtung",
+      "fail": "Durchgefallen",
+      "dangerous": "Gefährlich",
+      "not_inspected": "Nicht geprüft"
+    },
+    "result": {
+      "pass": "Bestanden",
+      "pass_minor": "Bestanden mit geringen Mängeln",
+      "fail": "Nicht bestanden — erhebliche Mängel",
+      "fail_dangerous": "Nicht bestanden — gefährliche Mängel",
+      "incomplete": "Nicht abgeschlossen"
+    },
+    "resultDetail": {
+      "pass": "Es wurden keine Mängel festgestellt.",
+      "pass_minor": "Das Fahrzeug hat bestanden. Beheben Sie die geringen Mängel ohne unnötige Verzögerung.",
+      "fail": "Das Fahrzeug hat nicht bestanden. Die Mängel müssen behoben und das Fahrzeug erneut geprüft werden.",
+      "fail_dangerous": "Das Fahrzeug darf bis zur Behebung der gefährlichen Mängel nicht im öffentlichen Straßenverkehr genutzt werden.",
+      "incomplete": "Diese Prüfung läuft noch."
+    },
+    "testDetails": "Prüfdaten",
+    "testDate": "Prüfdatum",
+    "certificateNumber": "Bescheinigungsnummer",
+    "vehicleCategory": "Fahrzeugklasse",
+    "inspector": "Prüfer",
+    "testLocation": "Prüfort",
+    "nextTestDue": "Nächste Prüfung fällig",
+    "vesselLabel": "Fahrzeug",
+    "plateLabel": "Kennzeichen",
+    "odometerLabel": "Kilometerstand",
+    "engineHoursLabel": "Betriebsstunden",
+    "summary": "Zusammenfassung",
+    "progressLabel": "{graded} Prüfpunkte bewertet",
+    "limit": "Grenzwert",
+    "viewPhoto": "Foto ansehen",
+    "deficienciesFound": "Festgestellte Mängel ({count})",
+    "allResults": "Alle Ergebnisse",
+    "privacyNotice": "Dieser Bericht wird Ihnen von der Werkstatt bereitgestellt, die die Prüfung durchgeführt hat. Er ist für jeden mit diesem Link abrufbar — bitte leiten Sie ihn nicht weiter. Wenden Sie sich an die Werkstatt, um den Link zurückzuziehen oder Ihre Daten löschen zu lassen."
   },
   "terms": {
     "title": "Verkaufsbedingungen (Salgsvilkår)",

+ 9 - 8
messages/de/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Statusberichte",
+    "readMore": "Mehr erfahren",
     "newReport": "Neuer Statusbericht",
     "empty": "Noch keine Statusberichte",
     "emptyDescription": "Erstellen Sie einen Statusbericht, um Ihren Kunden über den Fahrzeugstatus zu informieren.",
@@ -76,17 +77,17 @@
     "deleteTitle": "Statusbericht löschen",
     "deleteFailed": "Statusbericht konnte nicht gelöscht werden",
     "cancel": "Abbrechen",
-  "feedback": "Feedback",
-  "hasComment": "Erhalten",
-  "noFeedback": "Noch kein Feedback",
-  "sentAt": "Gesendet",
-  "sentVia": "Gesendet über",
-  "messageLabel": "Nachricht",
-  "videoLabel": "Video"
+    "feedback": "Feedback",
+    "hasComment": "Erhalten",
+    "noFeedback": "Noch kein Feedback",
+    "sentAt": "Gesendet",
+    "sentVia": "Gesendet über",
+    "messageLabel": "Nachricht",
+    "videoLabel": "Video"
   },
   "notify": {
     "defaultMessage": "Hallo {name}, wir haben ein Status-Update zu Ihrem {vehicle}. Hier ansehen: {url}",
     "emailSubject": "Fahrzeug-Statusbericht - {vehicle}",
-  "viewReport": "Bericht hier ansehen: {url}"
+    "viewReport": "Bericht hier ansehen: {url}"
   }
 }

+ 2 - 2
messages/de/vehicles.json

@@ -134,7 +134,7 @@
     "dueMileagePlaceholder": "z.B. 50000",
     "reminderUpdated": "Erinnerung aktualisiert",
     "reminderCreated": "Erinnerung erstellt",
-    "saveError": "Fehler beim {action} der Erinnerung",
+    "saveError": "Erinnerung konnte nicht gespeichert werden",
     "notifyLabel": "Bei Fälligkeit benachrichtigen",
     "notifyInApp": "In-App-Benachrichtigung",
     "notifyEmail": "E-Mail"
@@ -201,7 +201,7 @@
     "noteUpdated": "Notiz aktualisiert",
     "noteCreated": "Notiz erstellt",
     "titleRequired": "Titel und Inhalt sind erforderlich",
-    "saveError": "Fehler beim {action} der Notiz",
+    "saveError": "Notiz konnte nicht gespeichert werden",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",

+ 11 - 1
messages/en/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Created Webhook",
     "webhook_update": "Updated Webhook",
     "webhook_delete": "Deleted Webhook",
-    "webhook_rotateSecret": "Rotated Webhook Secret"
+    "webhook_rotateSecret": "Rotated Webhook Secret",
+    "inspection_reopen": "Reopened Inspection",
+    "inspectionTemplate_import": "Imported Inspection Template",
+    "scheduled_message_create": "Created Scheduled Message",
+    "scheduled_message_update": "Updated Scheduled Message",
+    "scheduled_message_delete": "Deleted Scheduled Message",
+    "scheduled_message_cancel": "Cancelled Scheduled Message",
+    "scheduled_message_send_now": "Sent Scheduled Message",
+    "settings_applyTaxRate": "Applied Tax Rate",
+    "settings_convertToExclusive": "Converted Prices to Tax Exclusive",
+    "settings_convertToInclusive": "Converted Prices to Tax Inclusive"
   }
 }

+ 16 - 3
messages/en/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Services",
     "reminders": "Reminders",
-    "quotes": "Quotes"
+    "quotes": "Quotes",
+    "messages": "Messages"
   },
   "selectVehicle": "Select Vehicle for Work Order",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} more",
+  "monthTotal": "{count} events this month",
+  "contextMenu": {
+    "newWorkOrder": "New work order",
+    "newReminder": "New reminder",
+    "newQuote": "New quote",
+    "openEvent": "Open ({count})",
+    "hint": "Tip: right-click a day for actions",
+    "scheduleMessage": "Schedule message"
+  },
   "events": {
     "status": {
       "completed": "Completed",
@@ -54,12 +64,15 @@
       "draft": "Draft",
       "done": "Done",
       "overdue": "Overdue",
-      "upcoming": "Upcoming"
+      "upcoming": "Upcoming",
+      "failed": "Failed",
+      "queued": "Queued"
     },
     "type": {
       "service": "Service",
       "reminder": "Reminder",
-      "quote": "Quote"
+      "quote": "Quote",
+      "message": "Message"
     },
     "noEvents": "No events",
     "selectDay": "Select a day with events or create a new work order."

+ 24 - 0
messages/en/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice has been updated to {version}",
     "whatsNew": "See what is new",
     "dismiss": "Dismiss"
+  },
+  "pagination": {
+    "showing": "Showing {start}-{end} of {total}",
+    "perPage": "per page",
+    "pageOf": "Page {page} of {pages}",
+    "first": "First page",
+    "previous": "Previous page",
+    "next": "Next page",
+    "last": "Last page"
+  },
+  "shared": {
+    "close": "Close",
+    "viewPlans": "View Plans",
+    "manageLicense": "Manage License",
+    "installOwn": "Install your own",
+    "install": "Install",
+    "installApp": "Install App",
+    "installTorqvoice": "Install Torqvoice",
+    "dismiss": "Dismiss",
+    "useCamera": "Use camera",
+    "enterManually": "Enter manually",
+    "enterBarcode": "Enter barcode...",
+    "scanHint": "Point your camera at a barcode or enter it manually",
+    "iosInstallHint": "Tap Share > Add to Home Screen"
   }
 }

+ 396 - 0
messages/en/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "No defect",
+      "attention": "Minor defect",
+      "fail": "Major defect",
+      "dangerous": "Dangerous defect",
+      "not_inspected": "Not inspected"
+    },
+    "basic": {
+      "pass": "Pass",
+      "attention": "Attention",
+      "fail": "Fail",
+      "dangerous": "Dangerous",
+      "not_inspected": "Not inspected"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Minor",
+      "fail": "Major",
+      "dangerous": "Danger",
+      "not_inspected": "N/A"
+    },
+    "hint": {
+      "pass": "Meets requirements. Nothing to report.",
+      "attention": "No significant effect on safety. Vehicle passes; repair when convenient.",
+      "fail": "May prejudice safety or affect the environment. Vehicle fails; repair and retest.",
+      "dangerous": "Direct and immediate risk to road safety. The vehicle must not be driven.",
+      "not_inspected": "This check has not been carried out."
+    }
+  },
+  "results": {
+    "pass": "Pass",
+    "pass_minor": "Pass with minor defects",
+    "fail": "Fail — major defects",
+    "fail_dangerous": "Fail — dangerous defects",
+    "incomplete": "Not completed",
+    "detail": {
+      "pass": "No deficiencies were found.",
+      "pass_minor": "The vehicle passes. Repair the minor deficiencies without undue delay.",
+      "fail": "The vehicle fails. The deficiencies must be repaired and the vehicle retested.",
+      "fail_dangerous": "The vehicle must not be used on the public road until the dangerous deficiencies are repaired.",
+      "incomplete": "The inspection is still in progress."
+    }
+  },
+  "page": {
+    "back": "Inspections",
+    "statusInProgress": "In progress",
+    "statusCompleted": "Completed",
+    "complete": "Complete",
+    "reopen": "Reopen",
+    "share": "Share",
+    "save": "Save",
+    "saving": "Saving…",
+    "savedAt": "Saved {time}",
+    "savesAsYouGo": "Saves as you go",
+    "saveFailed": "Some changes did not save",
+    "allSaved": "All changes are saved",
+    "moreActions": "More actions",
+    "downloadCertificate": "Download certificate",
+    "manageTemplates": "Manage templates",
+    "delete": "Delete",
+    "createWorkOrder": "Create work order",
+    "viewWorkOrder": "View work order",
+    "createQuote": "Create quote",
+    "viewQuote": "View quote",
+    "needsDefect": "Available once a defect has been recorded",
+    "workOrderRaised": "Work order {number} raised from this inspection on {date}",
+    "open": "Open",
+    "quoteCreated": "Quote created by {name} on {date}",
+    "quoteRequested": "The customer asked for a quote on {count} item(s)",
+    "stillToGrade": "{count} of {total} checks still to grade.",
+    "progress": "Progress",
+    "checksGraded": "checks graded",
+    "progressLabel": "{graded} of {total} checks graded: {pass} no defect, {attention} minor, {fail} major, {dangerous} dangerous.",
+    "sections": "Sections",
+    "graded": "{graded}/{total} graded",
+    "vehicle": "Vehicle",
+    "vessel": "Vessel",
+    "customer": "Customer",
+    "plate": "Plate",
+    "registration": "Registration",
+    "template": "Template",
+    "scaleEu": "Graded on the EU defect scale from Directive 2014/45/EU.",
+    "scaleBasic": "Graded pass / attention / fail.",
+    "country": "Country: {code}.",
+    "manageInspectionTemplates": "Manage inspection templates",
+    "readMore": "Read more",
+    "odometer": "Odometer",
+    "engineHours": "Engine hours",
+    "completeTitle": "Complete this inspection?",
+    "completeBody": "The checks are locked once the inspection is completed, and the result becomes \"{result}\".",
+    "completeBlocked": "{count} check(s) the template marks as mandatory are outstanding.",
+    "completeUngraded": "{count} check(s) have not been graded.",
+    "completeDangerous": "{count} dangerous defect(s) recorded. The vehicle must not be used on the public road.",
+    "reopenTitle": "Reopen this inspection?",
+    "reopenBody": "The checks become editable again and the result goes back to in progress. The inspector, certificate number and next test date are kept.",
+    "reopenShared": "The customer's link stays live and will show the result changing as you edit. Any certificate already downloaded keeps the old result.",
+    "deleteTitle": "Delete this inspection?",
+    "deleteBody": "This permanently deletes the inspection, its grades, notes and photos. It cannot be undone.",
+    "cancel": "Cancel",
+    "completed": "Inspection completed",
+    "reopened": "Inspection reopened",
+    "deleted": "Inspection deleted",
+    "completeFailed": "Failed to complete inspection",
+    "reopenFailed": "Failed to reopen inspection",
+    "deleteFailed": "Failed to delete inspection",
+    "quoteFailed": "Failed to create quote",
+    "workOrderFailed": "Failed to create work order"
+  },
+  "item": {
+    "required": "(required)",
+    "saving": "Saving",
+    "addNote": "Add note",
+    "hideNote": "Hide note",
+    "addPhoto": "Add a photo or video to {name}",
+    "notesFor": "Notes for {name}",
+    "describeDefect": "Describe the defect — this appears on the report",
+    "optionalNote": "Add a note (optional)",
+    "notesRequired": "Describe the defect before this grade is saved.",
+    "photoRequired": "A photo of the defect is required here. The inspection cannot be completed until one is attached.",
+    "reading": "Reading",
+    "readingUnit": "Reading ({unit})",
+    "limit": "Limit: {range}",
+    "recordedValue": "Recorded value",
+    "answer": "Answer",
+    "selectAnswer": "Select an answer",
+    "viewPhoto": "View photo {index} of {name} full size",
+    "photoAlt": "{name}, photo {index}",
+    "removePhoto": "Remove photo {index} from {name}",
+    "clearTitle": "Clear this grade?",
+    "clearBody": "The note recorded against \"{name}\" will be removed and the check goes back to not inspected.",
+    "clear": "Clear",
+    "cancel": "Cancel",
+    "saveFailed": "Could not save this check",
+    "uploadFailed": "Upload failed",
+    "uploadFailedFor": "Could not upload {name}"
+  },
+  "suggestions": {
+    "title": "Common defects",
+    "add": "Add \"{text}\" and grade as {grade}",
+    "more": "More ({count})",
+    "search": "Search defect wording",
+    "empty": "No matching phrase.",
+    "source": {
+      "workshop": "Your workshop",
+      "history": "Used before",
+      "regulation": "Directive 2014/45/EU",
+      "general": "General"
+    }
+  },
+  "media": {
+    "viewer": "Image {index} of {total}: {caption}",
+    "close": "Close image viewer",
+    "previous": "Previous image",
+    "next": "Next image"
+  },
+  "certificate": {
+    "title": "Certificate details",
+    "description": "Required on a roadworthiness certificate under Directive 2014/45/EU, Annex IV.",
+    "inspector": "Inspector",
+    "notRecorded": "Not recorded",
+    "addTechnician": "Add technician…",
+    "recordedAs": "Recorded as {name}",
+    "vehicleCategory": "Vehicle category",
+    "mileageAtTest": "{label} at time of test",
+    "reportReference": "Report reference",
+    "reportReferenceHelp": "Your own reference for this report. If you are an approved test centre issuing a national control slip, put its number here so the two match. Otherwise leave it empty.",
+    "optional": "Optional",
+    "placeOfTest": "Place of test",
+    "placeholderAddress": "Test centre or workshop address",
+    "fromSettings": "From your workshop settings.",
+    "change": "Change",
+    "differsFromWorkshop": "Differs from your workshop address.",
+    "useWorkshopAddress": "Use workshop address",
+    "noWorkshopAddress": "No workshop address is set.",
+    "addOne": "Add one",
+    "nextTestDue": "Next test due",
+    "notSet": "Not set",
+    "intervalGroup": "Set the next test date from the date of this test",
+    "intervalHelp": "Counted from the date of this test. Two years is the Union baseline for cars and light goods vehicles; check the interval your country applies.",
+    "months6": "6 months",
+    "years1": "1 year",
+    "years2": "2 years",
+    "years3": "3 years",
+    "years4": "4 years",
+    "unsaved": "Unsaved changes",
+    "saveDetails": "Save details",
+    "saved": "Certificate details saved",
+    "saveFailed": "Could not save the certificate details",
+    "addTechnicianTitle": "Add technician",
+    "addTechnicianBody": "They join the workshop roster and can be assigned work as well as inspections.",
+    "technicianName": "Name",
+    "technicianPlaceholder": "e.g. Anna Berg",
+    "addAndSelect": "Add and select",
+    "technicianAdded": "{name} added and selected",
+    "technicianFailed": "Could not add the technician",
+    "cancel": "Cancel"
+  },
+  "templates": {
+    "title": "Inspection templates",
+    "description": "The checklists your technicians work through. Build one per country, per vehicle type or per service you sell.",
+    "import": "Import",
+    "browse": "Browse checklists",
+    "new": "New template",
+    "restoreBanner": "{count} ready-made checklist(s) have been removed from your list. You can put them back.",
+    "restore": "Restore",
+    "restored": "Restored {count} checklist(s)",
+    "allPresent": "Every checklist is already here",
+    "restoreFailed": "Failed to add the checklists",
+    "emptyTitle": "No templates yet",
+    "emptyBody": "The ready-made checklists — including the EU periodic technical inspection — have all been removed. Put them back, or build your own from scratch.",
+    "restoreChecklists": "Restore checklists",
+    "buildMyOwn": "Build my own",
+    "default": "Default",
+    "actionsFor": "Actions for {name}",
+    "edit": "Edit",
+    "duplicate": "Duplicate",
+    "export": "Export…",
+    "delete": "Delete",
+    "sections": "{count} section(s)",
+    "checks": "{count} check(s)",
+    "measured": "{count} measured",
+    "euScale": "EU defect scale",
+    "basicScale": "Pass / attention / fail",
+    "deleteTitle": "Delete \"{name}\"?",
+    "deleteBody": "This permanently deletes the template. Inspections already carried out with it keep their own copy of the checklist and are not affected.",
+    "deleted": "Template deleted",
+    "deleteFailed": "Failed to delete template",
+    "duplicated": "Template duplicated",
+    "duplicateFailed": "Failed to duplicate template",
+    "cancel": "Cancel",
+    "srSections": "Sections",
+    "srChecks": "Checks",
+    "srMeasurements": "Measurements"
+  },
+  "presets": {
+    "title": "Start from a template",
+    "description": "Every preset is copied into your workshop as a normal template. Rename sections, move checks and change any limit to match your country and your equipment.",
+    "search": "Search by name, country or standard",
+    "searchLabel": "Search templates",
+    "inYourList": "In your list",
+    "counts": "{sections} sections · {checks} checks",
+    "noMatch": "No template matches \"{query}\".",
+    "warning": "Regulatory presets carry the common EU limits. Check them against your national rules before you issue a certificate.",
+    "cancel": "Cancel",
+    "add": "Add template",
+    "added": "Template added. Adjust it to match your workshop.",
+    "addFailed": "Failed to add template",
+    "group": {
+      "regulatory": "Regulatory",
+      "workshop": "Workshop",
+      "specialist": "Specialist"
+    },
+    "groupDescription": {
+      "regulatory": "Periodic technical inspection checklists built on Directive 2014/45/EU.",
+      "workshop": "General service and sales checklists that are not tied to a regulation.",
+      "specialist": "Checklists for drivetrains and vessels that need their own procedure."
+    },
+    "euScale": "EU defect scale",
+    "basicScale": "Pass / attention / fail"
+  },
+  "builder": {
+    "newTitle": "New template",
+    "editTitle": "Edit template",
+    "description": "Build the checklist your workshop actually uses. Drag to reorder, and configure each check to record a grade, a measurement, a written note or a fixed answer.",
+    "name": "Name",
+    "namePlaceholder": "e.g. Periodic technical inspection",
+    "templateDescription": "Description",
+    "descriptionPlaceholder": "What this checklist is for and when to use it.",
+    "country": "Country",
+    "notCountrySpecific": "Not country-specific",
+    "countryHelp": "Recorded on the report so a shop working across borders can tell its checklists apart.",
+    "defectScale": "Defect scale",
+    "scaleEu": "Minor / major / dangerous (EU)",
+    "scaleBasic": "Pass / attention / fail",
+    "scaleEuHelp": "The categories in Article 7(2) of Directive 2014/45/EU. A vehicle with only minor defects still passes.",
+    "scaleBasicHelp": "A plain three-step scale for service checklists that are not a statutory test.",
+    "defaultTemplate": "Default template",
+    "defaultHelp": "Pre-selected when a technician starts a new inspection.",
+    "summary": "{sections} section(s) · {checks} check(s)",
+    "renumber": "Renumber references",
+    "renumberHelp": "Numbers every section and check in order — 1, 1.1, 1.2, 2. New rows are numbered as you add them, so you only need this after moving things about.",
+    "renumberWarning": "This checklist uses regulation references such as 1.1.13. Renumbering replaces them.",
+    "addSection": "Add section",
+    "addCheck": "Add check",
+    "ref": "Ref.",
+    "sectionName": "Section name, e.g. Braking equipment",
+    "sectionNote": "Optional note shown above the checks in this section",
+    "checkName": "Check name, e.g. Brake linings and pads",
+    "reorderSection": "Reorder section {name}",
+    "reorderCheck": "Reorder check {name}",
+    "removeSection": "Remove section {name}",
+    "removeCheck": "Remove check {name}",
+    "duplicateCheck": "Duplicate check {name}",
+    "configure": "Configure {name}",
+    "hideSettings": "Hide settings for {name}",
+    "howRecorded": "How is it recorded?",
+    "guidance": "Guidance for the technician",
+    "guidancePlaceholder": "Shown under the check name on the inspection form.",
+    "measurement": "Measurement",
+    "unit": "Unit",
+    "minimum": "Minimum",
+    "maximum": "Maximum",
+    "outOfRange": "Defect if out of range",
+    "rangeHelp": "Leave a bound empty for a one-sided limit, e.g. a minimum of 1.6 mm with no maximum. Readings outside the range are graded automatically.",
+    "answers": "Answers",
+    "answersHelp": "Separate the answers with commas.",
+    "mustComplete": "Must be completed",
+    "photoRequired": "Photo required when a defect is recorded",
+    "commonWording": "Common defect wording",
+    "commonWordingHelp": "One phrase per line. These are offered first when a technician records a defect here, ahead of the built-in wording, so your shop can settle on how it describes a fault.",
+    "inputType": {
+      "condition": "Defect grading",
+      "measurement": "Measurement",
+      "text": "Free text",
+      "choice": "Choice"
+    },
+    "inputHint": {
+      "condition": "Technician grades the check against the defect scale.",
+      "measurement": "Records a number in a unit, graded automatically against a range.",
+      "text": "Records a written observation, e.g. a tyre brand or a fault code.",
+      "choice": "Technician picks one of a fixed list of answers."
+    },
+    "cancel": "Cancel",
+    "create": "Create template",
+    "saveChanges": "Save changes",
+    "created": "Template created",
+    "updated": "Template updated",
+    "saveFailed": "Failed to save template",
+    "severityAttention": "Minor defect",
+    "severityFail": "Major defect",
+    "severityDangerous": "Dangerous defect",
+    "answersPlaceholder": "Full, Partial, None"
+  },
+  "packages": {
+    "exportTitle": "Export \"{name}\"",
+    "exportDescription": "Downloads the whole checklist as a file — sections, checks, units and limits. Anyone running Torqvoice can import it.",
+    "includeWording": "Include your own defect wording",
+    "includeWordingHelp": "The phrases your workshop added to checks. Useful to whoever receives this, but they are free text typed at a bench and can name a customer, a colleague or a local arrangement. Off unless you have read them.",
+    "attributeTo": "Attribute it to (optional)",
+    "attributePlaceholder": "e.g. Egeland Auto",
+    "attributeHelp": "Written into the file so whoever installs it can see where it came from. Nothing is taken from your account.",
+    "download": "Download",
+    "exported": "Template exported",
+    "exportFailed": "Could not export this template",
+    "importTitle": "Import a checklist",
+    "importDescription": "Adds a checklist from a Torqvoice package file. It arrives as a normal template you can edit, and never replaces one you already have.",
+    "chooseFile": "Choose a package file",
+    "chooseAnother": "Choose a different file",
+    "unreadable": "That file could not be read. A Torqvoice package is a .json file exported from a template.",
+    "from": "From {author}",
+    "limitsWarning": "Limits in a shared checklist are whatever its author set. Check them against your national rules before issuing anything from it.",
+    "import": "Import",
+    "imported": "Imported {count} template(s)",
+    "importFailed": "Could not import this package",
+    "cancel": "Cancel"
+  },
+  "list": {
+    "tabAll": "All",
+    "tabInProgress": "In Progress",
+    "tabCompleted": "Completed",
+    "search": "Search inspections...",
+    "new": "New Inspection",
+    "empty": "No inspections found.",
+    "vehicle": "Vehicle",
+    "template": "Template",
+    "progress": "Progress",
+    "status": "Status",
+    "date": "Date",
+    "statusInProgress": "In Progress",
+    "statusCompleted": "Completed"
+  },
+  "new": {
+    "title": "New Inspection",
+    "vehicle": "Vehicle",
+    "searchVehicles": "Search vehicles...",
+    "loadingVehicles": "Loading vehicles...",
+    "noVehicles": "No vehicles found.",
+    "template": "Template",
+    "selectTemplate": "Select template",
+    "manageTemplates": "Manage templates",
+    "cancel": "Cancel",
+    "create": "Create Inspection",
+    "created": "Inspection created",
+    "createFailed": "Failed to create inspection"
+  },
+  "shareDialog": {
+    "title": "Share Inspection",
+    "description": "Share a read-only view of this inspection with your customer.",
+    "copyLink": "Copy link",
+    "copied": "Link copied to clipboard",
+    "generated": "Share link generated",
+    "revoked": "Share link revoked"
+  }
+}

+ 29 - 2
messages/en/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "SMS Messaging",
-    "featureDescription": "Send and receive SMS messages with your customers directly from Torqvoice."
+    "featureDescription": "Send and receive SMS messages with your customers directly from Torqvoice.",
+    "tabs": {
+      "inbox": "Inbox",
+      "scheduled": "Scheduled"
+    },
+    "smsNotConfiguredTitle": "SMS is not set up",
+    "smsNotConfiguredHint": "Connect an SMS provider to send and receive texts here. Scheduled email still works without it.",
+    "goToSmsSettings": "Go to SMS settings"
   },
   "notConfigured": {
     "title": "SMS Not Configured",
@@ -20,7 +27,10 @@
     "deleted": "Conversation deleted",
     "deleteError": "Failed to delete conversation",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Search conversations",
+    "noSearchResults": "No conversations match your search",
+    "now": "now"
   },
   "conversation": {
     "noPhone": "No phone number on file for {name}. Add a phone number to start messaging.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS Sent",
     "sentTo": "{label} has been sent to {name} ({phone})",
     "sendError": "Failed to send SMS"
+  },
+  "compose": {
+    "newMessage": "New message",
+    "title": "New message",
+    "searchPlaceholder": "Search customers by name or number",
+    "noMatches": "No customers match your search",
+    "noRecipients": "No customers with a phone number",
+    "noRecipientsHint": "Add a phone number to a customer to text them.",
+    "changeRecipient": "Pick someone else",
+    "messageLabel": "Message",
+    "messagePlaceholder": "Message {name}...",
+    "segments": "{chars} characters · {segments} SMS",
+    "send": "Send",
+    "scheduleInstead": "Schedule instead",
+    "sent": "Sent to {name}",
+    "sendError": "Could not send the message",
+    "templates": "Templates"
   }
 }

+ 2 - 3
messages/en/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Search...",
   "shortcut": "Ctrl+K",
+  "readMore": "Read more",
   "newWorkOrder": "New Work Order",
   "quickCreate": {
     "title": "Quick Add",
@@ -77,7 +78,6 @@
     "clients": "Clients",
     "customers": "Customers",
     "messages": "Messages",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Workshop",
     "vehicles": "Vehicles",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "e.g. Joe's Auto Repair",
     "cancel": "Cancel",
     "createCompany": "Create Company",
-    "lightMode": "Light Mode",
-    "darkMode": "Dark Mode",
+    "theme": "Theme",
     "signOut": "Sign Out",
     "more": "More",
     "auditLog": "Audit Log",

+ 31 - 1
messages/en/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Notes",
     "footerText": "Vehicle Inspection — {shopName}",
     "viewPortal": "View your portal: {url}",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "euPass": "No defect",
+    "euAttention": "Minor defect",
+    "euFail": "Major defect",
+    "euDangerous": "Dangerous defect",
+    "basicPass": "Pass",
+    "basicAttention": "Attention",
+    "basicFail": "Fail",
+    "basicDangerous": "Dangerous",
+    "resultPass": "Pass",
+    "resultPassMinor": "Pass with minor defects",
+    "resultFail": "Fail — major defects",
+    "resultFailDangerous": "Fail — dangerous defects",
+    "resultIncomplete": "Not completed",
+    "testDetails": "Test details",
+    "testDate": "Date of test",
+    "testLocation": "Place of test",
+    "inspector": "Inspector",
+    "certificateNumber": "Certificate number",
+    "vehicleCategory": "Vehicle category",
+    "nextTestDue": "Next test due",
+    "limit": "Limit",
+    "overallResult": "Result of the test",
+    "deficiencies": "Deficiencies found",
+    "reading": "Reading",
+    "noDeficiencies": "No deficiencies were recorded.",
+    "resultDetailPass": "No deficiencies were found.",
+    "resultDetailPassMinor": "The vehicle passes. Repair the minor deficiencies without undue delay.",
+    "resultDetailFail": "The vehicle fails. The deficiencies must be repaired and the vehicle retested.",
+    "resultDetailFailDangerous": "The vehicle must not be used on the public road until the dangerous deficiencies are repaired.",
+    "resultDetailIncomplete": "This inspection is still in progress."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "SERVICE HISTORY",

+ 76 - 0
messages/en/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Schedule a message",
+    "editTitle": "Edit scheduled message",
+    "channelLabel": "Send by",
+    "channels": {
+      "email": "Email",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "In-app note"
+    },
+    "repeatLabel": "Repeat",
+    "frequencies": {
+      "once": "Once",
+      "daily": "Daily",
+      "weekly": "Weekly",
+      "biweekly": "Every 2 weeks",
+      "monthly": "Monthly",
+      "yearly": "Yearly"
+    },
+    "customerLabel": "Customer",
+    "selectCustomer": "Select customer",
+    "none": "None",
+    "recipientEmail": "Email address",
+    "recipientPhone": "Phone number",
+    "recipientChat": "Telegram chat id",
+    "recipientOverride": "Send to another address instead",
+    "recipientHintCustomer": "Leave empty to use the details on file.",
+    "recipientHintDirect": "Pick a customer, or type where this goes.",
+    "subjectLabel": "Subject",
+    "subjectPlaceholder": "e.g. Your car is ready",
+    "messageLabel": "Message",
+    "messagePlaceholder": "What should we say?",
+    "characters": "{count} / {max} characters",
+    "dateLabel": "Date",
+    "timeLabel": "Time",
+    "endDateLabel": "Repeat until",
+    "endDateHint": "Leave empty to keep repeating.",
+    "schedule": "Schedule",
+    "scheduled": "Message scheduled",
+    "updated": "Scheduled message updated",
+    "saveError": "Could not save the message"
+  },
+  "list": {
+    "scheduleMessage": "Schedule message",
+    "scheduleForCustomer": "Schedule a message",
+    "filters": {
+      "upcoming": "Upcoming",
+      "sent": "Sent",
+      "failed": "Failed",
+      "cancelled": "Cancelled",
+      "all": "All"
+    },
+    "status": {
+      "scheduled": "Scheduled",
+      "sent": "Sent",
+      "failed": "Failed",
+      "cancelled": "Cancelled"
+    },
+    "empty": "Nothing scheduled",
+    "emptyHint": "Right-click a day in the calendar, or use Schedule message.",
+    "noRecipient": "No recipient",
+    "sentCount": "sent {count}x",
+    "rowMenu": "Message menu",
+    "sendNow": "Send now",
+    "cancel": "Cancel sending",
+    "sentNow": "Message sent",
+    "sendError": "Could not send the message",
+    "cancelled": "Sending cancelled",
+    "cancelError": "Could not cancel the message",
+    "deleted": "Message deleted",
+    "deleteError": "Could not delete the message",
+    "deleteTitle": "Delete this message?",
+    "deleteDescription": "The scheduled message is removed for good. Anything already sent stays in the conversation."
+  }
+}

+ 14 - 2
messages/en/settings.json

@@ -856,8 +856,18 @@
   "appearance": {
     "title": "Appearance",
     "description": "Customize how Torqvoice looks and feels.",
-    "darkMode": "Dark Mode",
-    "darkModeHint": "Switch between light and dark themes",
+    "themeLabel": "Theme",
+    "themeHint": "Choose the color scheme for the app. The choice is saved on this device.",
+    "themes": {
+      "light": "Light",
+      "dark": "Dark",
+      "graphite": "Graphite",
+      "ocean": "Ocean",
+      "forest": "Forest",
+      "midnight": "Midnight",
+      "carbon": "Carbon",
+      "system": "System"
+    },
     "dateTimeTitle": "Date & Time",
     "dateTimeDescription": "Configure how dates and times are displayed across the application.",
     "dateFormat": "Date Format",
@@ -901,6 +911,8 @@
     "optAuditLogsDesc": "Activity and change history",
     "optSmsMessages": "SMS Messages",
     "optSmsMessagesDesc": "Sent and received SMS messages",
+    "optScheduledMessages": "Scheduled Messages",
+    "optScheduledMessagesDesc": "Queued and repeating messages waiting to go out",
     "optNotifications": "Notifications",
     "optNotificationsDesc": "System notifications",
     "optCustomFields": "Custom Fields",

+ 47 - 1
messages/en/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "Download PDF",
     "notes": "Notes",
     "quoteCancelled": "Quote request cancelled",
-    "cancelFailed": "Failed to cancel request"
+    "cancelFailed": "Failed to cancel request",
+    "eu": {
+      "pass": "No defect",
+      "attention": "Minor defect",
+      "fail": "Major defect",
+      "dangerous": "Dangerous defect",
+      "not_inspected": "Not inspected"
+    },
+    "basic": {
+      "pass": "Pass",
+      "attention": "Attention",
+      "fail": "Fail",
+      "dangerous": "Dangerous",
+      "not_inspected": "Not inspected"
+    },
+    "result": {
+      "pass": "Pass",
+      "pass_minor": "Pass with minor defects",
+      "fail": "Fail — major defects",
+      "fail_dangerous": "Fail — dangerous defects",
+      "incomplete": "Not completed"
+    },
+    "resultDetail": {
+      "pass": "No deficiencies were found.",
+      "pass_minor": "The vehicle passes. Repair the minor deficiencies without undue delay.",
+      "fail": "The vehicle fails. The deficiencies must be repaired and the vehicle retested.",
+      "fail_dangerous": "The vehicle must not be used on the public road until the dangerous deficiencies are repaired.",
+      "incomplete": "This inspection is still in progress."
+    },
+    "testDetails": "Test details",
+    "testDate": "Date of test",
+    "certificateNumber": "Certificate number",
+    "vehicleCategory": "Vehicle category",
+    "inspector": "Inspector",
+    "testLocation": "Place of test",
+    "nextTestDue": "Next test due",
+    "vesselLabel": "Vessel",
+    "plateLabel": "Registration",
+    "odometerLabel": "Odometer",
+    "engineHoursLabel": "Engine hours",
+    "summary": "Summary",
+    "progressLabel": "{graded} checks graded",
+    "limit": "Limit",
+    "viewPhoto": "View photo",
+    "deficienciesFound": "Deficiencies found ({count})",
+    "allResults": "All results",
+    "privacyNotice": "This report is shared with you by the workshop that carried out the inspection. It is available to anyone holding this link, so please do not forward it. Contact the workshop to have the link withdrawn or your data erased."
   },
   "terms": {
     "title": "Terms of Sale (Salgsvilkår)",

+ 8 - 7
messages/en/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Status Reports",
+    "readMore": "Read more",
     "newReport": "New Status Report",
     "empty": "No status reports yet",
     "emptyDescription": "Create a status report to update your customer on the vehicle status.",
@@ -76,13 +77,13 @@
     "deleteTitle": "Delete Status Report",
     "deleteFailed": "Failed to delete status report",
     "cancel": "Cancel",
-  "feedback": "Feedback",
-  "hasComment": "Received",
-  "noFeedback": "No feedback yet",
-  "sentAt": "Sent",
-  "sentVia": "Sent via",
-  "messageLabel": "Message",
-  "videoLabel": "Video"
+    "feedback": "Feedback",
+    "hasComment": "Received",
+    "noFeedback": "No feedback yet",
+    "sentAt": "Sent",
+    "sentVia": "Sent via",
+    "messageLabel": "Message",
+    "videoLabel": "Video"
   },
   "notify": {
     "defaultMessage": "Hi {name}, we have a status update on your {vehicle}. View it here: {url}",

+ 3 - 3
messages/en/vehicles.json

@@ -134,7 +134,7 @@
     "dueMileagePlaceholder": "e.g. 50000",
     "reminderUpdated": "Reminder updated",
     "reminderCreated": "Reminder created",
-    "saveError": "Failed to {action} reminder",
+    "saveError": "Failed to save reminder",
     "notifyLabel": "Notify me when due",
     "notifyInApp": "In-app notification",
     "notifyEmail": "Email"
@@ -201,7 +201,7 @@
     "noteUpdated": "Note updated",
     "noteCreated": "Note created",
     "titleRequired": "Title and content are required",
-    "saveError": "Failed to {action} note",
+    "saveError": "Failed to save note",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",
@@ -249,7 +249,7 @@
     "findingUpdated": "Observation updated",
     "findingResolved": "Observation resolved",
     "findingDeleted": "Observation deleted",
-    "saveError": "Failed to {action} observation",
+    "saveError": "Failed to save observation",
     "deleteError": "Failed to delete observation",
     "resolveError": "Failed to resolve observation",
     "showing": "Showing {start}-{end} of {total}",

+ 11 - 1
messages/es/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Webhook creado",
     "webhook_update": "Webhook actualizado",
     "webhook_delete": "Webhook eliminado",
-    "webhook_rotateSecret": "Secreto de webhook rotado"
+    "webhook_rotateSecret": "Secreto de webhook rotado",
+    "inspection_reopen": "Inspección reabierta",
+    "inspectionTemplate_import": "Plantilla de inspección importada",
+    "scheduled_message_create": "Mensaje programado creado",
+    "scheduled_message_update": "Mensaje programado actualizado",
+    "scheduled_message_delete": "Mensaje programado eliminado",
+    "scheduled_message_cancel": "Mensaje programado cancelado",
+    "scheduled_message_send_now": "Mensaje programado enviado",
+    "settings_applyTaxRate": "Tipo impositivo aplicado",
+    "settings_convertToExclusive": "Precios convertidos a sin impuestos",
+    "settings_convertToInclusive": "Precios convertidos a con impuestos"
   }
 }

+ 32 - 32
messages/es/auth.json

@@ -1,9 +1,9 @@
 {
   "signIn": {
     "title": "Bienvenido de nuevo",
-    "description": "Inicie sesion en su taller",
-    "passwordPlaceholder": "Ingrese su contrasena",
-    "forgotPassword": "Olvido su contrasena?",
+    "description": "Inicie sesión en su taller",
+    "passwordPlaceholder": "Ingrese su contraseña",
+    "forgotPassword": "Olvido su contraseña?",
     "noAccount": "No tiene una cuenta?",
     "createOne": "Crear una",
     "termsAgreement": "Al utilizar este servicio, usted acepta nuestros",
@@ -12,7 +12,7 @@
     "passkeyDescription": "Usa tu huella digital, rostro o llave de seguridad",
     "errors": {
       "tooManyAttempts": "Demasiados intentos, vuelva a intentarlo mas tarde.",
-      "invalidCredentials": "Correo electronico o contrasena no validos",
+      "invalidCredentials": "Correo electrónico o contraseña no validos",
       "passkeyFailed": "Error al iniciar sesión con passkey. Inténtelo de nuevo o use correo y contraseña."
     },
     "resetPasswordCta": "Restablécela aquí"
@@ -20,10 +20,10 @@
   "signUp": {
     "title": "Crear una cuenta",
     "descriptionInvite": "Cree su cuenta para unirse al equipo",
-    "descriptionDefault": "Configure su taller para gestionar los vehiculos de sus clientes",
+    "descriptionDefault": "Configure su taller para gestionar los vehículos de sus clientes",
     "fullName": "Nombre completo",
     "fullNamePlaceholder": "Juan Perez",
-    "passwordPlaceholder": "Cree una contrasena segura",
+    "passwordPlaceholder": "Cree una contraseña segura",
     "agreeToTerms": "Acepto los",
     "createAccountJoin": "Crear cuenta y unirse al equipo",
     "createAccount": "Crear cuenta",
@@ -31,7 +31,7 @@
     "errors": {
       "couldNotCreate": "No se pudo crear la cuenta",
       "registrationDisabled": "El registro esta deshabilitado actualmente. Por favor, contacte a su administrador.",
-      "invitationFailed": "No se pudo aceptar la invitacion",
+      "invitationFailed": "No se pudo aceptar la invitación",
       "termsRequired": "Acepta los términos del servicio para continuar",
       "emailExists": "Ya existe una cuenta con este correo electrónico."
     },
@@ -39,28 +39,28 @@
     "signInInstead": "Inicia sesión en su lugar"
   },
   "forgotPassword": {
-    "title": "Restablecer su contrasena",
-    "description": "Ingrese su correo electronico y le enviaremos un enlace de restablecimiento",
+    "title": "Restablecer su contraseña",
+    "description": "Ingrese su correo electrónico y le enviaremos un enlace de restablecimiento",
     "sendResetLink": "Enviar enlace de restablecimiento",
-    "backToSignIn": "Volver a iniciar sesion",
-    "successMessage": "Si existe una cuenta con ese correo electronico, se ha enviado un enlace para restablecer la contrasena. Revise su bandeja de entrada."
+    "backToSignIn": "Volver a iniciar sesión",
+    "successMessage": "Si existe una cuenta con ese correo electrónico, se ha enviado un enlace para restablecer la contraseña. Revise su bandeja de entrada."
   },
   "resetPassword": {
-    "title": "Establecer nueva contrasena",
-    "description": "Ingrese su nueva contrasena a continuacion",
-    "newPassword": "Nueva contrasena",
-    "newPasswordPlaceholder": "Ingrese la nueva contrasena",
-    "confirmPassword": "Confirmar contrasena",
-    "confirmPasswordPlaceholder": "Confirme la nueva contrasena",
-    "resetButton": "Restablecer contrasena",
-    "backToSignIn": "Volver a iniciar sesion",
+    "title": "Establecer nueva contraseña",
+    "description": "Ingrese su nueva contraseña a continuación",
+    "newPassword": "Nueva contraseña",
+    "newPasswordPlaceholder": "Ingrese la nueva contraseña",
+    "confirmPassword": "Confirmar contraseña",
+    "confirmPasswordPlaceholder": "Confirme la nueva contraseña",
+    "resetButton": "Restablecer contraseña",
+    "backToSignIn": "Volver a iniciar sesión",
     "requestNewLink": "Solicitar nuevo enlace",
-    "invalidToken": "Token de restablecimiento no valido o faltante. Por favor, solicite un nuevo enlace de restablecimiento de contrasena.",
-    "successMessage": "Su contrasena se ha restablecido correctamente. Ahora puede iniciar sesion con su nueva contrasena.",
+    "invalidToken": "Token de restablecimiento no válido o faltante. Por favor, solicite un nuevo enlace de restablecimiento de contraseña.",
+    "successMessage": "Su contraseña se ha restablecido correctamente. Ahora puede iniciar sesión con su nueva contraseña.",
     "errors": {
-      "passwordsMismatch": "Las contrasenas no coinciden.",
-      "passwordTooShort": "La contrasena debe tener al menos 8 caracteres.",
-      "resetFailed": "No se pudo restablecer la contrasena. Es posible que el enlace haya expirado."
+      "passwordsMismatch": "Las contraseñas no coinciden.",
+      "passwordTooShort": "La contraseña debe tener al menos 8 caracteres.",
+      "resetFailed": "No se pudo restablecer la contraseña. Es posible que el enlace haya expirado."
     }
   },
   "verifyEmail": {
@@ -74,18 +74,18 @@
   },
   "verify2fa": {
     "title": "Autenticacion de dos factores",
-    "descriptionTotp": "Ingrese el codigo de 6 digitos de su aplicacion de autenticacion",
+    "descriptionTotp": "Ingrese el código de 6 dígitos de su aplicación de autenticacion",
     "descriptionBackup": "Ingrese uno de sus codigos de respaldo",
-    "authCode": "Codigo de autenticacion",
-    "backupCode": "Codigo de respaldo",
-    "backupCodePlaceholder": "Ingrese el codigo de respaldo",
+    "authCode": "Código de autenticacion",
+    "backupCode": "Código de respaldo",
+    "backupCodePlaceholder": "Ingrese el código de respaldo",
     "totpPlaceholder": "000000",
-    "trustDevice": "Confiar en este dispositivo durante 30 dias",
+    "trustDevice": "Confiar en este dispositivo durante 30 días",
     "verify": "Verificar",
-    "useAuthenticator": "Usar la aplicacion de autenticacion",
-    "useBackupCode": "Usar un codigo de respaldo",
+    "useAuthenticator": "Usar la aplicación de autenticacion",
+    "useBackupCode": "Usar un código de respaldo",
     "errors": {
-      "invalidCode": "Codigo no valido"
+      "invalidCode": "Código no válido"
     }
   }
 }

+ 4 - 4
messages/es/billing.json

@@ -79,9 +79,9 @@
     "failedDelete": "Error al eliminar",
     "processed": "{count} factura(s) procesada(s)",
     "failedProcess": "Error al procesar",
-    "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "pause": "Pausar",
+    "resume": "Reanudar",
+    "delete": "Eliminar",
+    "removeRow": "Quitar fila"
   }
 }

+ 16 - 3
messages/es/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Servicios",
     "reminders": "Recordatorios",
-    "quotes": "Presupuestos"
+    "quotes": "Presupuestos",
+    "messages": "Mensajes"
   },
   "selectVehicle": "Seleccionar vehículo para orden de trabajo",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} más",
+  "monthTotal": "{count} eventos este mes",
+  "contextMenu": {
+    "newWorkOrder": "Nueva orden de trabajo",
+    "newReminder": "Nuevo recordatorio",
+    "newQuote": "Nuevo presupuesto",
+    "openEvent": "Abrir ({count})",
+    "hint": "Consejo: haz clic derecho en un día para ver las acciones",
+    "scheduleMessage": "Programar mensaje"
+  },
   "events": {
     "status": {
       "completed": "Completado",
@@ -54,12 +64,15 @@
       "draft": "Borrador",
       "done": "Hecho",
       "overdue": "Vencido",
-      "upcoming": "Próximo"
+      "upcoming": "Próximo",
+      "failed": "Fallido",
+      "queued": "En cola"
     },
     "type": {
       "service": "Servicio",
       "reminder": "Recordatorio",
-      "quote": "Presupuesto"
+      "quote": "Presupuesto",
+      "message": "Mensaje"
     },
     "noEvents": "Sin eventos",
     "selectDay": "Seleccione un día con eventos o cree una nueva orden de trabajo."

+ 29 - 5
messages/es/common.json

@@ -1,7 +1,7 @@
 {
   "brandName": "Torqvoice",
   "buttons": {
-    "signIn": "Iniciar sesion",
+    "signIn": "Iniciar sesión",
     "save": "Guardar",
     "cancel": "Cancelar",
     "delete": "Eliminar",
@@ -21,8 +21,8 @@
     "delete": "Eliminar"
   },
   "form": {
-    "email": "Correo electronico",
-    "password": "Contrasena",
+    "email": "Correo electrónico",
+    "password": "Contraseña",
     "emailPlaceholder": "you@example.com",
     "name": "Nombre",
     "phone": "Teléfono",
@@ -31,11 +31,11 @@
     "notes": "Notas"
   },
   "errors": {
-    "unexpected": "Ha ocurrido un error inesperado. Por favor, intentelo de nuevo.",
+    "unexpected": "Ha ocurrido un error inesperado. Por favor, inténtelo de nuevo.",
     "error": "Error"
   },
   "terms": {
-    "termsOfService": "Terminos de servicio"
+    "termsOfService": "Términos de servicio"
   },
   "errorPage": {
     "title": "Algo salió mal",
@@ -52,5 +52,29 @@
     "updated": "Torqvoice se ha actualizado a {version}",
     "whatsNew": "Ver novedades",
     "dismiss": "Cerrar"
+  },
+  "pagination": {
+    "showing": "Mostrando {start}–{end} de {total}",
+    "perPage": "por página",
+    "pageOf": "Página {page} de {pages}",
+    "first": "Primera página",
+    "previous": "Página anterior",
+    "next": "Página siguiente",
+    "last": "Última página"
+  },
+  "shared": {
+    "close": "Cerrar",
+    "viewPlans": "Ver planes",
+    "manageLicense": "Gestionar licencia",
+    "installOwn": "Instale el suyo",
+    "install": "Instalar",
+    "installApp": "Instalar aplicación",
+    "installTorqvoice": "Instalar Torqvoice",
+    "dismiss": "Descartar",
+    "useCamera": "Usar la cámara",
+    "enterManually": "Introducir manualmente",
+    "enterBarcode": "Introducir código de barras…",
+    "scanHint": "Apunte la cámara a un código de barras o introdúzcalo manualmente",
+    "iosInstallHint": "Toque Compartir > Añadir a inicio"
   }
 }

+ 396 - 0
messages/es/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Sin deficiencia",
+      "attention": "Deficiencia leve",
+      "fail": "Deficiencia grave",
+      "dangerous": "Deficiencia peligrosa",
+      "not_inspected": "No inspeccionado"
+    },
+    "basic": {
+      "pass": "Apto",
+      "attention": "Atención",
+      "fail": "No apto",
+      "dangerous": "Peligroso",
+      "not_inspected": "No inspeccionado"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Leve",
+      "fail": "Grave",
+      "dangerous": "Peligrosa",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Cumple los requisitos. Nada que señalar.",
+      "attention": "Sin efecto significativo sobre la seguridad. El vehículo es apto; subsanar cuando convenga.",
+      "fail": "Puede perjudicar la seguridad o afectar al medio ambiente. El vehículo no es apto; subsanar y volver a inspeccionar.",
+      "dangerous": "Riesgo directo e inmediato para la seguridad vial. El vehículo no debe circular.",
+      "not_inspected": "Este punto no se ha realizado."
+    }
+  },
+  "results": {
+    "pass": "Favorable",
+    "pass_minor": "Favorable con deficiencias leves",
+    "fail": "Desfavorable — deficiencias graves",
+    "fail_dangerous": "Negativo — deficiencias peligrosas",
+    "incomplete": "Sin finalizar",
+    "detail": {
+      "pass": "No se detectaron deficiencias.",
+      "pass_minor": "El vehículo es apto. Repare las deficiencias leves sin demora indebida.",
+      "fail": "El vehículo no es apto. Las deficiencias deben repararse y el vehículo volver a inspeccionarse.",
+      "fail_dangerous": "El vehículo no debe circular por la vía pública hasta que se reparen las deficiencias peligrosas.",
+      "incomplete": "Esta inspección sigue en curso."
+    }
+  },
+  "page": {
+    "back": "Inspecciones",
+    "statusInProgress": "En curso",
+    "statusCompleted": "Cerrada",
+    "complete": "Cerrar",
+    "reopen": "Reabrir",
+    "share": "Compartir",
+    "save": "Guardar",
+    "saving": "Guardando…",
+    "savedAt": "Guardado {time}",
+    "savesAsYouGo": "Guarda mientras trabaja",
+    "saveFailed": "Algunos cambios no se guardaron",
+    "allSaved": "Todos los cambios están guardados",
+    "moreActions": "Más acciones",
+    "downloadCertificate": "Descargar informe",
+    "manageTemplates": "Gestionar plantillas",
+    "delete": "Eliminar",
+    "createWorkOrder": "Crear orden de trabajo",
+    "viewWorkOrder": "Ver orden de trabajo",
+    "createQuote": "Crear presupuesto",
+    "viewQuote": "Ver presupuesto",
+    "needsDefect": "Disponible cuando se registre una deficiencia",
+    "workOrderRaised": "Orden de trabajo {number} creada desde esta inspección el {date}",
+    "open": "Abrir",
+    "quoteCreated": "Presupuesto creado por {name} el {date}",
+    "quoteRequested": "El cliente pidió presupuesto de {count} punto(s)",
+    "stillToGrade": "Quedan {count} de {total} puntos por calificar.",
+    "progress": "Avance",
+    "checksGraded": "puntos calificados",
+    "progressLabel": "{graded} de {total} puntos calificados: {pass} sin deficiencia, {attention} leves, {fail} graves, {dangerous} peligrosas.",
+    "sections": "Grupos",
+    "graded": "{graded}/{total} calificados",
+    "vehicle": "Vehículo",
+    "vessel": "Embarcación",
+    "customer": "Cliente",
+    "plate": "Matrícula",
+    "registration": "Matrícula",
+    "template": "Plantilla",
+    "scaleEu": "Calificado según la escala de deficiencias de la UE de la Directiva 2014/45/UE.",
+    "scaleBasic": "Calificado apto / atención / no apto.",
+    "country": "País: {code}.",
+    "manageInspectionTemplates": "Gestionar plantillas de inspección",
+    "readMore": "Más información",
+    "odometer": "Cuentakilómetros",
+    "engineHours": "Horas de motor",
+    "completeTitle": "¿Cerrar esta inspección?",
+    "completeBody": "Los puntos quedan bloqueados al cerrar, y el resultado pasa a ser «{result}».",
+    "completeBlocked": "Quedan {count} punto(s) que la plantilla marca como obligatorios.",
+    "completeUngraded": "{count} punto(s) no se han calificado.",
+    "completeDangerous": "{count} deficiencia(s) peligrosa(s) registrada(s). El vehículo no debe circular por la vía pública.",
+    "reopenTitle": "¿Reabrir esta inspección?",
+    "reopenBody": "Los puntos vuelven a ser editables y el resultado regresa a en curso. Se conservan el inspector, el número de certificado y la fecha de la próxima inspección.",
+    "reopenShared": "El enlace del cliente sigue activo y mostrará cómo cambia el resultado mientras trabaja. Un informe ya descargado conserva el resultado anterior.",
+    "deleteTitle": "¿Eliminar esta inspección?",
+    "deleteBody": "Esto elimina de forma permanente la inspección, sus calificaciones, notas y fotos. No se puede deshacer.",
+    "cancel": "Cancelar",
+    "completed": "Inspección cerrada",
+    "reopened": "Inspección reabierta",
+    "deleted": "Inspección eliminada",
+    "completeFailed": "No se pudo cerrar la inspección",
+    "reopenFailed": "No se pudo reabrir la inspección",
+    "deleteFailed": "No se pudo eliminar la inspección",
+    "quoteFailed": "No se pudo crear el presupuesto",
+    "workOrderFailed": "No se pudo crear la orden de trabajo"
+  },
+  "item": {
+    "required": "(obligatorio)",
+    "saving": "Guardando",
+    "addNote": "Añadir nota",
+    "hideNote": "Ocultar nota",
+    "addPhoto": "Añadir foto o vídeo a {name}",
+    "notesFor": "Notas de {name}",
+    "describeDefect": "Describa la deficiencia — aparece en el informe",
+    "optionalNote": "Añadir una nota (opcional)",
+    "notesRequired": "Describa la deficiencia antes de que se guarde esta calificación.",
+    "photoRequired": "Aquí se exige una foto de la deficiencia. La inspección no puede cerrarse hasta que se adjunte una.",
+    "reading": "Lectura",
+    "readingUnit": "Lectura ({unit})",
+    "limit": "Límite: {range}",
+    "recordedValue": "Valor registrado",
+    "answer": "Respuesta",
+    "selectAnswer": "Elija una respuesta",
+    "viewPhoto": "Ver la foto {index} de {name} a tamaño completo",
+    "photoAlt": "{name}, foto {index}",
+    "removePhoto": "Quitar la foto {index} de {name}",
+    "clearTitle": "¿Borrar esta calificación?",
+    "clearBody": "Se eliminará la nota registrada en «{name}» y el punto volverá a no inspeccionado.",
+    "clear": "Borrar",
+    "cancel": "Cancelar",
+    "saveFailed": "No se pudo guardar este punto",
+    "uploadFailed": "Error al subir",
+    "uploadFailedFor": "No se pudo subir {name}"
+  },
+  "suggestions": {
+    "title": "Deficiencias habituales",
+    "add": "Añadir «{text}» y calificar como {grade}",
+    "more": "Más ({count})",
+    "search": "Buscar redacción",
+    "empty": "Ninguna redacción coincide.",
+    "source": {
+      "workshop": "Su taller",
+      "history": "Usada antes",
+      "regulation": "Directiva 2014/45/UE",
+      "general": "General"
+    }
+  },
+  "media": {
+    "viewer": "Imagen {index} de {total}: {caption}",
+    "close": "Cerrar el visor",
+    "previous": "Imagen anterior",
+    "next": "Imagen siguiente"
+  },
+  "certificate": {
+    "title": "Datos del informe",
+    "description": "Exigidos en un informe de inspección técnica conforme a la Directiva 2014/45/UE, anexo IV.",
+    "inspector": "Inspector",
+    "notRecorded": "No registrado",
+    "addTechnician": "Añadir técnico…",
+    "recordedAs": "Registrado como {name}",
+    "vehicleCategory": "Categoría del vehículo",
+    "mileageAtTest": "{label} en el momento de la inspección",
+    "reportReference": "Referencia del informe",
+    "reportReferenceHelp": "Su propia referencia para este informe. Si es un centro autorizado que emite un informe oficial, escriba aquí su número para que ambos coincidan. En caso contrario, déjelo vacío.",
+    "optional": "Opcional",
+    "placeOfTest": "Lugar de la inspección",
+    "placeholderAddress": "Estación de inspección o dirección del taller",
+    "fromSettings": "De la configuración de su taller.",
+    "change": "Cambiar",
+    "differsFromWorkshop": "Difiere de la dirección de su taller.",
+    "useWorkshopAddress": "Usar la dirección del taller",
+    "noWorkshopAddress": "No hay ninguna dirección de taller configurada.",
+    "addOne": "Añadir una",
+    "nextTestDue": "Próxima inspección",
+    "notSet": "Sin definir",
+    "intervalGroup": "Fijar la fecha de la próxima inspección a partir de esta",
+    "intervalHelp": "Contado desde la fecha de esta inspección. Dos años es la referencia de la Unión para turismos y vehículos comerciales ligeros; compruebe el intervalo que aplica su país.",
+    "months6": "6 meses",
+    "years1": "1 año",
+    "years2": "2 años",
+    "years3": "3 años",
+    "years4": "4 años",
+    "unsaved": "Cambios sin guardar",
+    "saveDetails": "Guardar datos",
+    "saved": "Datos guardados",
+    "saveFailed": "No se pudieron guardar los datos",
+    "addTechnicianTitle": "Añadir técnico",
+    "addTechnicianBody": "Se incorpora a la lista del taller y se le pueden asignar tanto trabajos como inspecciones.",
+    "technicianName": "Nombre",
+    "technicianPlaceholder": "p. ej. Anna Berg",
+    "addAndSelect": "Añadir y seleccionar",
+    "technicianAdded": "{name} añadido y seleccionado",
+    "technicianFailed": "No se pudo añadir al técnico",
+    "cancel": "Cancelar"
+  },
+  "templates": {
+    "title": "Plantillas de inspección",
+    "description": "Las listas de comprobación que recorren sus técnicos. Cree una por país, por tipo de vehículo o por servicio que venda.",
+    "import": "Importar",
+    "browse": "Explorar listas",
+    "new": "Nueva plantilla",
+    "restoreBanner": "{count} listas ya preparadas se han quitado de su lista. Puede volver a añadirlas.",
+    "restore": "Restaurar",
+    "restored": "{count} lista(s) restaurada(s)",
+    "allPresent": "Todas las listas ya están aquí",
+    "restoreFailed": "No se pudieron añadir las listas",
+    "emptyTitle": "Aún no hay plantillas",
+    "emptyBody": "Las listas ya preparadas, incluida la inspección técnica periódica de la UE, se han quitado todas. Vuelva a añadirlas o construya la suya desde cero.",
+    "restoreChecklists": "Restaurar listas",
+    "buildMyOwn": "Construir la mía",
+    "default": "Predeterminada",
+    "actionsFor": "Acciones de {name}",
+    "edit": "Editar",
+    "duplicate": "Duplicar",
+    "export": "Exportar…",
+    "delete": "Eliminar",
+    "sections": "{count} grupo(s)",
+    "checks": "{count} punto(s)",
+    "measured": "{count} medidos",
+    "euScale": "Escala de deficiencias UE",
+    "basicScale": "Apto / atención / no apto",
+    "deleteTitle": "¿Eliminar «{name}»?",
+    "deleteBody": "Esto elimina la plantilla de forma permanente. Las inspecciones ya realizadas con ella conservan su propia copia de la lista y no se ven afectadas.",
+    "deleted": "Plantilla eliminada",
+    "deleteFailed": "No se pudo eliminar la plantilla",
+    "duplicated": "Plantilla duplicada",
+    "duplicateFailed": "No se pudo duplicar la plantilla",
+    "cancel": "Cancelar",
+    "srSections": "Grupos",
+    "srChecks": "Puntos",
+    "srMeasurements": "Mediciones"
+  },
+  "presets": {
+    "title": "Partir de una plantilla",
+    "description": "Cada plantilla se copia a su taller como una plantilla normal. Renombre grupos, mueva puntos y cambie cualquier límite para que encaje con su país y su equipo.",
+    "search": "Buscar por nombre, país o norma",
+    "searchLabel": "Buscar plantillas",
+    "inYourList": "En su lista",
+    "counts": "{sections} grupos · {checks} puntos",
+    "noMatch": "Ninguna plantilla coincide con «{query}».",
+    "warning": "Las plantillas reglamentarias llevan los límites habituales de la UE. Compruébelos con su normativa nacional antes de emitir un informe.",
+    "cancel": "Cancelar",
+    "add": "Añadir plantilla",
+    "added": "Plantilla añadida. Adáptela a su taller.",
+    "addFailed": "No se pudo añadir la plantilla",
+    "group": {
+      "regulatory": "Reglamentaria",
+      "workshop": "Taller",
+      "specialist": "Especializada"
+    },
+    "groupDescription": {
+      "regulatory": "Listas de inspección técnica periódica basadas en la Directiva 2014/45/UE.",
+      "workshop": "Listas generales de servicio y venta no vinculadas a una normativa.",
+      "specialist": "Listas para motorizaciones y embarcaciones que requieren su propio procedimiento."
+    },
+    "euScale": "Escala de deficiencias UE",
+    "basicScale": "Apto / atención / no apto"
+  },
+  "builder": {
+    "newTitle": "Nueva plantilla",
+    "editTitle": "Editar plantilla",
+    "description": "Construya la lista que su taller usa de verdad. Arrastre para reordenar y configure cada punto para que registre una calificación, una medición, una nota escrita o una respuesta fija.",
+    "name": "Nombre",
+    "namePlaceholder": "p. ej. Inspección técnica periódica",
+    "templateDescription": "Descripción",
+    "descriptionPlaceholder": "Para qué sirve esta lista y cuándo se usa.",
+    "country": "País",
+    "notCountrySpecific": "No específica de un país",
+    "countryHelp": "Se registra en el informe para que un taller que trabaja a ambos lados de una frontera distinga sus listas.",
+    "defectScale": "Escala de deficiencias",
+    "scaleEu": "Leve / grave / peligrosa (UE)",
+    "scaleBasic": "Apto / atención / no apto",
+    "scaleEuHelp": "Las categorías del artículo 7, apartado 2, de la Directiva 2014/45/UE. Un vehículo con solo deficiencias leves sigue siendo apto.",
+    "scaleBasicHelp": "Una escala sencilla de tres pasos para listas de servicio que no son una inspección reglamentaria.",
+    "defaultTemplate": "Plantilla predeterminada",
+    "defaultHelp": "Preseleccionada cuando un técnico inicia una nueva inspección.",
+    "summary": "{sections} grupo(s) · {checks} punto(s)",
+    "renumber": "Renumerar referencias",
+    "renumberHelp": "Numera cada grupo y cada punto en orden: 1, 1.1, 1.2, 2. Las filas nuevas se numeran al añadirlas, así que esto solo hace falta tras mover cosas.",
+    "renumberWarning": "Esta lista usa referencias normativas como 1.1.13. Renumerar las sustituye.",
+    "addSection": "Añadir grupo",
+    "addCheck": "Añadir punto",
+    "ref": "Ref.",
+    "sectionName": "Nombre del grupo, p. ej. Frenos",
+    "sectionNote": "Nota opcional mostrada sobre los puntos de este grupo",
+    "checkName": "Nombre del punto, p. ej. Pastillas de freno",
+    "reorderSection": "Reordenar el grupo {name}",
+    "reorderCheck": "Reordenar el punto {name}",
+    "removeSection": "Quitar el grupo {name}",
+    "removeCheck": "Quitar el punto {name}",
+    "duplicateCheck": "Duplicar el punto {name}",
+    "configure": "Configurar {name}",
+    "hideSettings": "Ocultar los ajustes de {name}",
+    "howRecorded": "¿Cómo se registra?",
+    "guidance": "Indicación para el técnico",
+    "guidancePlaceholder": "Se muestra bajo el nombre del punto en el formulario de inspección.",
+    "measurement": "Medición",
+    "unit": "Unidad",
+    "minimum": "Mínimo",
+    "maximum": "Máximo",
+    "outOfRange": "Deficiencia fuera de intervalo",
+    "rangeHelp": "Deje un límite vacío para un requisito de un solo lado, por ejemplo un mínimo de 1,6 mm sin máximo. Las lecturas fuera del intervalo se califican automáticamente.",
+    "answers": "Respuestas",
+    "answersHelp": "Separe las respuestas con comas.",
+    "mustComplete": "Debe cumplimentarse",
+    "photoRequired": "Foto obligatoria cuando se registra una deficiencia",
+    "commonWording": "Redacciones habituales",
+    "commonWordingHelp": "Una redacción por línea. Se ofrecen las primeras cuando un técnico registra aquí una deficiencia, por delante de los textos incorporados, para que su taller acuerde cómo describir un fallo.",
+    "inputType": {
+      "condition": "Calificación de deficiencia",
+      "measurement": "Medición",
+      "text": "Texto libre",
+      "choice": "Elección"
+    },
+    "inputHint": {
+      "condition": "El técnico califica el punto según la escala de deficiencias.",
+      "measurement": "Registra un número con unidad, calificado automáticamente frente a un intervalo.",
+      "text": "Registra una observación escrita, por ejemplo una marca de neumático o un código de avería.",
+      "choice": "El técnico elige una respuesta de una lista fija."
+    },
+    "cancel": "Cancelar",
+    "create": "Crear plantilla",
+    "saveChanges": "Guardar cambios",
+    "created": "Plantilla creada",
+    "updated": "Plantilla actualizada",
+    "saveFailed": "No se pudo guardar la plantilla",
+    "severityAttention": "Deficiencia leve",
+    "severityFail": "Deficiencia grave",
+    "severityDangerous": "Deficiencia peligrosa",
+    "answersPlaceholder": "Completo, Parcial, Ninguno"
+  },
+  "packages": {
+    "exportTitle": "Exportar «{name}»",
+    "exportDescription": "Descarga toda la lista como archivo: grupos, puntos, unidades y límites. Cualquiera que use Torqvoice puede importarla.",
+    "includeWording": "Incluir sus propias redacciones",
+    "includeWordingHelp": "Las redacciones que su taller añadió a los puntos. Útiles para quien las reciba, pero son texto libre escrito en el banco de trabajo y pueden nombrar a un cliente, a un compañero o un acuerdo local. Desactivado salvo que las haya leído.",
+    "attributeTo": "Atribuir a (opcional)",
+    "attributePlaceholder": "p. ej. Egeland Auto",
+    "attributeHelp": "Se escribe en el archivo para que quien lo instale vea de dónde viene. No se toma nada de su cuenta.",
+    "download": "Descargar",
+    "exported": "Plantilla exportada",
+    "exportFailed": "No se pudo exportar esta plantilla",
+    "importTitle": "Importar una lista",
+    "importDescription": "Añade una lista desde un archivo de paquete de Torqvoice. Llega como una plantilla normal que puede editar y nunca sustituye a una que ya tenga.",
+    "chooseFile": "Elegir un archivo de paquete",
+    "chooseAnother": "Elegir otro archivo",
+    "unreadable": "No se pudo leer ese archivo. Un paquete de Torqvoice es un archivo .json exportado desde una plantilla.",
+    "from": "De {author}",
+    "limitsWarning": "Los límites de una lista compartida son los que fijó su autor. Compruébelos con su normativa nacional antes de emitir nada a partir de ella.",
+    "import": "Importar",
+    "imported": "{count} plantilla(s) importada(s)",
+    "importFailed": "No se pudo importar este paquete",
+    "cancel": "Cancelar"
+  },
+  "list": {
+    "tabAll": "Todas",
+    "tabInProgress": "En curso",
+    "tabCompleted": "Cerradas",
+    "search": "Buscar inspecciones…",
+    "new": "Nueva inspección",
+    "empty": "No se encontraron inspecciones.",
+    "vehicle": "Vehículo",
+    "template": "Plantilla",
+    "progress": "Avance",
+    "status": "Estado",
+    "date": "Fecha",
+    "statusInProgress": "En curso",
+    "statusCompleted": "Cerrada"
+  },
+  "new": {
+    "title": "Nueva inspección",
+    "vehicle": "Vehículo",
+    "searchVehicles": "Buscar vehículos…",
+    "loadingVehicles": "Cargando vehículos…",
+    "noVehicles": "No se encontraron vehículos.",
+    "template": "Plantilla",
+    "selectTemplate": "Elegir plantilla",
+    "manageTemplates": "Gestionar plantillas",
+    "cancel": "Cancelar",
+    "create": "Crear inspección",
+    "created": "Inspección creada",
+    "createFailed": "No se pudo crear la inspección"
+  },
+  "shareDialog": {
+    "title": "Compartir inspección",
+    "description": "Comparta con su cliente una vista de solo lectura de esta inspección.",
+    "copyLink": "Copiar enlace",
+    "copied": "Enlace copiado al portapapeles",
+    "generated": "Enlace de compartición creado",
+    "revoked": "Enlace de compartición revocado"
+  }
+}

+ 29 - 2
messages/es/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "Mensajería SMS",
-    "featureDescription": "Envíe y reciba mensajes SMS con sus clientes directamente desde Torqvoice."
+    "featureDescription": "Envíe y reciba mensajes SMS con sus clientes directamente desde Torqvoice.",
+    "tabs": {
+      "inbox": "Bandeja",
+      "scheduled": "Programados"
+    },
+    "smsNotConfiguredTitle": "SMS no está configurado",
+    "smsNotConfiguredHint": "Conecta un proveedor de SMS para enviar y recibir mensajes aquí. El correo programado funciona igual.",
+    "goToSmsSettings": "Ir a ajustes de SMS"
   },
   "notConfigured": {
     "title": "SMS no configurado",
@@ -20,7 +27,10 @@
     "deleted": "Conversación eliminada",
     "deleteError": "No se pudo eliminar la conversación",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Buscar conversaciones",
+    "noSearchResults": "Ninguna conversación coincide con la búsqueda",
+    "now": "ahora"
   },
   "conversation": {
     "noPhone": "No hay número de teléfono registrado para {name}. Agregue un número de teléfono para comenzar a enviar mensajes.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS enviado",
     "sentTo": "{label} ha sido enviado a {name} ({phone})",
     "sendError": "No se pudo enviar el SMS"
+  },
+  "compose": {
+    "newMessage": "Nuevo mensaje",
+    "title": "Nuevo mensaje",
+    "searchPlaceholder": "Buscar clientes por nombre o número",
+    "noMatches": "Ningún cliente coincide con la búsqueda",
+    "noRecipients": "No hay clientes con teléfono",
+    "noRecipientsHint": "Añade un teléfono al cliente para enviarle SMS.",
+    "changeRecipient": "Elegir a otra persona",
+    "messageLabel": "Mensaje",
+    "messagePlaceholder": "Mensaje para {name}...",
+    "segments": "{chars} caracteres · {segments} SMS",
+    "send": "Enviar",
+    "scheduleInstead": "Programar en su lugar",
+    "sent": "Enviado a {name}",
+    "sendError": "No se pudo enviar el mensaje",
+    "templates": "Plantillas"
   }
 }

+ 2 - 3
messages/es/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Buscar...",
   "shortcut": "Ctrl+K",
+  "readMore": "Más información",
   "newWorkOrder": "Nueva orden de trabajo",
   "quickCreate": {
     "title": "Agregar",
@@ -77,7 +78,6 @@
     "clients": "Clientes",
     "customers": "Clientes",
     "messages": "Mensajes",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Taller",
     "vehicles": "Vehículos",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "ej. Taller Mecánico López",
     "cancel": "Cancelar",
     "createCompany": "Crear empresa",
-    "lightMode": "Modo claro",
-    "darkMode": "Modo oscuro",
+    "theme": "Tema",
     "signOut": "Cerrar sesión",
     "more": "Más",
     "auditLog": "Registro de auditoría",

+ 31 - 1
messages/es/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Notas",
     "footerText": "Inspección de vehículo — {shopName}",
     "viewPortal": "Ver su portal: {url}",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "euPass": "Sin deficiencia",
+    "euAttention": "Deficiencia leve",
+    "euFail": "Deficiencia grave",
+    "euDangerous": "Deficiencia peligrosa",
+    "basicPass": "Apto",
+    "basicAttention": "Atención",
+    "basicFail": "No apto",
+    "basicDangerous": "Peligroso",
+    "resultPass": "Favorable",
+    "resultPassMinor": "Favorable con deficiencias leves",
+    "resultFail": "Desfavorable — deficiencias graves",
+    "resultFailDangerous": "Negativo — deficiencias peligrosas",
+    "resultIncomplete": "Sin finalizar",
+    "testDetails": "Datos de la inspección",
+    "testDate": "Fecha de la inspección",
+    "testLocation": "Lugar de la inspección",
+    "inspector": "Inspector",
+    "certificateNumber": "Número de certificado",
+    "vehicleCategory": "Categoría del vehículo",
+    "nextTestDue": "Próxima inspección",
+    "limit": "Límite",
+    "overallResult": "Resultado de la inspección",
+    "deficiencies": "Deficiencias detectadas",
+    "reading": "Lectura",
+    "noDeficiencies": "No se registraron deficiencias.",
+    "resultDetailPass": "No se detectaron deficiencias.",
+    "resultDetailPassMinor": "El vehículo es apto. Repare las deficiencias leves sin demora indebida.",
+    "resultDetailFail": "El vehículo no es apto. Las deficiencias deben repararse y el vehículo volver a inspeccionarse.",
+    "resultDetailFailDangerous": "El vehículo no debe circular por la vía pública hasta que se reparen las deficiencias peligrosas.",
+    "resultDetailIncomplete": "Esta inspección sigue en curso."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "HISTORIAL DE SERVICIO",

+ 76 - 0
messages/es/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Programar un mensaje",
+    "editTitle": "Editar mensaje programado",
+    "channelLabel": "Enviar por",
+    "channels": {
+      "email": "Correo",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "Nota en la app"
+    },
+    "repeatLabel": "Repetir",
+    "frequencies": {
+      "once": "Una vez",
+      "daily": "Diario",
+      "weekly": "Semanal",
+      "biweekly": "Cada 2 semanas",
+      "monthly": "Mensual",
+      "yearly": "Anual"
+    },
+    "customerLabel": "Cliente",
+    "selectCustomer": "Seleccionar cliente",
+    "none": "Ninguno",
+    "recipientEmail": "Dirección de correo",
+    "recipientPhone": "Número de teléfono",
+    "recipientChat": "ID de chat de Telegram",
+    "recipientOverride": "Enviar a otra dirección",
+    "recipientHintCustomer": "Déjalo vacío para usar los datos guardados.",
+    "recipientHintDirect": "Elige un cliente o escribe el destino.",
+    "subjectLabel": "Asunto",
+    "subjectPlaceholder": "p. ej. Su coche está listo",
+    "messageLabel": "Mensaje",
+    "messagePlaceholder": "¿Qué quieres decir?",
+    "characters": "{count} / {max} caracteres",
+    "dateLabel": "Fecha",
+    "timeLabel": "Hora",
+    "endDateLabel": "Repetir hasta",
+    "endDateHint": "Déjalo vacío para repetir siempre.",
+    "schedule": "Programar",
+    "scheduled": "Mensaje programado",
+    "updated": "Mensaje programado actualizado",
+    "saveError": "No se pudo guardar el mensaje"
+  },
+  "list": {
+    "scheduleMessage": "Programar mensaje",
+    "scheduleForCustomer": "Programar un mensaje",
+    "filters": {
+      "upcoming": "Próximos",
+      "sent": "Enviados",
+      "failed": "Fallidos",
+      "cancelled": "Cancelados",
+      "all": "Todos"
+    },
+    "status": {
+      "scheduled": "Programado",
+      "sent": "Enviado",
+      "failed": "Fallido",
+      "cancelled": "Cancelado"
+    },
+    "empty": "Nada programado",
+    "emptyHint": "Haz clic derecho en un día del calendario o usa Programar mensaje.",
+    "noRecipient": "Sin destinatario",
+    "sentCount": "enviado {count}x",
+    "rowMenu": "Menú del mensaje",
+    "sendNow": "Enviar ahora",
+    "cancel": "Cancelar envío",
+    "sentNow": "Mensaje enviado",
+    "sendError": "No se pudo enviar el mensaje",
+    "cancelled": "Envío cancelado",
+    "cancelError": "No se pudo cancelar el mensaje",
+    "deleted": "Mensaje eliminado",
+    "deleteError": "No se pudo eliminar el mensaje",
+    "deleteTitle": "¿Eliminar este mensaje?",
+    "deleteDescription": "El mensaje programado se elimina definitivamente. Lo ya enviado permanece en la conversación."
+  }
+}

+ 233 - 221
messages/es/settings.json

@@ -1,10 +1,10 @@
 {
-  "title": "Configuracion",
+  "title": "Configuración",
   "subtitle": "Administre su taller, facturas y preferencias",
   "nav": {
     "categories": {
       "general": "General",
-      "billing": "Facturacion y documentos",
+      "billing": "Facturación y documentos",
       "communications": "Comunicaciones",
       "workshop": "Taller",
       "integrations": "Integraciones",
@@ -16,12 +16,12 @@
         "description": "Datos comerciales y marca"
       },
       "subscription": {
-        "title": "Suscripcion",
-        "description": "Plan y facturacion"
+        "title": "Suscripción",
+        "description": "Plan y facturación"
       },
       "account": {
         "title": "Cuenta",
-        "description": "Nombre, correo y contrasena"
+        "description": "Nombre, correo y contraseña"
       },
       "team": {
         "title": "Equipo",
@@ -29,7 +29,7 @@
       },
       "invoice": {
         "title": "Facturas y presupuestos",
-        "description": "Configuracion de facturas, diseno y campos personalizados"
+        "description": "Configuración de facturas, diseño y campos personalizados"
       },
       "templates": {
         "title": "Plantillas",
@@ -57,11 +57,11 @@
       },
       "email": {
         "title": "Correo",
-        "description": "Proveedor de correo y envio"
+        "description": "Proveedor de correo y envío"
       },
       "sms": {
         "title": "SMS",
-        "description": "Proveedor de SMS y mensajeria"
+        "description": "Proveedor de SMS y mensajería"
       },
       "telegram": {
         "title": "Telegram",
@@ -73,7 +73,7 @@
       },
       "workshop": {
         "title": "Taller",
-        "description": "Valores predeterminados de tecnico y mano de obra"
+        "description": "Valores predeterminados de técnico y mano de obra"
       },
       "laborPresets": {
         "title": "Paquetes de mano de obra",
@@ -97,7 +97,7 @@
       },
       "appearance": {
         "title": "Apariencia",
-        "description": "Tema y visualizacion"
+        "description": "Tema y visualización"
       },
       "data": {
         "title": "Datos",
@@ -109,7 +109,7 @@
       },
       "about": {
         "title": "Acerca de",
-        "description": "Version e informacion"
+        "description": "Version e información"
       },
       "alerts": {
         "title": "Alertas",
@@ -123,7 +123,7 @@
     "pro": "PRO"
   },
   "readOnly": {
-    "banner": "Tiene acceso de solo lectura a la configuracion. Contacte a un administrador para realizar cambios."
+    "banner": "Tiene acceso de solo lectura a la configuración. Contacte a un administrador para realizar cambios."
   },
   "featureLocked": {
     "requiresPro": "Requiere una licencia Pro",
@@ -141,23 +141,23 @@
     "failedUploadLogo": "Error al subir el logo",
     "detailsTitle": "Datos de la empresa",
     "shopName": "Nombre de la empresa / taller",
-    "shopNamePlaceholder": "Taller Mecanico Lopez",
-    "orgNumber": "Numero de organizacion",
+    "shopNamePlaceholder": "Taller Mecánico Lopez",
+    "orgNumber": "Número de organización",
     "orgNumberPlaceholder": "123 456 789",
-    "phone": "Telefono",
+    "phone": "Teléfono",
     "phonePlaceholder": "(555) 123-4567",
-    "email": "Correo electronico",
+    "email": "Correo electrónico",
     "emailPlaceholder": "servicio@ejemplo.com",
-    "address": "Direccion",
+    "address": "Dirección",
     "addressPlaceholder": "Calle Principal 123\nPiso 1\n12345 Ciudad",
     "saveCompany": "Guardar datos de empresa",
     "addNewCompany": "Agregar nueva empresa",
     "companyName": "Nombre de la empresa",
-    "companyNamePlaceholder": "Ej. Taller Mecanico Lopez",
+    "companyNamePlaceholder": "Ej. Taller Mecánico Lopez",
     "cancel": "Cancelar",
     "createCompany": "Crear empresa",
-    "settingsSaved": "Configuracion de empresa guardada",
-    "failedSave": "Error al guardar la configuracion",
+    "settingsSaved": "Configuración de empresa guardada",
+    "failedSave": "Error al guardar la configuración",
     "companyCreated": "Empresa creada exitosamente",
     "serviceType": "Tipo de Servicio",
     "serviceTypeDescription": "Seleccione el tipo de servicio que ofrece su taller. Esto cambia las etiquetas de los campos en toda la aplicación.",
@@ -168,7 +168,7 @@
   },
   "account": {
     "profileTitle": "Perfil",
-    "profileDescription": "Actualice su nombre para mostrar y direccion de correo electronico.",
+    "profileDescription": "Actualice su nombre para mostrar y dirección de correo electrónico.",
     "emailVerified": "Verificado",
     "emailNotVerified": "No verificado",
     "sendVerificationEmail": "Enviar correo de verificación",
@@ -178,50 +178,50 @@
     "emailChangeSent": "Se ha enviado un enlace de confirmación a su nueva dirección de correo electrónico. Su correo se actualizará cuando haga clic en el enlace.",
     "name": "Nombre",
     "namePlaceholder": "Su nombre",
-    "emailLabel": "Correo electronico",
-    "emailPlaceholder": "Su correo electronico",
+    "emailLabel": "Correo electrónico",
+    "emailPlaceholder": "Su correo electrónico",
     "saveProfile": "Guardar perfil",
     "profileUpdated": "Perfil actualizado",
     "failedUpdateProfile": "Error al actualizar el perfil",
-    "failedUpdateEmail": "Error al actualizar el correo electronico",
-    "changePasswordTitle": "Cambiar contrasena",
-    "changePasswordDescription": "Ingrese su contrasena actual y elija una nueva.",
-    "currentPassword": "Contrasena actual",
-    "newPassword": "Nueva contrasena",
-    "confirmNewPassword": "Confirmar nueva contrasena",
-    "changePassword": "Cambiar contrasena",
-    "passwordChanged": "Contrasena cambiada",
-    "passwordsNoMatch": "Las contrasenas no coinciden",
-    "passwordMinLength": "La contrasena debe tener al menos 8 caracteres",
-    "failedChangePassword": "Error al cambiar la contrasena",
+    "failedUpdateEmail": "Error al actualizar el correo electrónico",
+    "changePasswordTitle": "Cambiar contraseña",
+    "changePasswordDescription": "Ingrese su contraseña actual y elija una nueva.",
+    "currentPassword": "Contraseña actual",
+    "newPassword": "Nueva contraseña",
+    "confirmNewPassword": "Confirmar nueva contraseña",
+    "changePassword": "Cambiar contraseña",
+    "passwordChanged": "Contraseña cambiada",
+    "passwordsNoMatch": "Las contraseñas no coinciden",
+    "passwordMinLength": "La contraseña debe tener al menos 8 caracteres",
+    "failedChangePassword": "Error al cambiar la contraseña",
     "twoFactorTitle": "Autenticacion de dos factores",
     "twoFactorEnabled": "La autenticacion de dos factores esta habilitada",
-    "twoFactorDisablePrompt": "Ingrese su contrasena para deshabilitar la autenticacion de dos factores.",
-    "twoFactorEnablePrompt": "Agregue una capa adicional de seguridad a su cuenta habilitando la autenticacion de dos factores con una aplicacion de autenticacion.",
-    "password": "Contrasena",
-    "enterPassword": "Ingrese su contrasena",
+    "twoFactorDisablePrompt": "Ingrese su contraseña para deshabilitar la autenticacion de dos factores.",
+    "twoFactorEnablePrompt": "Agregue una capa adicional de seguridad a su cuenta habilitando la autenticacion de dos factores con una aplicación de autenticacion.",
+    "password": "Contraseña",
+    "enterPassword": "Ingrese su contraseña",
     "disable2FA": "Deshabilitar 2FA",
     "enable2FA": "Habilitar 2FA",
     "twoFactorDisabled": "Autenticacion de dos factores deshabilitada",
     "failedEnable2FA": "Error al habilitar 2FA",
     "failedDisable2FA": "Error al deshabilitar 2FA",
-    "enterPasswordError": "Por favor ingrese su contrasena",
+    "enterPasswordError": "Por favor ingrese su contraseña",
     "setupDialogTitle": "Habilitar autenticacion de dos factores",
-    "setupDialogDescription": "Ingrese su contrasena para comenzar a configurar 2FA con una aplicacion de autenticacion.",
+    "setupDialogDescription": "Ingrese su contraseña para comenzar a configurar 2FA con una aplicación de autenticacion.",
     "continue": "Continuar",
-    "scanQRTitle": "Escanear codigo QR",
-    "scanQRDescription": "Escanee este codigo QR con su aplicacion de autenticacion (Google Authenticator, Authy, etc.)",
-    "verifyCodeTitle": "Verificar codigo",
-    "verifyCodeDescription": "Ingrese el codigo de 6 digitos de su aplicacion de autenticacion para verificar que esta configurada correctamente.",
-    "authCode": "Codigo de autenticacion",
+    "scanQRTitle": "Escanear código QR",
+    "scanQRDescription": "Escanee este código QR con su aplicación de autenticacion (Google Authenticator, Authy, etc.)",
+    "verifyCodeTitle": "Verificar código",
+    "verifyCodeDescription": "Ingrese el código de 6 dígitos de su aplicación de autenticacion para verificar que esta configurada correctamente.",
+    "authCode": "Código de autenticacion",
     "authCodePlaceholder": "000000",
-    "back": "Atras",
+    "back": "Atrás",
     "verify": "Verificar",
-    "enterCodeError": "Por favor ingrese el codigo de su aplicacion de autenticacion",
-    "invalidCode": "Codigo invalido. Intente nuevamente.",
-    "verificationFailed": "Verificacion fallida",
+    "enterCodeError": "Por favor ingrese el código de su aplicación de autenticacion",
+    "invalidCode": "Código invalido. Intente nuevamente.",
+    "verificationFailed": "Verificación fallida",
     "backupCodesTitle": "Guardar codigos de respaldo",
-    "backupCodesDescription": "Guarde estos codigos en un lugar seguro. Puede usarlos para iniciar sesion si pierde acceso a su aplicacion de autenticacion. Cada codigo solo puede usarse una vez.",
+    "backupCodesDescription": "Guarde estos codigos en un lugar seguro. Puede usarlos para iniciar sesión si pierde acceso a su aplicación de autenticacion. Cada código solo puede usarse una vez.",
     "copyCodes": "Copiar codigos",
     "copied": "Copiado",
     "backupCodesCopied": "Codigos de respaldo copiados al portapapeles",
@@ -229,28 +229,28 @@
     "twoFactorEnabledSuccess": "Autenticacion de dos factores habilitada",
     "dangerZone": "Zona de peligro",
     "deleteContentTitle": "Eliminar contenido",
-    "deleteContentDescription": "Elimine selectivamente datos de la organizacion como vehiculos, clientes, cotizaciones o inventario. Su cuenta y configuracion permaneceran intactas.",
+    "deleteContentDescription": "Elimine selectivamente datos de la organización como vehículos, clientes, cotizaciones o inventario. Su cuenta y configuración permaneceran intactas.",
     "deleteContentButton": "Eliminar contenido",
     "deleteAccountTitle": "Eliminar cuenta",
-    "deleteAccountDescription": "Elimine permanentemente su cuenta y todos los datos asociados incluyendo vehiculos, registros de servicio, ordenes de trabajo, facturas, clientes, archivos y pagos. Esta accion no se puede deshacer.",
+    "deleteAccountDescription": "Elimine permanentemente su cuenta y todos los datos asociados incluyendo vehículos, registros de servicio, órdenes de trabajo, facturas, clientes, archivos y pagos. Esta acción no se puede deshacer.",
     "deleteAccountButton": "Eliminar cuenta",
     "deleteAccountDialogTitle": "Eliminar cuenta",
-    "deleteAccountDialogDescription": "Esto eliminara permanentemente su cuenta y todos los datos asociados. Esta accion es irreversible. Todos sus vehiculos, registros de servicio, ordenes de trabajo, cotizaciones, clientes, archivos e historial de pagos seran eliminados permanentemente.",
+    "deleteAccountDialogDescription": "Esto eliminará permanentemente su cuenta y todos los datos asociados. Esta acción es irreversible. Todos sus vehículos, registros de servicio, órdenes de trabajo, cotizaciones, clientes, archivos e historial de pagos seran eliminados permanentemente.",
     "deleteAccountConfirmPhrase": "delete me",
     "deleteAccountConfirmPrompt": "Escriba <bold>delete me</bold> para confirmar",
     "permanentlyDelete": "Eliminar permanentemente",
     "deleting": "Eliminando...",
     "failedDeleteAccount": "Error al eliminar la cuenta",
     "deleteContentDialogTitle": "Eliminar contenido",
-    "deleteContentDialogDescription": "Seleccione el contenido que desea eliminar permanentemente. Esta accion no se puede deshacer.",
-    "contentVehicles": "Vehiculos",
-    "contentVehiclesDescription": "Todos los vehiculos y sus registros de servicio, notas, recordatorios, registros de combustible y facturas recurrentes",
+    "deleteContentDialogDescription": "Seleccione el contenido que desea eliminar permanentemente. Esta acción no se puede deshacer.",
+    "contentVehicles": "Vehículos",
+    "contentVehiclesDescription": "Todos los vehículos y sus registros de servicio, notas, recordatorios, registros de combustible y facturas recurrentes",
     "contentCustomers": "Clientes",
-    "contentCustomersDescription": "Todos los registros de clientes. Los vehiculos vinculados a clientes eliminados seran desvinculados.",
+    "contentCustomersDescription": "Todos los registros de clientes. Los vehículos vinculados a clientes eliminados seran desvinculados.",
     "contentQuotes": "Cotizaciones",
     "contentQuotesDescription": "Todas las cotizaciones y sus partidas",
     "contentInventory": "Inventario",
-    "contentInventoryDescription": "Todas las piezas de inventario y sus imagenes",
+    "contentInventoryDescription": "Todas las piezas de inventario y sus imágenes",
     "contentInspections": "Inspecciones",
     "contentInspectionsDescription": "Todas las inspecciones de vehículos y sus resultados",
     "contentTechnicians": "Técnicos",
@@ -306,43 +306,43 @@
   "team": {
     "title": "Equipo",
     "noOrgDescription": "Cree un equipo para compartir datos con otros usuarios.",
-    "orgDescription": "Administre los miembros de su organizacion y sus roles.",
-    "createOrg": "Crear organizacion",
-    "createOrgDescription": "Cree una organizacion para invitar miembros del equipo. Usted sera el propietario.",
-    "orgName": "Nombre de la organizacion",
+    "orgDescription": "Administre los miembros de su organización y sus roles.",
+    "createOrg": "Crear organización",
+    "createOrgDescription": "Cree una organización para invitar miembros del equipo. Usted sera el propietario.",
+    "orgName": "Nombre de la organización",
     "orgNamePlaceholder": "Mi taller",
     "create": "Crear",
-    "orgCreated": "Organizacion creada",
-    "failedCreateOrg": "Error al crear la organizacion",
+    "orgCreated": "Organización creada",
+    "failedCreateOrg": "Error al crear la organización",
     "memberCount": "{count} miembro",
     "memberCountPlural": "{count} miembros",
     "admin": "Administrador",
     "member": "Miembro",
-    "inviteByEmail": "Invitar por correo electronico",
+    "inviteByEmail": "Invitar por correo electrónico",
     "inviteEmailPlaceholder": "usuario@ejemplo.com",
     "invite": "Invitar",
     "invited": "Miembro invitado exitosamente.",
     "userNotFoundTitle": "Usuario no encontrado",
-    "userNotFoundDescription": "No se encontro cuenta para \"{email}\". Enviar un correo de invitacion para registrarse y unirse a su equipo?",
-    "sendInvitation": "Enviar invitacion",
-    "invitationSentTitle": "Invitacion enviada",
-    "invitationSentDescription": "Se ha enviado un correo de invitacion a {email}.",
+    "userNotFoundDescription": "No se encontró cuenta para \"{email}\". Enviar un correo de invitación para registrarse y unirse a su equipo?",
+    "sendInvitation": "Enviar invitación",
+    "invitationSentTitle": "Invitación enviada",
+    "invitationSentDescription": "Se ha enviado un correo de invitación a {email}.",
     "failedInvite": "Error al invitar al miembro",
-    "failedSendInvitation": "Error al enviar la invitacion",
+    "failedSendInvitation": "Error al enviar la invitación",
     "pendingInvitations": "Invitaciones pendientes",
     "invitedAs": "Invitado como {role}",
     "expires": "Expira {date}",
     "pending": "Pendiente",
-    "copyInviteLink": "Copiar enlace de invitacion",
-    "inviteLinkCopied": "Enlace de invitacion copiado al portapapeles",
-    "cancelInvitation": "Cancelar invitacion",
-    "cancelInvitationDescription": "Cancelar la invitacion a {email}? Ya no podran usar este enlace para unirse.",
-    "invitationCancelled": "Invitacion cancelada",
-    "failedCancelInvitation": "Error al cancelar la invitacion",
+    "copyInviteLink": "Copiar enlace de invitación",
+    "inviteLinkCopied": "Enlace de invitación copiado al portapapeles",
+    "cancelInvitation": "Cancelar invitación",
+    "cancelInvitationDescription": "Cancelar la invitación a {email}? Ya no podran usar este enlace para unirse.",
+    "invitationCancelled": "Invitación cancelada",
+    "failedCancelInvitation": "Error al cancelar la invitación",
     "customRoles": "Roles personalizados",
     "newRole": "Nuevo rol",
     "roleName": "Nombre del rol",
-    "roleNamePlaceholder": "Ej. Tecnico",
+    "roleNamePlaceholder": "Ej. Técnico",
     "fullAdminAccess": "Acceso completo de administrador (omite todas las verificaciones de permisos)",
     "permissions": "Permisos",
     "createRole": "Crear rol",
@@ -351,20 +351,20 @@
     "roleUpdated": "Rol actualizado",
     "failedSaveRole": "Error al guardar el rol",
     "deleteRole": "Eliminar rol",
-    "deleteRoleDescription": "Eliminar el rol \"{name}\"? Los miembros con este rol perderan sus permisos personalizados.",
+    "deleteRoleDescription": "Eliminar el rol \"{name}\"? Los miembros con este rol perderán sus permisos personalizados.",
     "roleDeleted": "Rol eliminado",
     "failedDeleteRole": "Error al eliminar el rol",
     "fullAccess": "Acceso completo",
     "permissionCount": "{count} permiso",
     "permissionCountPlural": "{count} permisos",
-    "noCustomRoles": "Aun no hay roles personalizados. Cree uno para definir permisos granulares para los miembros del equipo.",
+    "noCustomRoles": "Aún no hay roles personalizados. Cree uno para definir permisos granulares para los miembros del equipo.",
     "presetAll": "Todos",
     "presetViewOnly": "Solo lectura",
     "presetWriteAll": "Lectura y escritura",
     "presetNone": "Ninguno",
     "builtInRoles": "Roles integrados",
     "ownerLabel": "Propietario",
-    "ownerDescription": "Acceso completo. Puede gestionar miembros, cambiar roles y eliminar la organizacion.",
+    "ownerDescription": "Acceso completo. Puede gestionar miembros, cambiar roles y eliminar la organización.",
     "adminLabel": "Administrador",
     "adminDescription": "Puede invitar/eliminar miembros y gestionar datos compartidos.",
     "memberLabel": "Miembro",
@@ -383,26 +383,26 @@
     "editRole": "Edit role"
   },
   "invoice": {
-    "title": "Diseno de factura",
+    "title": "Diseño de factura",
     "description": "Configure lo que aparece en las facturas PDF generadas.",
     "tabs": {
       "general": "General",
       "layout": "Diseño",
       "customFields": "Campos personalizados"
     },
-    "invoiceNumberFormat": "Formato de numero de factura",
+    "invoiceNumberFormat": "Formato de número de factura",
     "invoiceNumberFormatHint": "Use <code>{year}</code> para el ano actual. Vista previa: <bold>{preview}</bold>",
-    "quoteNumberFormat": "Formato de numero de presupuesto",
+    "quoteNumberFormat": "Formato de número de presupuesto",
     "quoteNumberFormatHint": "Use <code>{year}</code> para el ano actual. Vista previa: <bold>{preview}</bold>",
     "quoteValidDays": "Validez del presupuesto (días)",
     "quoteValidDaysHint": "Los nuevos presupuestos reciben una fecha de validez con esta cantidad de días. 0 lo desactiva.",
     "sectionInvoices": "Facturas",
     "sectionQuotes": "Presupuestos",
-    "nextInvoiceNumber": "Siguiente numero de factura",
+    "nextInvoiceNumber": "Siguiente número de factura",
     "nextInvoiceNumberPlaceholder": "Ej. 94",
-    "nextInvoiceNumberHint": "La siguiente factura usara este numero (ej. {example})",
-    "dueDays": "Dias de vencimiento",
-    "dueDaysHint": "Numero de dias hasta el vencimiento de la factura",
+    "nextInvoiceNumberHint": "La siguiente factura usara este número (ej. {example})",
+    "dueDays": "Días de vencimiento",
+    "dueDaysHint": "Número de días hasta el vencimiento de la factura",
     "visibilityTitle": "Visibilidad en la factura",
     "companyLogo": "Logo de la empresa",
     "companyLogoHint": "Mostrar logo de la empresa en el encabezado de la factura",
@@ -410,9 +410,9 @@
     "companyNameHint": "Mostrar texto del nombre de la empresa en el encabezado",
     "bankAccount": "Cuenta bancaria",
     "bankAccountHint": "Mostrar cuenta bancaria / IBAN en la factura",
-    "organizationNumber": "Numero de organizacion",
-    "organizationNumberHint": "Mostrar numero de organizacion en el encabezado",
-    "customFooter": "Pie de pagina personalizado",
+    "organizationNumber": "Número de organización",
+    "organizationNumberHint": "Mostrar número de organización en el encabezado",
+    "customFooter": "Pie de página personalizado",
     "footerPlaceholder": "Gracias por su preferencia!",
     "footerHint": "Este texto aparece al final de cada factura",
     "partsMarkupTitle": "Margen de Repuestos",
@@ -421,8 +421,8 @@
     "defaultMarkupPercentHint": "Los repuestos nuevos agregados manualmente se prellenan con este margen. Déjelo en 0 para ingresar precios manualmente.",
     "markupAppliesToInventory": "Aplicar margen a repuestos de inventario",
     "markupAppliesToInventoryHint": "Cuando está habilitado, los repuestos seleccionados del inventario también usan costo + margen predeterminado (anula el precio de venta del inventario).",
-    "saveInvoice": "Guardar configuracion de factura",
-    "saved": "Configuracion de factura guardada",
+    "saveInvoice": "Guardar configuración de factura",
+    "saved": "Configuración de factura guardada",
     "layoutDescription": "Personaliza el orden y la visibilidad de las secciones en tus facturas y presupuestos.",
     "layoutSaved": "Diseño guardado correctamente",
     "preview": "Vista previa",
@@ -492,19 +492,19 @@
   "templates": {
     "title": "Plantillas",
     "invoiceDescription": "Personalice la apariencia de sus facturas y cotizaciones PDF.",
-    "inspectionsDescription": "Administre listas de verificacion de inspecciones y plantillas multipunto.",
+    "inspectionsDescription": "Administre listas de verificación de inspecciones y plantillas multipunto.",
     "smsDescription": "Personalice los mensajes SMS enviados a los clientes.",
     "tabs": {
       "invoice": "Factura",
-      "quotation": "Cotizacion",
+      "quotation": "Cotización",
       "inspections": "Inspecciones",
       "sms": "SMS",
-      "layout": "Disposicion"
+      "layout": "Disposición"
     },
     "presets": "Presets de plantilla",
     "primaryColor": "Color primario",
-    "fontAndLayout": "Fuente y diseno",
-    "fontFamily": "Familia tipografica",
+    "fontAndLayout": "Fuente y diseño",
+    "fontFamily": "Familia tipográfica",
     "helveticaDefault": "Helvetica (Predeterminado)",
     "timesRoman": "Times Roman",
     "courier": "Courier",
@@ -516,7 +516,7 @@
     "preview": "Vista previa de {name}",
     "billTo": "Facturar a",
     "preparedFor": "Preparado para",
-    "vehicle": "Vehiculo",
+    "vehicle": "Vehículo",
     "part": "Pieza",
     "qty": "Cant.",
     "price": "Precio",
@@ -533,31 +533,31 @@
     "previewAdditionalInfo": "Información adicional",
     "previewThankYou": "Gracias por su confianza",
     "saveInvoiceTemplate": "Guardar plantilla de factura",
-    "saveQuotationTemplate": "Guardar plantilla de cotizacion",
-    "invoiceTemplateSaved": "Configuracion de plantilla de factura guardada",
-    "quotationTemplateSaved": "Configuracion de plantilla de cotizacion guardada",
-    "failedSave": "Error al guardar la configuracion",
+    "saveQuotationTemplate": "Guardar plantilla de cotización",
+    "invoiceTemplateSaved": "Configuración de plantilla de factura guardada",
+    "quotationTemplateSaved": "Configuración de plantilla de cotización guardada",
+    "failedSave": "Error al guardar la configuración",
     "smsTemplates": "Plantillas de mensajes SMS",
-    "smsTemplatesDescription": "Personalice los mensajes de texto enviados a los clientes. Use variables como <code>'{companyName}'</code> para insertar valores dinamicos.",
+    "smsTemplatesDescription": "Personalice los mensajes de texto enviados a los clientes. Use variables como <code>'{companyName}'</code> para insertar valores dinámicos.",
     "reset": "Restablecer",
     "invoiceReady": "Factura lista",
-    "invoiceReadyDescription": "Se envia al compartir una factura con un cliente.",
-    "quoteReady": "Cotizacion lista",
-    "quoteReadyDescription": "Se envia al compartir una cotizacion con un cliente.",
-    "inspectionReady": "Inspeccion lista",
-    "inspectionReadyDescription": "Se envia al compartir un informe de inspeccion con un cliente.",
+    "invoiceReadyDescription": "Se envía al compartir una factura con un cliente.",
+    "quoteReady": "Cotización lista",
+    "quoteReadyDescription": "Se envía al compartir una cotización con un cliente.",
+    "inspectionReady": "Inspección lista",
+    "inspectionReadyDescription": "Se envía al compartir un informe de inspección con un cliente.",
     "statusInProgress": "Estado: En progreso",
-    "statusInProgressDescription": "Se envia cuando el estado de una orden de trabajo cambia a En progreso.",
+    "statusInProgressDescription": "Se envía cuando el estado de una orden de trabajo cambia a En progreso.",
     "statusWaitingParts": "Estado: Esperando piezas",
-    "statusWaitingPartsDescription": "Se envia cuando el estado cambia a Esperando piezas.",
+    "statusWaitingPartsDescription": "Se envía cuando el estado cambia a Esperando piezas.",
     "statusReady": "Estado: Listo para recoger",
-    "statusReadyDescription": "Se envia cuando el estado cambia a Listo.",
+    "statusReadyDescription": "Se envía cuando el estado cambia a Listo.",
     "statusCompleted": "Estado: Completado",
-    "statusCompletedDescription": "Se envia cuando el estado cambia a Completado.",
+    "statusCompletedDescription": "Se envía cuando el estado cambia a Completado.",
     "paymentReceived": "Pago recibido",
-    "paymentReceivedDescription": "Se envia cuando se registra un pago para una factura.",
+    "paymentReceivedDescription": "Se envía cuando se registra un pago para una factura.",
     "saveSmsTemplates": "Guardar plantillas SMS",
-    "smsTemplateSaved": "Configuracion de plantillas SMS guardada",
+    "smsTemplateSaved": "Configuración de plantillas SMS guardada",
     "smsDefaults": {
       "invoiceReady": "Su factura está lista. Véala aquí: {share_link}",
       "quoteReady": "Su presupuesto está listo para revisión. Véalo aquí: {share_link}",
@@ -569,18 +569,18 @@
       "paymentReceived": "Pago de {amount} recibido para la factura {invoice_number}. ¡Gracias!"
     },
     "colorPresets": {
-      "amber": "Ambar",
+      "amber": "Ámbar",
       "blue": "Azul",
       "emerald": "Esmeralda",
       "red": "Rojo",
-      "purple": "Purpura",
+      "purple": "Púrpura",
       "slate": "Pizarra",
       "rose": "Rosa",
-      "indigo": "Indigo"
+      "indigo": "Índigo"
     },
-    "layoutTitle": "Disposicion de factura",
+    "layoutTitle": "Disposición de factura",
     "layoutDescription": "Personaliza el orden y la visibilidad de las secciones en tus facturas y presupuestos.",
-    "layoutSaved": "Disposicion guardada correctamente",
+    "layoutSaved": "Disposición guardada correctamente",
     "layoutDocInvoice": "Factura",
     "layoutDocQuote": "Presupuesto"
   },
@@ -590,12 +590,12 @@
     "detailsDescription": "Cuenta bancaria y condiciones de pago en las facturas.",
     "bankAccount": "Cuenta bancaria (IBAN)",
     "bankAccountPlaceholder": "NO93 8601 1117 947",
-    "bankAccountHint": "Su numero de cuenta bancaria o IBAN para recibir pagos",
+    "bankAccountHint": "Su número de cuenta bancaria o IBAN para recibir pagos",
     "paymentTerms": "Condiciones de pago",
-    "paymentTermsPlaceholder": "Neto 14 dias",
-    "paymentTermsHint": "Texto de condiciones de pago en las facturas (ej. \"Neto 14 dias\", \"Pago al recibir\")",
-    "onlinePayments": "Pagos en linea",
-    "onlinePaymentsDescription": "Permita a los clientes pagar facturas en linea a traves de enlaces de factura compartidos.",
+    "paymentTermsPlaceholder": "Neto 14 días",
+    "paymentTermsHint": "Texto de condiciones de pago en las facturas (ej. \"Neto 14 días\", \"Pago al recibir\")",
+    "onlinePayments": "Pagos en línea",
+    "onlinePaymentsDescription": "Permita a los clientes pagar facturas en línea a través de enlaces de factura compartidos.",
     "stripe": "Stripe",
     "stripeDescription": "Aceptar pagos con tarjeta de credito/debito",
     "secretKey": "Clave secreta",
@@ -607,26 +607,26 @@
     "vippsDescription": "Aceptar pagos moviles Vipps (Noruega)",
     "clientId": "ID de cliente",
     "clientSecret": "Secreto del cliente",
-    "subscriptionKey": "Clave de suscripcion",
-    "merchantSerialNumber": "Numero de serie del comerciante",
+    "subscriptionKey": "Clave de suscripción",
+    "merchantSerialNumber": "Número de serie del comerciante",
     "testMode": "Modo de prueba",
     "callbackUrl": "URL de callback",
-    "termsOfSale": "Condiciones de venta (Salgsvilkar)",
-    "termsOfSaleDescription": "Requerido por Vipps. Los clientes pueden verlas desde la pagina de factura.",
+    "termsOfSale": "Condiciones de venta (Salgsvilkår)",
+    "termsOfSaleDescription": "Requerido por Vipps. Los clientes pueden verlas desde la página de factura.",
     "externalTermsUrl": "URL de condiciones externas (opcional)",
-    "externalTermsUrlHint": "Enlace a una pagina externa con sus condiciones. Si se establece, la factura enlazara aqui.",
+    "externalTermsUrlHint": "Enlace a una página externa con sus condiciones. Si se establece, la factura enlazara aquí.",
     "publicTermsUrl": "URL publica de condiciones",
     "publicTermsUrlHint": "Comparta esta URL con Vipps o enlacela desde su sitio web.",
     "paypal": "PayPal",
     "paypalDescription": "Aceptar pagos PayPal",
     "sandboxMode": "Modo sandbox",
     "paypalWebhookHint": "Agregue esta URL en su Panel de Desarrollador de PayPal en Webhooks. Suscribase a <code>PAYMENT.CAPTURE.COMPLETED</code>.",
-    "savePayment": "Guardar configuracion de pago",
-    "saved": "Configuracion de pago guardada"
+    "savePayment": "Guardar configuración de pago",
+    "saved": "Configuración de pago guardada"
   },
   "tax": {
     "title": "Impuesto",
-    "description": "Configure la tasa de impuesto aplicada a facturas, presupuestos y ordenes de trabajo.",
+    "description": "Configure la tasa de impuesto aplicada a facturas, presupuestos y órdenes de trabajo.",
     "modeLabel": "Modo de impuesto",
     "modeHint": "Elija si los precios de las lineas se introducen con impuesto incluido (inclusivo) o antes de impuestos (exclusivo). Los registros existentes mantienen el modo con el que fueron creados.",
     "modeExclusive": "Exclusivo",
@@ -665,18 +665,18 @@
     "enableTax": "Habilitar impuestos",
     "enableTaxHint": "Mostrar calculo de impuestos en facturas y registros de servicio",
     "defaultTaxRate": "Tasa de impuesto predeterminada (%)",
-    "defaultTaxRateHint": "Se completa automaticamente al crear nuevos registros de servicio",
+    "defaultTaxRateHint": "Se completa automáticamente al crear nuevos registros de servicio",
     "applyTaxToExistingLabel": "Aplicar impuesto a registros existentes",
-    "applyTaxToExistingHint": "Aplica la tasa de impuesto predeterminada a ordenes de trabajo y presupuestos existentes que no tienen tasa configurada. Elegibles: {serviceRecords} ordenes de trabajo, {quotes} presupuestos.",
+    "applyTaxToExistingHint": "Aplica la tasa de impuesto predeterminada a órdenes de trabajo y presupuestos existentes que no tienen tasa configurada. Elegibles: {serviceRecords} órdenes de trabajo, {quotes} presupuestos.",
     "applyTaxToExistingButton": "Aplicar impuesto a registros existentes",
     "applyTaxConfirmTitle": "¿Aplicar impuesto a registros existentes?",
-    "applyTaxConfirmDescription": "Esto establecera la tasa de impuesto en {rate}% en {serviceRecords} ordenes de trabajo y {quotes} presupuestos que actualmente no tienen tasa, y recalculara sus totales. Los registros con una tasa personalizada no se modificaran. Esta accion no se puede deshacer.",
+    "applyTaxConfirmDescription": "Esto establecerá la tasa de impuesto en {rate}% en {serviceRecords} órdenes de trabajo y {quotes} presupuestos que actualmente no tienen tasa, y recalculara sus totales. Los registros con una tasa personalizada no se modificaran. Esta acción no se puede deshacer.",
     "applyTaxConfirmLabel": "Aplicar impuesto",
-    "applyTaxSuccess": "Se actualizaron {serviceRecords} ordenes de trabajo y {quotes} presupuestos.",
+    "applyTaxSuccess": "Se actualizaron {serviceRecords} órdenes de trabajo y {quotes} presupuestos.",
     "applyTaxFailed": "No se pudo aplicar el impuesto a los registros existentes",
-    "applyTaxNoRecords": "Ningun registro necesita la tasa de impuesto predeterminada.",
-    "saveSettings": "Guardar configuracion",
-    "saved": "Configuracion guardada",
+    "applyTaxNoRecords": "Ningún registro necesita la tasa de impuesto predeterminada.",
+    "saveSettings": "Guardar configuración",
+    "saved": "Configuración guardada",
     "currencies": {
       "USD": "Dolar estadounidense",
       "EUR": "Euro",
@@ -736,9 +736,9 @@
     },
     "formatTitle": "Formato de moneda",
     "formatSymbolName": "Simbolo",
-    "formatCodeName": "Codigo",
+    "formatCodeName": "Código",
     "formatSymbolLabel": "Simbolo: {value}",
-    "formatCodeLabel": "Codigo: {value}"
+    "formatCodeLabel": "Código: {value}"
   },
   "localization": {
     "languageTitle": "Idioma",
@@ -767,7 +767,7 @@
     "label": "Etiqueta",
     "labelPlaceholder": "ej. Vencimiento de garantía",
     "fieldName": "Nombre del campo (ID)",
-    "fieldNamePlaceholder": "vencimiento_garantia",
+    "fieldNamePlaceholder": "vencimiento_garantía",
     "fieldNameHint": "Solo letras minúsculas, números y guiones bajos.",
     "fieldType": "Tipo de campo",
     "entityType": "Tipo de entidad",
@@ -798,7 +798,7 @@
   "workshop": {
     "title": "Valores predeterminados del taller",
     "description": "Valores predeterminados al crear nuevos registros de servicio.",
-    "defaultTechnician": "Nombre del tecnico predeterminado",
+    "defaultTechnician": "Nombre del técnico predeterminado",
     "technicianPlaceholder": "Buscar técnico...",
     "failedCreateTech": "Error al crear técnico",
     "creating": "Creando...",
@@ -819,8 +819,8 @@
     "liters": "litros (L)",
     "miles": "millas (mi)",
     "gallons": "galones (gal)",
-    "saveWorkshop": "Guardar configuracion del taller",
-    "saved": "Configuracion del taller guardada",
+    "saveWorkshop": "Guardar configuración del taller",
+    "saved": "Configuración del taller guardada",
     "assignDialogTitle": "¿Asignar a órdenes de trabajo existentes?",
     "assignDialogDescription": "¿Desea asignar {name} a todas las órdenes de trabajo que no tienen un técnico asignado?",
     "assignDialogConfirm": "Sí, asignar",
@@ -835,60 +835,70 @@
       "0": "Domingo",
       "1": "Lunes",
       "2": "Martes",
-      "3": "Miercoles",
+      "3": "Miércoles",
       "4": "Jueves",
       "5": "Viernes",
-      "6": "Sabado"
+      "6": "Sábado"
     }
   },
   "maintenance": {
     "title": "Mantenimiento predictivo",
-    "description": "Prediga el kilometraje actual de cada vehiculo a partir de su historial de servicio y muestre los vehiculos que necesitan o se acercan a su proximo servicio.",
+    "description": "Prediga el kilometraje actual de cada vehículo a partir de su historial de servicio y muestre los vehículos que necesitan o se acercan a su próximo servicio.",
     "enablePredicted": "Habilitar mantenimiento predictivo",
-    "enablePredictedHint": "Mostrar predicciones en detalles del vehiculo y panel",
+    "enablePredictedHint": "Mostrar predicciones en detalles del vehículo y panel",
     "serviceInterval": "Intervalo de servicio ({unit})",
     "serviceIntervalHint": "Distancia entre servicios recomendados",
     "approachingThreshold": "Umbral de proximidad ({unit})",
-    "approachingThresholdHint": "Mostrar advertencia cuando este dentro de esta distancia del proximo servicio",
-    "saveMaintenance": "Guardar configuracion de mantenimiento",
-    "saved": "Configuracion de mantenimiento guardada"
+    "approachingThresholdHint": "Mostrar advertencia cuando este dentro de esta distancia del próximo servicio",
+    "saveMaintenance": "Guardar configuración de mantenimiento",
+    "saved": "Configuración de mantenimiento guardada"
   },
   "appearance": {
     "title": "Apariencia",
     "description": "Personalice como se ve y se siente Torqvoice.",
-    "darkMode": "Modo oscuro",
-    "darkModeHint": "Cambiar entre temas claro y oscuro",
+    "themeLabel": "Tema",
+    "themeHint": "Elige la combinación de colores de la aplicación. La elección se guarda en este dispositivo.",
+    "themes": {
+      "light": "Claro",
+      "dark": "Oscuro",
+      "graphite": "Grafito",
+      "ocean": "Océano",
+      "forest": "Bosque",
+      "midnight": "Medianoche",
+      "carbon": "Carbono",
+      "system": "Sistema"
+    },
     "dateTimeTitle": "Fecha y hora",
-    "dateTimeDescription": "Configure como se muestran las fechas y horas en la aplicacion.",
+    "dateTimeDescription": "Configure como se muestran las fechas y horas en la aplicación.",
     "dateFormat": "Formato de fecha",
     "timeFormat": "Formato de hora",
     "time12h": "12 horas (2:30 PM)",
     "time24h": "24 horas (14:30)",
     "timezone": "Zona horaria",
-    "timezoneAuto": "Detectar automaticamente (navegador)",
+    "timezoneAuto": "Detectar automáticamente (navegador)",
     "searchTimezone": "Buscar zona horaria...",
     "noTimezoneFound": "No se encontró zona horaria.",
     "timezoneHint": "Con deteccion automatica, cada usuario ve las fechas en la zona horaria de su navegador.",
     "previewLabel": "Vista previa",
     "dateLabel": "Fecha",
     "dateTimeLabel": "Fecha y hora",
-    "saveSettings": "Guardar configuracion",
-    "saved": "Configuracion guardada"
+    "saveSettings": "Guardar configuración",
+    "saved": "Configuración guardada"
   },
   "data": {
-    "title": "Gestion de datos",
+    "title": "Gestión de datos",
     "description": "Exporte sus datos como respaldo o importe un archivo previamente exportado.",
     "exportTitle": "Exportar datos",
-    "exportDescription": "Descargue sus datos como archivo zip. Seleccione las categorias a incluir en el respaldo.",
+    "exportDescription": "Descargue sus datos como archivo zip. Seleccione las categorías a incluir en el respaldo.",
     "includeInBackup": "Incluir en el respaldo:",
     "selectAll": "Seleccionar todo",
     "deselectAll": "Deseleccionar todo",
-    "optSettings": "Configuracion",
-    "optSettingsDesc": "Info del taller, configuracion de facturas, proveedores de pago",
+    "optSettings": "Configuración",
+    "optSettingsDesc": "Info del taller, configuración de facturas, proveedores de pago",
     "optCustomers": "Clientes",
-    "optCustomersDesc": "Registros de clientes e informacion de contacto",
-    "optVehicles": "Vehiculos y registros de servicio",
-    "optVehiclesDesc": "Vehiculos, notas, registros de combustible, recordatorios, registros de servicio",
+    "optCustomersDesc": "Registros de clientes e información de contacto",
+    "optVehicles": "Vehículos y registros de servicio",
+    "optVehiclesDesc": "Vehículos, notas, registros de combustible, recordatorios, registros de servicio",
     "optQuotes": "Cotizaciones",
     "optQuotesDesc": "Cotizaciones con piezas y mano de obra",
     "optInventory": "Inventario",
@@ -901,12 +911,14 @@
     "optAuditLogsDesc": "Historial de actividad y cambios",
     "optSmsMessages": "Mensajes SMS",
     "optSmsMessagesDesc": "Mensajes SMS enviados y recibidos",
+    "optScheduledMessages": "Mensajes programados",
+    "optScheduledMessagesDesc": "Mensajes en cola y recurrentes pendientes de envío",
     "optNotifications": "Notificaciones",
     "optNotificationsDesc": "Notificaciones del sistema",
     "optCustomFields": "Campos personalizados",
     "optCustomFieldsDesc": "Definiciones y valores de campos personalizados",
     "optFiles": "Archivos subidos",
-    "optFilesDesc": "Imagenes, adjuntos de servicio, logo",
+    "optFilesDesc": "Imágenes, adjuntos de servicio, logo",
     "filesWarning": "Incluye archivos subidos — el respaldo puede ser mas grande",
     "downloadBackup": "Descargar respaldo",
     "exportComplete": "Exportacion completada",
@@ -914,12 +926,12 @@
     "exportFailed": "Exportacion fallida",
     "exportFailedMessage": "No se pudieron exportar sus datos. Intente nuevamente.",
     "importTitle": "Importar datos",
-    "importWarning": "La importacion <bold>reemplazara todos los datos existentes</bold> con el contenido del archivo de respaldo. Esta accion no se puede deshacer.",
+    "importWarning": "La importación <bold>reemplazara todos los datos existentes</bold> con el contenido del archivo de respaldo. Esta acción no se puede deshacer.",
     "importFileHint": "Soporta archivos de respaldo .zip (v2) y .json (v1).",
     "uploadRestore": "Subir y restaurar",
-    "importComplete": "Importacion completada",
+    "importComplete": "Importación completada",
     "importCompleteMessage": "Todos los datos han sido restaurados del archivo de respaldo.",
-    "importFailed": "Importacion fallida",
+    "importFailed": "Importación fallida",
     "importFromOther": "Importar de otros servicios",
     "importFromOtherDescription": "Migre sus datos desde otra plataforma. Seleccione un servicio para comenzar.",
     "lubelogTitle": "Importar de LubeLog",
@@ -930,11 +942,11 @@
     "lubelogStep4": "Suba el archivo zip descargado abajo",
     "lubelogAddNote": "Esto <bold>agregara datos junto a</bold> sus registros existentes — nada sera eliminado.",
     "lubelogImported": "Que se importara:",
-    "lubelogVehicles": "Vehiculos",
+    "lubelogVehicles": "Vehículos",
     "lubelogServiceRecords": "Registros de servicio con adjuntos",
     "lubelogNotes": "Notas",
     "lubelogFileHint": "Archivos hasta 200MB soportados.",
-    "lubelogImportComplete": "Importacion de LubeLog completada",
+    "lubelogImportComplete": "Importación de LubeLog completada",
     "cancel": "Cancelar",
     "import": "Importar",
     "invoiceNinjaTitle": "Importar de Invoice Ninja",
@@ -951,7 +963,7 @@
     "invoiceNinjaDocuments": "Documentos y adjuntos",
     "invoiceNinjaPayments": "Pagos",
     "invoiceNinjaFileHint": "Suba un archivo de exportacion zip de Invoice Ninja. Archivos hasta 200MB soportados.",
-    "invoiceNinjaImportComplete": "Importacion de Invoice Ninja completada",
+    "invoiceNinjaImportComplete": "Importación de Invoice Ninja completada",
     "backupStatus": {
       "title": "Protección de datos",
       "description": "Nos tomamos sus datos en serio. Todos los datos de su organización, incluidos clientes, vehículos, órdenes de trabajo, facturas y archivos subidos, se respaldan automáticamente cada hora. Las copias de seguridad se protegen con cifrado AES-256 antes de salir de nuestra infraestructura y se almacenan en una ubicación separada y segura, de modo que ningún tercero puede leerlas.",
@@ -962,22 +974,22 @@
   },
   "license": {
     "title": "Licencia marca blanca",
-    "description": "Active una licencia de marca blanca para eliminar la marca Torqvoice de las facturas y la aplicacion.",
+    "description": "Active una licencia de marca blanca para eliminar la marca Torqvoice de las facturas y la aplicación.",
     "purchaseWhiteLabel": "Comprar marca blanca",
     "status": "Estado:",
     "active": "Activa",
     "inactive": "Inactiva",
-    "lastChecked": "Ultima verificacion: {date}",
+    "lastChecked": "Última verificación: {date}",
     "enterLicenseKey": "Ingrese clave de licencia",
     "validate": "Validar",
     "validated": "Licencia validada exitosamente",
     "invalid": "Clave de licencia invalida",
     "failedValidate": "Error al validar la licencia",
-    "keyHint": "Cada clave de licencia esta vinculada a esta organizacion y no puede compartirse entre varias organizaciones."
+    "keyHint": "Cada clave de licencia esta vinculada a esta organización y no puede compartirse entre varias organizaciones."
   },
   "about": {
     "title": "Acerca de Torqvoice",
-    "description": "Torqvoice es su solucion completa de gestion de servicios de vehiculos. Rastree historial de servicio, reparaciones y mas.",
+    "description": "Torqvoice es su solucion completa de gestión de servicios de vehículos. Rastree historial de servicio, reparaciones y mas.",
     "version": "Version",
     "website": "Sitio web",
     "documentation": "Documentacion",
@@ -985,21 +997,21 @@
   },
   "portal": {
     "title": "Portal del cliente",
-    "description": "Permita a sus clientes iniciar sesion y ver sus vehiculos, facturas, cotizaciones e inspecciones. Los clientes tambien pueden enviar solicitudes de servicio.",
+    "description": "Permita a sus clientes iniciar sesión y ver sus vehículos, facturas, cotizaciones e inspecciones. Los clientes también pueden enviar solicitudes de servicio.",
     "enablePortal": "Habilitar portal del cliente",
-    "enablePortalHint": "Los clientes con direccion de correo electronico pueden iniciar sesion con enlace magico",
+    "enablePortalHint": "Los clientes con dirección de correo electrónico pueden iniciar sesión con enlace magico",
     "enabled": "Portal del cliente habilitado",
     "disabled": "Portal del cliente deshabilitado",
-    "failedUpdate": "Error al actualizar la configuracion",
+    "failedUpdate": "Error al actualizar la configuración",
     "customSlug": "Slug personalizado del portal",
     "save": "Guardar",
     "slugSaved": "Slug del portal guardado",
     "slugRemoved": "Slug del portal eliminado",
     "failedUpdateSlug": "Error al actualizar el slug",
-    "slugHint": "Letras minusculas, numeros, guiones y guiones bajos. 3-48 caracteres. Dejar vacio para usar la URL predeterminada.",
+    "slugHint": "Letras minúsculas, números, guiones y guiones bajos. 3-48 caracteres. Dejar vacío para usar la URL predeterminada.",
     "portalUrl": "URL del portal",
     "urlCopied": "URL del portal copiada",
-    "shareHint": "Comparta este enlace con sus clientes para que puedan iniciar sesion en su portal.",
+    "shareHint": "Comparta este enlace con sus clientes para que puedan iniciar sesión en su portal.",
     "serviceRequestAlertsHint": "Las solicitudes de servicio del portal siempre aparecen en tu campana de notificaciones. También puedes recibirlas por correo.",
     "serviceRequestAlertsLink": "Ajustes de avisos →",
     "descriptionLabel": "Sobre tu taller",
@@ -1037,28 +1049,28 @@
   },
   "email": {
     "title": "Proveedor de correo",
-    "description": "Configure el proveedor de correo electronico de su organizacion para enviar facturas y presupuestos. Si no se configura, se utilizara el proveedor de correo predeterminado de la plataforma.",
+    "description": "Configure el proveedor de correo electrónico de su organización para enviar facturas y presupuestos. Si no se configura, se utilizara el proveedor de correo predeterminado de la plataforma.",
     "useCustomLabel": "Usar proveedor de correo personalizado",
     "useCustomHint": "Active para configurar su propio proveedor de correo en lugar de usar el predeterminado de la plataforma",
-    "platformDefaultInfo": "Su organizacion utiliza el proveedor de correo predeterminado de la plataforma. Las facturas y presupuestos se enviaran con la configuracion de correo de la plataforma.",
+    "platformDefaultInfo": "Su organización utiliza el proveedor de correo predeterminado de la plataforma. Las facturas y presupuestos se enviaran con la configuración de correo de la plataforma.",
     "smtpHost": "Host SMTP",
     "smtpHostPlaceholder": "smtp.example.com",
     "smtpPort": "Puerto SMTP",
     "smtpPortPlaceholder": "587",
     "username": "Usuario",
     "usernamePlaceholder": "usuario@example.com",
-    "password": "Contrasena",
+    "password": "Contraseña",
     "fromEmail": "Correo del remitente",
     "fromEmailPlaceholder": "noreply@example.com",
     "fromEmailDomainPlaceholder": "noreply@sudominio.com",
     "fromName": "Nombre del remitente",
     "fromNamePlaceholder": "Su Taller",
-    "tlsConnection": "Conexion TLS (Puerto 465)",
-    "tlsConnectionHint": "Active para TLS implicito. Desactive para STARTTLS (puerto 587/25).",
+    "tlsConnection": "Conexión TLS (Puerto 465)",
+    "tlsConnectionHint": "Active para TLS implícito. Desactive para STARTTLS (puerto 587/25).",
     "verifyTlsCerts": "Verificar certificados TLS",
-    "verifyTlsCertsHint": "Desactive para permitir certificados autofirmados (no recomendado para produccion)",
-    "requireTlsUpgrade": "Requerir actualizacion TLS",
-    "requireTlsUpgradeHint": "Forzar actualizacion TLS en conexiones STARTTLS",
+    "verifyTlsCertsHint": "Desactive para permitir certificados autofirmados (no recomendado para producción)",
+    "requireTlsUpgrade": "Requerir actualización TLS",
+    "requireTlsUpgradeHint": "Forzar actualización TLS en conexiones STARTTLS",
     "apiKey": "Clave API",
     "apiKeyHintResend": "Obtenga su clave API en",
     "serverToken": "Token de servidor",
@@ -1066,31 +1078,31 @@
     "apiKeyHintMailgun": "Obtenga su clave API en",
     "domain": "Dominio",
     "domainPlaceholder": "mg.sudominio.com",
-    "region": "Region",
+    "region": "Región",
     "apiKeyHintSendGrid": "Obtenga su clave API en",
     "accessKeyId": "ID de clave de acceso",
     "secretAccessKey": "Clave de acceso secreta",
-    "awsRegion": "Region AWS",
+    "awsRegion": "Región AWS",
     "awsRegionPlaceholder": "us-east-1",
-    "awsRegionHint": "La region AWS donde esta configurado SES (ej. us-east-1, eu-west-1)",
+    "awsRegionHint": "La región AWS donde esta configurado SES (ej. us-east-1, eu-west-1)",
     "sendTestEmail": "Enviar correo de prueba",
-    "testEmailHint": "Guarde la configuracion primero, luego envie un correo de prueba a su cuenta",
-    "saveSettings": "Guardar configuracion",
-    "savedDefault": "Configuracion de correo guardada — usando predeterminado de la plataforma",
-    "saved": "Configuracion de correo guardada",
-    "failedSave": "Error al guardar la configuracion",
+    "testEmailHint": "Guarde la configuración primero, luego envie un correo de prueba a su cuenta",
+    "saveSettings": "Guardar configuración",
+    "savedDefault": "Configuración de correo guardada — usando predeterminado de la plataforma",
+    "saved": "Configuración de correo guardada",
+    "failedSave": "Error al guardar la configuración",
     "testSentTo": "Correo de prueba enviado a {email}",
     "testFailed": "Prueba de correo fallida"
   },
   "sms": {
     "title": "Proveedor SMS",
-    "description": "Configure su proveedor de SMS para mensajeria bidireccional con clientes. Cada organizacion usa su propio proveedor de SMS y numero de telefono.",
-    "enableLabel": "Activar mensajeria SMS",
+    "description": "Configure su proveedor de SMS para mensajería bidireccional con clientes. Cada organización usa su propio proveedor de SMS y número de teléfono.",
+    "enableLabel": "Activar mensajería SMS",
     "enableHint": "Enviar y recibir mensajes SMS con clientes",
-    "disabledInfo": "La mensajeria SMS esta desactivada. Activela para enviar y recibir mensajes de texto con sus clientes.",
-    "phoneNumber": "Numero de telefono",
+    "disabledInfo": "La mensajería SMS esta desactivada. Activela para enviar y recibir mensajes de texto con sus clientes.",
+    "phoneNumber": "Número de teléfono",
     "phoneNumberPlaceholder": "+34612345678",
-    "phoneNumberHint": "Su numero de telefono habilitado para SMS en formato E.164 (ej. +34612345678)",
+    "phoneNumberHint": "Su número de teléfono habilitado para SMS en formato E.164 (ej. +34612345678)",
     "accountSid": "SID de cuenta",
     "authToken": "Token de autenticacion",
     "apiKey": "Clave API",
@@ -1098,15 +1110,15 @@
     "webhookUrl": "URL de webhook",
     "webhookUrlHint": "Configure esta URL en su panel de {provider} para recibir mensajes SMS entrantes.",
     "webhookCopied": "URL de webhook copiada",
-    "testPhoneNumber": "Numero de telefono de prueba",
+    "testPhoneNumber": "Número de teléfono de prueba",
     "testPhonePlaceholder": "+34698765432",
     "sendTestSms": "Enviar SMS de prueba",
-    "testSmsHint": "Guarde la configuracion primero, luego ingrese un numero de destinatario para enviar un SMS de prueba",
-    "enterTestPhone": "Ingrese un numero de telefono para enviar el SMS de prueba",
-    "saveSettings": "Guardar configuracion",
-    "savedDisabled": "Configuracion SMS guardada — SMS desactivado",
-    "saved": "Configuracion SMS guardada",
-    "failedSave": "Error al guardar la configuracion",
+    "testSmsHint": "Guarde la configuración primero, luego ingrese un número de destinatario para enviar un SMS de prueba",
+    "enterTestPhone": "Ingrese un número de teléfono para enviar el SMS de prueba",
+    "saveSettings": "Guardar configuración",
+    "savedDisabled": "Configuración SMS guardada — SMS desactivado",
+    "saved": "Configuración SMS guardada",
+    "failedSave": "Error al guardar la configuración",
     "testSentTo": "SMS de prueba enviado a {phone}",
     "testFailed": "Prueba de SMS fallida",
     "copyWebhookUrl": "Copy webhook URL"
@@ -1179,24 +1191,24 @@
   },
   "ai": {
     "title": "Asistente de IA",
-    "readMore": "Read More",
-    "description": "Configure la IA para generar automaticamente notas de servicio y resumir el historial del vehiculo.",
+    "readMore": "Más información",
+    "description": "Configure la IA para generar automáticamente notas de servicio y resumir el historial del vehículo.",
     "enableLabel": "Habilitar IA",
-    "enableHint": "Usar funciones impulsadas por IA en toda la aplicacion",
-    "disabledInfo": "Habilite la IA para usar funciones como descripciones de servicio generadas automaticamente y resumenes del historial del vehiculo.",
+    "enableHint": "Usar funciones impulsadas por IA en toda la aplicación",
+    "disabledInfo": "Habilite la IA para usar funciones como descripciones de servicio generadas automáticamente y resumenes del historial del vehículo.",
     "provider": "Proveedor de IA",
     "apiKey": "Clave API",
     "apiKeyHint": "Su clave API de {provider}. Almacenada de forma segura y nunca compartida.",
     "model": "Modelo",
-    "testConnection": "Probar conexion",
-    "testSuccess": "Conexion de IA exitosa!",
-    "testFailed": "Conexion fallida. Verifique su clave API y modelo.",
-    "saved": "Configuracion de IA guardada",
-    "failedSave": "Error al guardar la configuracion de IA",
-    "saveSettings": "Guardar configuracion",
+    "testConnection": "Probar conexión",
+    "testSuccess": "Conexión de IA exitosa!",
+    "testFailed": "Conexión fallida. Verifique su clave API y modelo.",
+    "saved": "Configuración de IA guardada",
+    "failedSave": "Error al guardar la configuración de IA",
+    "saveSettings": "Guardar configuración",
     "featuresTitle": "Funciones impulsadas por IA incluidas:",
-    "featureServiceNotes": "Generar automaticamente descripciones profesionales de servicio a partir de piezas y mano de obra",
-    "featureHistorySummary": "Resumen del historial de servicio del vehiculo con un clic",
+    "featureServiceNotes": "Generar automáticamente descripciones profesionales de servicio a partir de piezas y mano de obra",
+    "featureHistorySummary": "Resumen del historial de servicio del vehículo con un clic",
     "cost": {
       "high": "Alto costo",
       "medium": "Medio",

+ 47 - 1
messages/es/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "Descargar PDF",
     "notes": "Notas",
     "quoteCancelled": "Solicitud de presupuesto cancelada",
-    "cancelFailed": "Error al cancelar la solicitud"
+    "cancelFailed": "Error al cancelar la solicitud",
+    "eu": {
+      "pass": "Sin deficiencia",
+      "attention": "Deficiencia leve",
+      "fail": "Deficiencia grave",
+      "dangerous": "Deficiencia peligrosa",
+      "not_inspected": "No inspeccionado"
+    },
+    "basic": {
+      "pass": "Apto",
+      "attention": "Atención",
+      "fail": "No apto",
+      "dangerous": "Peligroso",
+      "not_inspected": "No inspeccionado"
+    },
+    "result": {
+      "pass": "Favorable",
+      "pass_minor": "Favorable con deficiencias leves",
+      "fail": "Desfavorable — deficiencias graves",
+      "fail_dangerous": "Negativo — deficiencias peligrosas",
+      "incomplete": "Sin finalizar"
+    },
+    "resultDetail": {
+      "pass": "No se detectaron deficiencias.",
+      "pass_minor": "El vehículo es apto. Repare las deficiencias leves sin demora indebida.",
+      "fail": "El vehículo no es apto. Las deficiencias deben repararse y el vehículo volver a inspeccionarse.",
+      "fail_dangerous": "El vehículo no debe circular por la vía pública hasta que se reparen las deficiencias peligrosas.",
+      "incomplete": "Esta inspección sigue en curso."
+    },
+    "testDetails": "Datos de la inspección",
+    "testDate": "Fecha de la inspección",
+    "certificateNumber": "Número de certificado",
+    "vehicleCategory": "Categoría del vehículo",
+    "inspector": "Inspector",
+    "testLocation": "Lugar de la inspección",
+    "nextTestDue": "Próxima inspección",
+    "vesselLabel": "Embarcación",
+    "plateLabel": "Matrícula",
+    "odometerLabel": "Cuentakilómetros",
+    "engineHoursLabel": "Horas de motor",
+    "summary": "Resumen",
+    "progressLabel": "{graded} puntos evaluados",
+    "limit": "Límite",
+    "viewPhoto": "Ver foto",
+    "deficienciesFound": "Deficiencias detectadas ({count})",
+    "allResults": "Todos los resultados",
+    "privacyNotice": "Este informe se lo facilita el taller que realizó la inspección. Cualquier persona con este enlace puede consultarlo, así que le rogamos que no lo reenvíe. Contacte con el taller para retirar el enlace o solicitar la supresión de sus datos."
   },
   "terms": {
     "title": "Términos de venta (Salgsvilkår)",

+ 9 - 8
messages/es/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Informes de estado",
+    "readMore": "Más información",
     "newReport": "Nuevo informe",
     "empty": "Sin informes de estado",
     "emptyDescription": "Crea un informe de estado para actualizar a tu cliente sobre el estado del vehículo.",
@@ -76,17 +77,17 @@
     "deleteTitle": "Eliminar informe de estado",
     "deleteFailed": "No se pudo eliminar el informe de estado",
     "cancel": "Cancelar",
-  "feedback": "Comentario",
-  "hasComment": "Recibido",
-  "noFeedback": "Sin comentarios aún",
-  "sentAt": "Enviado",
-  "sentVia": "Enviado por",
-  "messageLabel": "Mensaje",
-  "videoLabel": "Video"
+    "feedback": "Comentario",
+    "hasComment": "Recibido",
+    "noFeedback": "Sin comentarios aún",
+    "sentAt": "Enviado",
+    "sentVia": "Enviado por",
+    "messageLabel": "Mensaje",
+    "videoLabel": "Video"
   },
   "notify": {
     "defaultMessage": "Hola {name}, tenemos una actualización de estado de su {vehicle}. Véala aquí: {url}",
     "emailSubject": "Actualización de estado del vehículo - {vehicle}",
-  "viewReport": "Ver el informe aquí: {url}"
+    "viewReport": "Ver el informe aquí: {url}"
   }
 }

+ 59 - 59
messages/es/vehicles.json

@@ -3,13 +3,13 @@
     "active": "Activos",
     "archived": "Archivados",
     "searchPlaceholder": "Buscar por placa, marca, modelo, VIN...",
-    "addVehicle": "Agregar vehiculo",
-    "emptySearch": "Ningun vehiculo coincide con su busqueda.",
-    "emptyArchived": "No hay vehiculos archivados.",
-    "empty": "Aun no hay vehiculos.",
+    "addVehicle": "Agregar vehículo",
+    "emptySearch": "Ningún vehículo coincide con su búsqueda.",
+    "emptyArchived": "No hay vehículos archivados.",
+    "empty": "Aún no hay vehículos.",
     "table": {
       "plate": "Placa",
-      "vehicle": "Vehiculo",
+      "vehicle": "Vehículo",
       "customer": "Cliente",
       "mileage": "Kilometraje",
       "mileageMarine": "Horas de Motor",
@@ -19,28 +19,28 @@
     "archive": "Archivar",
     "unarchive": "Desarchivar",
     "delete": "Eliminar",
-    "deleteTitle": "Eliminar vehiculo",
-    "deleteDescription": "Eliminar {name}? Esto eliminara todos los registros de servicio y notas asociados.",
-    "unarchiveTitle": "Desarchivar vehiculo",
-    "unarchiveDescription": "Restaurar {name} a la lista de vehiculos activos?",
-    "vehicleUnarchived": "Vehiculo desarchivado",
-    "unarchiveError": "Error al desarchivar vehiculo",
-    "deleteError": "Error al eliminar vehiculo",
-    "error": "Error al cargar vehiculos",
+    "deleteTitle": "Eliminar vehículo",
+    "deleteDescription": "Eliminar {name}? Esto eliminará todos los registros de servicio y notas asociados.",
+    "unarchiveTitle": "Desarchivar vehículo",
+    "unarchiveDescription": "Restaurar {name} a la lista de vehículos activos?",
+    "vehicleUnarchived": "Vehículo desarchivado",
+    "unarchiveError": "Error al desarchivar vehículo",
+    "deleteError": "Error al eliminar vehículo",
+    "error": "Error al cargar vehículos",
     "viewTable": "Table view",
     "viewGrid": "Grid view",
     "viewLargeGrid": "Large grid view",
     "openMenu": "Open menu"
   },
   "detail": {
-    "vehicleArchived": "Este vehiculo esta archivado",
-    "backToVehicles": "Volver a vehiculos",
+    "vehicleArchived": "Este vehículo esta archivado",
+    "backToVehicles": "Volver a vehículos",
     "newWorkOrder": "Nueva orden de trabajo",
-    "editVehicle": "Editar vehiculo",
+    "editVehicle": "Editar vehículo",
     "unarchive": "Desarchivar",
     "archive": "Archivar",
     "delete": "Eliminar",
-    "notFound": "Vehiculo no encontrado",
+    "notFound": "Vehículo no encontrado",
     "predictedKm": "Km predichos",
     "predictedMileage": "Kilometraje predicho",
     "predictedHours": "Horas Previstas",
@@ -48,7 +48,7 @@
     "dismissed": "Descartado",
     "undo": "Deshacer",
     "serviceOverdue": "Servicio vencido",
-    "serviceSoon": "Servicio proximo",
+    "serviceSoon": "Servicio próximo",
     "services": "servicios",
     "purchased": "Comprado el {date}",
     "tabs": {
@@ -63,12 +63,12 @@
     "noteDeleteError": "Error al eliminar",
     "reminderDeleted": "Recordatorio eliminado",
     "reminderDeleteError": "Error al eliminar",
-    "vehicleUnarchived": "Vehiculo desarchivado",
+    "vehicleUnarchived": "Vehículo desarchivado",
     "unarchiveError": "Error al desarchivar",
-    "vehicleDeleted": "Vehiculo eliminado",
-    "vehicleDeleteError": "Error al eliminar vehiculo",
-    "deleteTitle": "Eliminar vehiculo?",
-    "deleteDescription": "Esto eliminara permanentemente {name} y todos los registros de servicio, notas y recordatorios asociados. Esta accion no se puede deshacer.",
+    "vehicleDeleted": "Vehículo eliminado",
+    "vehicleDeleteError": "Error al eliminar vehículo",
+    "deleteTitle": "Eliminar vehículo?",
+    "deleteDescription": "Esto eliminará permanentemente {name} y todos los registros de servicio, notas y recordatorios asociados. Esta acción no se puede deshacer.",
     "edit": "Editar",
     "aiSummary": "Resumen IA",
     "aiSummaryTitle": "Resumen del historial de servicio",
@@ -102,8 +102,8 @@
     "columnTotal": "Total"
   },
   "inspections": {
-    "newInspection": "Nueva inspeccion",
-    "empty": "Aun no hay inspecciones",
+    "newInspection": "Nueva inspección",
+    "empty": "Aún no hay inspecciones",
     "template": "Plantilla",
     "progress": "Progreso",
     "status": "Estado",
@@ -118,23 +118,23 @@
     "addReminder": "Agregar recordatorio",
     "emptyActive": "No hay recordatorios activos",
     "emptyCompleted": "No hay recordatorios completados",
-    "empty": "Aun no hay recordatorios",
+    "empty": "Aún no hay recordatorios",
     "overdue": "Vencido",
     "dueSoon": "Vence pronto",
     "due": "Vence el {date}",
     "dueAt": "Vence a los {mileage} {unit}",
     "editTitle": "Editar recordatorio",
     "addTitle": "Agregar recordatorio",
-    "titleLabel": "Titulo *",
+    "titleLabel": "Título *",
     "titlePlaceholder": "ej. Cambio de aceite",
-    "descriptionLabel": "Descripcion",
+    "descriptionLabel": "Descripción",
     "descriptionPlaceholder": "Detalles opcionales...",
     "dueDateLabel": "Fecha de vencimiento",
     "dueMileageLabel": "Kilometraje de vencimiento",
     "dueMileagePlaceholder": "ej. 50000",
     "reminderUpdated": "Recordatorio actualizado",
     "reminderCreated": "Recordatorio creado",
-    "saveError": "Error al {action} recordatorio",
+    "saveError": "Error al guardar el recordatorio",
     "notifyLabel": "Notificarme al vencer",
     "notifyInApp": "Notificación en la app",
     "notifyEmail": "Correo electrónico"
@@ -143,22 +143,22 @@
     "searchPlaceholder": "Buscar registros...",
     "allTypes": "Todos los tipos",
     "maintenance": "Mantenimiento",
-    "repair": "Reparacion",
+    "repair": "Reparación",
     "upgrade": "Mejora",
-    "inspection": "Inspeccion",
+    "inspection": "Inspección",
     "newWorkOrder": "Nueva orden de trabajo",
     "exportServiceHistory": "Exportar Historial",
     "table": {
       "date": "Fecha",
-      "title": "Titulo",
+      "title": "Título",
       "type": "Tipo",
       "status": "Estado",
       "mileage": "Kilometraje",
       "mileageMarine": "Horas de Motor",
-      "technician": "Tecnico",
+      "technician": "Técnico",
       "files": "Archivos",
       "total": "Total",
-      "warranty": "Garantia"
+      "warranty": "Garantía"
     },
     "warranty": {
       "status": {
@@ -168,11 +168,11 @@
         "none": "N/A"
       }
     },
-    "emptyFiltered": "Ningun registro de servicio coincide con sus filtros.",
-    "empty": "Aun no hay registros de servicio.",
+    "emptyFiltered": "Ningún registro de servicio coincide con sus filtros.",
+    "empty": "Aún no hay registros de servicio.",
     "showing": "Mostrando {start}-{end} de {total}",
-    "perPage": "por pagina",
-    "page": "Pagina {page} de {totalPages}",
+    "perPage": "por página",
+    "page": "Página {page} de {totalPages}",
     "firstPage": "First page",
     "previousPage": "Previous page",
     "nextPage": "Next page",
@@ -181,27 +181,27 @@
   "notes": {
     "addNote": "Agregar nota",
     "table": {
-      "title": "Titulo",
+      "title": "Título",
       "content": "Contenido",
       "date": "Fecha"
     },
-    "empty": "Aun no hay notas.",
+    "empty": "Aún no hay notas.",
     "pin": "Fijar",
     "unpin": "Desfijar",
     "delete": "Eliminar",
     "showing": "Mostrando {start}-{end} de {total}",
-    "perPage": "por pagina",
-    "page": "Pagina {page} de {totalPages}",
+    "perPage": "por página",
+    "page": "Página {page} de {totalPages}",
     "editTitle": "Editar nota",
     "addTitle": "Agregar nota",
-    "titleLabel": "Titulo *",
-    "titlePlaceholder": "Titulo de la nota",
+    "titleLabel": "Título *",
+    "titlePlaceholder": "Título de la nota",
     "contentLabel": "Contenido *",
     "contentPlaceholder": "Escriba su nota...",
     "noteUpdated": "Nota actualizada",
     "noteCreated": "Nota creada",
-    "titleRequired": "El titulo y el contenido son obligatorios",
-    "saveError": "Error al {action} nota",
+    "titleRequired": "El título y el contenido son obligatorios",
+    "saveError": "Error al guardar la nota",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",
@@ -249,7 +249,7 @@
     "findingUpdated": "Observación actualizada",
     "findingResolved": "Observación resuelta",
     "findingDeleted": "Observación eliminada",
-    "saveError": "Error al {action} observación",
+    "saveError": "Error al guardar la observación",
     "deleteError": "Error al eliminar observación",
     "resolveError": "Error al resolver observación",
     "showing": "Mostrando {start}-{end} de {total}",
@@ -276,19 +276,19 @@
     }
   },
   "form": {
-    "editTitle": "Editar vehiculo",
-    "addTitle": "Agregar nuevo vehiculo",
+    "editTitle": "Editar vehículo",
+    "addTitle": "Agregar nuevo vehículo",
     "photo": "Foto",
     "clickToUpload": "Haga clic para subir una foto",
     "imageFormats": "JPEG, PNG, WebP hasta 5MB",
     "imageTooLarge": "Imagen demasiado grande",
-    "maxFileSize": "El tamano maximo del archivo es 5MB",
+    "maxFileSize": "El tamaño máximo del archivo es 5MB",
     "uploadingImage": "Subiendo imagen...",
     "uploadFailed": "Error al subir",
     "imageUploaded": "Imagen subida",
     "customer": "Cliente",
     "searchCustomers": "Buscar clientes...",
-    "noCustomerFound": "No se encontro ningun cliente.",
+    "noCustomerFound": "No se encontró ningún cliente.",
     "noCustomer": "Sin cliente",
     "addCustomer": "Agregar cliente",
     "make": "Marca *",
@@ -304,11 +304,11 @@
     "electric": "Electrico",
     "hybrid": "Hibrido",
     "other": "Otro",
-    "transmission": "Transmision",
+    "transmission": "Transmisión",
     "automatic": "Automatica",
     "manual": "Manual",
     "cvt": "CVT",
-    "engineSize": "Tamano del motor",
+    "engineSize": "Tamaño del motor",
     "engineCode": "Código del motor",
     "makeMarine": "Fabricante *",
     "mileageMarine": "Horas de Motor",
@@ -319,17 +319,17 @@
     "twoStroke": "Dos Tiempos",
     "vinMarine": "HIN",
     "licensePlateMarine": "Número de Registro",
-    "vehicleUpdated": "Vehiculo actualizado",
-    "vehicleAdded": "Vehiculo agregado",
-    "saveError": "Error al guardar vehiculo"
+    "vehicleUpdated": "Vehículo actualizado",
+    "vehicleAdded": "Vehículo agregado",
+    "saveError": "Error al guardar vehículo"
   },
   "archiveDialog": {
-    "title": "Archivar vehiculo",
-    "description": "Archivar <span>{name}</span>? Se ocultara de la lista principal pero todo el historial de servicio se conservara.",
+    "title": "Archivar vehículo",
+    "description": "Archivar <span>{name}</span>? Se ocultara de la lista principal pero todo el historial de servicio se conservará.",
     "reasonLabel": "Motivo (opcional)",
     "reasonPlaceholder": "ej. Vendido, siniestrado, dado de baja...",
     "archived": "{name} archivado",
-    "archiveError": "Error al archivar vehiculo"
+    "archiveError": "Error al archivar vehículo"
   },
   "serviceRecords": {
     "firstPage": "First page",

+ 11 - 1
messages/fr/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Webhook créé",
     "webhook_update": "Webhook mis à jour",
     "webhook_delete": "Webhook supprimé",
-    "webhook_rotateSecret": "Secret du webhook renouvelé"
+    "webhook_rotateSecret": "Secret du webhook renouvelé",
+    "inspection_reopen": "Inspection rouverte",
+    "inspectionTemplate_import": "Modèle d'inspection importé",
+    "scheduled_message_create": "Message planifié créé",
+    "scheduled_message_update": "Message planifié mis à jour",
+    "scheduled_message_delete": "Message planifié supprimé",
+    "scheduled_message_cancel": "Message planifié annulé",
+    "scheduled_message_send_now": "Message planifié envoyé",
+    "settings_applyTaxRate": "Taux de taxe appliqué",
+    "settings_convertToExclusive": "Prix convertis hors taxes",
+    "settings_convertToInclusive": "Prix convertis toutes taxes comprises"
   }
 }

+ 3 - 3
messages/fr/billing.json

@@ -80,8 +80,8 @@
     "processed": "{count} facture(s) traitée(s)",
     "failedProcess": "Échec du traitement",
     "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "resume": "Reprendre",
+    "delete": "Supprimer",
+    "removeRow": "Supprimer la ligne"
   }
 }

+ 16 - 3
messages/fr/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Services",
     "reminders": "Rappels",
-    "quotes": "Devis"
+    "quotes": "Devis",
+    "messages": "Messages"
   },
   "selectVehicle": "Sélectionner un véhicule pour l’ordre de travail",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} de plus",
+  "monthTotal": "{count} événements ce mois-ci",
+  "contextMenu": {
+    "newWorkOrder": "Nouvel ordre de travail",
+    "newReminder": "Nouveau rappel",
+    "newQuote": "Nouveau devis",
+    "openEvent": "Ouvrir ({count})",
+    "hint": "Astuce : faites un clic droit sur un jour pour voir les actions",
+    "scheduleMessage": "Programmer un message"
+  },
   "events": {
     "status": {
       "completed": "Terminé",
@@ -54,12 +64,15 @@
       "draft": "Brouillon",
       "done": "Fait",
       "overdue": "En retard",
-      "upcoming": "À venir"
+      "upcoming": "À venir",
+      "failed": "Échec",
+      "queued": "En file"
     },
     "type": {
       "service": "Service",
       "reminder": "Rappel",
-      "quote": "Devis"
+      "quote": "Devis",
+      "message": "Message"
     },
     "noEvents": "Aucun événement",
     "selectDay": "Sélectionnez un jour avec des événements ou créez un nouvel ordre de travail."

+ 24 - 0
messages/fr/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice a été mis à jour vers {version}",
     "whatsNew": "Voir les nouveautés",
     "dismiss": "Fermer"
+  },
+  "pagination": {
+    "showing": "{start}–{end} sur {total}",
+    "perPage": "par page",
+    "pageOf": "Page {page} sur {pages}",
+    "first": "Première page",
+    "previous": "Page précédente",
+    "next": "Page suivante",
+    "last": "Dernière page"
+  },
+  "shared": {
+    "close": "Fermer",
+    "viewPlans": "Voir les formules",
+    "manageLicense": "Gérer la licence",
+    "installOwn": "Installer la vôtre",
+    "install": "Installer",
+    "installApp": "Installer l'application",
+    "installTorqvoice": "Installer Torqvoice",
+    "dismiss": "Fermer",
+    "useCamera": "Utiliser la caméra",
+    "enterManually": "Saisir manuellement",
+    "enterBarcode": "Saisir un code-barres…",
+    "scanHint": "Pointez la caméra vers un code-barres ou saisissez-le manuellement",
+    "iosInstallHint": "Touchez Partager > Sur l'écran d'accueil"
   }
 }

+ 396 - 0
messages/fr/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Aucune défaillance",
+      "attention": "Défaillance mineure",
+      "fail": "Défaillance majeure",
+      "dangerous": "Défaillance critique",
+      "not_inspected": "Non contrôlé"
+    },
+    "basic": {
+      "pass": "Conforme",
+      "attention": "Attention",
+      "fail": "Non conforme",
+      "dangerous": "Dangereux",
+      "not_inspected": "Non contrôlé"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Mineure",
+      "fail": "Majeure",
+      "dangerous": "Critique",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Conforme aux exigences. Rien à signaler.",
+      "attention": "Sans effet notable sur la sécurité. Le véhicule est accepté ; à réparer à l'occasion.",
+      "fail": "Peut compromettre la sécurité ou affecter l'environnement. Le véhicule est refusé ; à réparer et recontrôler.",
+      "dangerous": "Danger direct et immédiat pour la sécurité routière. Le véhicule ne doit pas circuler.",
+      "not_inspected": "Ce point n'a pas été contrôlé."
+    }
+  },
+  "results": {
+    "pass": "Favorable",
+    "pass_minor": "Favorable avec défaillances mineures",
+    "fail": "Défavorable — défaillances majeures",
+    "fail_dangerous": "Défavorable — défaillances critiques",
+    "incomplete": "Non terminé",
+    "detail": {
+      "pass": "Aucune défaillance n'a été constatée.",
+      "pass_minor": "Le véhicule est accepté. Réparez les défaillances mineures sans délai excessif.",
+      "fail": "Le véhicule est refusé. Les défaillances doivent être réparées et le véhicule doit repasser au contrôle.",
+      "fail_dangerous": "Le véhicule ne doit pas circuler sur la voie publique tant que les défaillances critiques ne sont pas réparées.",
+      "incomplete": "Ce contrôle est toujours en cours."
+    }
+  },
+  "page": {
+    "back": "Inspections",
+    "statusInProgress": "En cours",
+    "statusCompleted": "Terminée",
+    "complete": "Clôturer",
+    "reopen": "Rouvrir",
+    "share": "Partager",
+    "save": "Enregistrer",
+    "saving": "Enregistrement…",
+    "savedAt": "Enregistré {time}",
+    "savesAsYouGo": "Enregistre au fil de l'eau",
+    "saveFailed": "Certaines modifications n'ont pas été enregistrées",
+    "allSaved": "Toutes les modifications sont enregistrées",
+    "moreActions": "Autres actions",
+    "downloadCertificate": "Télécharger le procès-verbal",
+    "manageTemplates": "Gérer les modèles",
+    "delete": "Supprimer",
+    "createWorkOrder": "Créer un ordre de réparation",
+    "viewWorkOrder": "Voir l'ordre de réparation",
+    "createQuote": "Créer un devis",
+    "viewQuote": "Voir le devis",
+    "needsDefect": "Disponible dès qu'une défaillance est constatée",
+    "workOrderRaised": "Ordre de réparation {number} créé depuis cette inspection le {date}",
+    "open": "Ouvrir",
+    "quoteCreated": "Devis créé par {name} le {date}",
+    "quoteRequested": "Le client a demandé un devis sur {count} point(s)",
+    "stillToGrade": "{count} points sur {total} restent à évaluer.",
+    "progress": "Avancement",
+    "checksGraded": "points évalués",
+    "progressLabel": "{graded} points sur {total} évalués : {pass} aucune défaillance, {attention} mineures, {fail} majeures, {dangerous} critiques.",
+    "sections": "Groupes",
+    "graded": "{graded}/{total} évalués",
+    "vehicle": "Véhicule",
+    "vessel": "Bateau",
+    "customer": "Client",
+    "plate": "Immatriculation",
+    "registration": "Immatriculation",
+    "template": "Modèle",
+    "scaleEu": "Évalué selon l'échelle de défaillances de l'UE issue de la directive 2014/45/UE.",
+    "scaleBasic": "Évalué conforme / attention / non conforme.",
+    "country": "Pays : {code}.",
+    "manageInspectionTemplates": "Gérer les modèles d'inspection",
+    "readMore": "En savoir plus",
+    "odometer": "Compteur",
+    "engineHours": "Heures moteur",
+    "completeTitle": "Clôturer cette inspection ?",
+    "completeBody": "Les points sont verrouillés à la clôture, et le résultat devient « {result} ».",
+    "completeBlocked": "{count} point(s) que le modèle rend obligatoires restent en attente.",
+    "completeUngraded": "{count} point(s) n'ont pas été évalués.",
+    "completeDangerous": "{count} défaillance(s) critique(s) constatée(s). Le véhicule ne doit pas circuler sur la voie publique.",
+    "reopenTitle": "Rouvrir cette inspection ?",
+    "reopenBody": "Les points redeviennent modifiables et le résultat repasse en cours. Le contrôleur, le numéro de certificat et la date du prochain contrôle sont conservés.",
+    "reopenShared": "Le lien client reste actif et montrera le résultat évoluer pendant votre travail. Un procès-verbal déjà téléchargé conserve l'ancien résultat.",
+    "deleteTitle": "Supprimer cette inspection ?",
+    "deleteBody": "Cela supprime définitivement l'inspection, ses évaluations, ses notes et ses photos. L'opération est irréversible.",
+    "cancel": "Annuler",
+    "completed": "Inspection clôturée",
+    "reopened": "Inspection rouverte",
+    "deleted": "Inspection supprimée",
+    "completeFailed": "Impossible de clôturer l'inspection",
+    "reopenFailed": "Impossible de rouvrir l'inspection",
+    "deleteFailed": "Impossible de supprimer l'inspection",
+    "quoteFailed": "Impossible de créer le devis",
+    "workOrderFailed": "Impossible de créer l'ordre de réparation"
+  },
+  "item": {
+    "required": "(obligatoire)",
+    "saving": "Enregistrement",
+    "addNote": "Ajouter une note",
+    "hideNote": "Masquer la note",
+    "addPhoto": "Ajouter une photo ou une vidéo à {name}",
+    "notesFor": "Notes pour {name}",
+    "describeDefect": "Décrivez la défaillance — elle figure sur le rapport",
+    "optionalNote": "Ajouter une note (facultatif)",
+    "notesRequired": "Décrivez la défaillance avant que cette évaluation soit enregistrée.",
+    "photoRequired": "Une photo de la défaillance est requise ici. L'inspection ne peut pas être clôturée tant qu'aucune n'est jointe.",
+    "reading": "Mesure",
+    "readingUnit": "Mesure ({unit})",
+    "limit": "Limite : {range}",
+    "recordedValue": "Valeur relevée",
+    "answer": "Réponse",
+    "selectAnswer": "Choisir une réponse",
+    "viewPhoto": "Voir la photo {index} de {name} en taille réelle",
+    "photoAlt": "{name}, photo {index}",
+    "removePhoto": "Retirer la photo {index} de {name}",
+    "clearTitle": "Effacer cette évaluation ?",
+    "clearBody": "La note enregistrée sur « {name} » sera supprimée et le point repassera à non contrôlé.",
+    "clear": "Effacer",
+    "cancel": "Annuler",
+    "saveFailed": "Impossible d'enregistrer ce point",
+    "uploadFailed": "Échec du téléversement",
+    "uploadFailedFor": "Impossible de téléverser {name}"
+  },
+  "suggestions": {
+    "title": "Défaillances courantes",
+    "add": "Ajouter « {text} » et évaluer en {grade}",
+    "more": "Plus ({count})",
+    "search": "Rechercher une formulation",
+    "empty": "Aucune formulation correspondante.",
+    "source": {
+      "workshop": "Votre atelier",
+      "history": "Déjà utilisée",
+      "regulation": "Directive 2014/45/UE",
+      "general": "Général"
+    }
+  },
+  "media": {
+    "viewer": "Image {index} sur {total} : {caption}",
+    "close": "Fermer la visionneuse",
+    "previous": "Image précédente",
+    "next": "Image suivante"
+  },
+  "certificate": {
+    "title": "Mentions du procès-verbal",
+    "description": "Requises sur un procès-verbal de contrôle technique au titre de la directive 2014/45/UE, annexe IV.",
+    "inspector": "Contrôleur",
+    "notRecorded": "Non renseigné",
+    "addTechnician": "Ajouter un technicien…",
+    "recordedAs": "Enregistré comme {name}",
+    "vehicleCategory": "Catégorie du véhicule",
+    "mileageAtTest": "{label} au moment du contrôle",
+    "reportReference": "Référence du rapport",
+    "reportReferenceHelp": "Votre propre référence pour ce rapport. Si vous êtes un centre agréé délivrant un procès-verbal officiel, indiquez ici son numéro pour que les deux concordent. Sinon, laissez vide.",
+    "optional": "Facultatif",
+    "placeOfTest": "Lieu du contrôle",
+    "placeholderAddress": "Centre de contrôle ou adresse de l'atelier",
+    "fromSettings": "D'après les paramètres de votre atelier.",
+    "change": "Modifier",
+    "differsFromWorkshop": "Diffère de l'adresse de votre atelier.",
+    "useWorkshopAddress": "Utiliser l'adresse de l'atelier",
+    "noWorkshopAddress": "Aucune adresse d'atelier n'est renseignée.",
+    "addOne": "En ajouter une",
+    "nextTestDue": "Prochain contrôle",
+    "notSet": "Non défini",
+    "intervalGroup": "Définir la date du prochain contrôle à partir de celle-ci",
+    "intervalHelp": "Compté à partir de la date de ce contrôle. Deux ans est la référence de l'Union pour les voitures et les véhicules utilitaires légers ; vérifiez la périodicité appliquée dans votre pays.",
+    "months6": "6 mois",
+    "years1": "1 an",
+    "years2": "2 ans",
+    "years3": "3 ans",
+    "years4": "4 ans",
+    "unsaved": "Modifications non enregistrées",
+    "saveDetails": "Enregistrer les mentions",
+    "saved": "Mentions enregistrées",
+    "saveFailed": "Impossible d'enregistrer les mentions",
+    "addTechnicianTitle": "Ajouter un technicien",
+    "addTechnicianBody": "La personne rejoint la liste de l'atelier et peut se voir attribuer des travaux comme des inspections.",
+    "technicianName": "Nom",
+    "technicianPlaceholder": "p. ex. Anna Berg",
+    "addAndSelect": "Ajouter et sélectionner",
+    "technicianAdded": "{name} ajouté et sélectionné",
+    "technicianFailed": "Impossible d'ajouter le technicien",
+    "cancel": "Annuler"
+  },
+  "templates": {
+    "title": "Modèles d'inspection",
+    "description": "Les listes de points que vos techniciens parcourent. Créez-en une par pays, par type de véhicule ou par prestation que vous vendez.",
+    "import": "Importer",
+    "browse": "Parcourir les listes",
+    "new": "Nouveau modèle",
+    "restoreBanner": "{count} listes toutes prêtes ont été retirées de votre liste. Vous pouvez les remettre.",
+    "restore": "Restaurer",
+    "restored": "{count} liste(s) restaurée(s)",
+    "allPresent": "Toutes les listes sont déjà présentes",
+    "restoreFailed": "Impossible d'ajouter les listes",
+    "emptyTitle": "Aucun modèle pour l'instant",
+    "emptyBody": "Les listes toutes prêtes, dont le contrôle technique périodique de l'UE, ont toutes été retirées. Remettez-les, ou construisez la vôtre de zéro.",
+    "restoreChecklists": "Restaurer les listes",
+    "buildMyOwn": "Construire la mienne",
+    "default": "Par défaut",
+    "actionsFor": "Actions pour {name}",
+    "edit": "Modifier",
+    "duplicate": "Dupliquer",
+    "export": "Exporter…",
+    "delete": "Supprimer",
+    "sections": "{count} groupe(s)",
+    "checks": "{count} point(s)",
+    "measured": "{count} mesurés",
+    "euScale": "Échelle de défaillances UE",
+    "basicScale": "Conforme / attention / non conforme",
+    "deleteTitle": "Supprimer « {name} » ?",
+    "deleteBody": "Cela supprime définitivement le modèle. Les inspections déjà réalisées avec lui conservent leur propre copie de la liste et ne sont pas affectées.",
+    "deleted": "Modèle supprimé",
+    "deleteFailed": "Impossible de supprimer le modèle",
+    "duplicated": "Modèle dupliqué",
+    "duplicateFailed": "Impossible de dupliquer le modèle",
+    "cancel": "Annuler",
+    "srSections": "Groupes",
+    "srChecks": "Points",
+    "srMeasurements": "Mesures"
+  },
+  "presets": {
+    "title": "Partir d'un modèle",
+    "description": "Chaque modèle est copié dans votre atelier comme un modèle ordinaire. Renommez les groupes, déplacez les points et modifiez toute limite pour correspondre à votre pays et à votre équipement.",
+    "search": "Rechercher par nom, pays ou norme",
+    "searchLabel": "Rechercher des modèles",
+    "inYourList": "Dans votre liste",
+    "counts": "{sections} groupes · {checks} points",
+    "noMatch": "Aucun modèle ne correspond à « {query} ».",
+    "warning": "Les modèles réglementaires portent les limites usuelles de l'UE. Vérifiez-les au regard de votre réglementation nationale avant de délivrer un procès-verbal.",
+    "cancel": "Annuler",
+    "add": "Ajouter le modèle",
+    "added": "Modèle ajouté. Adaptez-le à votre atelier.",
+    "addFailed": "Impossible d'ajouter le modèle",
+    "group": {
+      "regulatory": "Réglementaire",
+      "workshop": "Atelier",
+      "specialist": "Spécialisé"
+    },
+    "groupDescription": {
+      "regulatory": "Listes de contrôle technique périodique fondées sur la directive 2014/45/UE.",
+      "workshop": "Listes générales d'entretien et de vente, sans lien avec une réglementation.",
+      "specialist": "Listes pour des motorisations et des bateaux qui exigent leur propre procédure."
+    },
+    "euScale": "Échelle de défaillances UE",
+    "basicScale": "Conforme / attention / non conforme"
+  },
+  "builder": {
+    "newTitle": "Nouveau modèle",
+    "editTitle": "Modifier le modèle",
+    "description": "Construisez la liste que votre atelier utilise réellement. Faites glisser pour réordonner, et configurez chaque point pour enregistrer une évaluation, une mesure, une note écrite ou une réponse fixe.",
+    "name": "Nom",
+    "namePlaceholder": "p. ex. Contrôle technique périodique",
+    "templateDescription": "Description",
+    "descriptionPlaceholder": "À quoi sert cette liste et quand l'utiliser.",
+    "country": "Pays",
+    "notCountrySpecific": "Non spécifique à un pays",
+    "countryHelp": "Consigné sur le rapport pour qu'un atelier travaillant de part et d'autre d'une frontière distingue ses listes.",
+    "defectScale": "Échelle de défaillances",
+    "scaleEu": "Mineure / majeure / critique (UE)",
+    "scaleBasic": "Conforme / attention / non conforme",
+    "scaleEuHelp": "Les catégories de l'article 7, paragraphe 2, de la directive 2014/45/UE. Un véhicule ne présentant que des défaillances mineures reste accepté.",
+    "scaleBasicHelp": "Une échelle simple à trois niveaux pour les listes d'entretien qui ne sont pas un contrôle réglementaire.",
+    "defaultTemplate": "Modèle par défaut",
+    "defaultHelp": "Présélectionné quand un technicien démarre une nouvelle inspection.",
+    "summary": "{sections} groupe(s) · {checks} point(s)",
+    "renumber": "Renuméroter les références",
+    "renumberHelp": "Numérote chaque groupe et chaque point dans l'ordre : 1, 1.1, 1.2, 2. Les nouvelles lignes sont numérotées à l'ajout, vous n'en avez donc besoin qu'après avoir déplacé des éléments.",
+    "renumberWarning": "Cette liste utilise des références réglementaires comme 1.1.13. La renumérotation les remplace.",
+    "addSection": "Ajouter un groupe",
+    "addCheck": "Ajouter un point",
+    "ref": "Réf.",
+    "sectionName": "Nom du groupe, p. ex. Freinage",
+    "sectionNote": "Note facultative affichée au-dessus des points de ce groupe",
+    "checkName": "Nom du point, p. ex. Garnitures de frein",
+    "reorderSection": "Réordonner le groupe {name}",
+    "reorderCheck": "Réordonner le point {name}",
+    "removeSection": "Supprimer le groupe {name}",
+    "removeCheck": "Supprimer le point {name}",
+    "duplicateCheck": "Dupliquer le point {name}",
+    "configure": "Configurer {name}",
+    "hideSettings": "Masquer les réglages de {name}",
+    "howRecorded": "Comment est-ce enregistré ?",
+    "guidance": "Consigne pour le technicien",
+    "guidancePlaceholder": "Affichée sous le nom du point sur le formulaire d'inspection.",
+    "measurement": "Mesure",
+    "unit": "Unité",
+    "minimum": "Minimum",
+    "maximum": "Maximum",
+    "outOfRange": "Défaillance hors plage",
+    "rangeHelp": "Laissez une borne vide pour une limite unilatérale, par exemple un minimum de 1,6 mm sans maximum. Les mesures hors plage sont évaluées automatiquement.",
+    "answers": "Réponses",
+    "answersHelp": "Séparez les réponses par des virgules.",
+    "mustComplete": "Doit être renseigné",
+    "photoRequired": "Photo requise lorsqu'une défaillance est constatée",
+    "commonWording": "Formulations courantes",
+    "commonWordingHelp": "Une formulation par ligne. Elles sont proposées en premier lorsqu'un technicien constate une défaillance ici, avant les textes intégrés, pour que votre atelier s'accorde sur la description d'un défaut.",
+    "inputType": {
+      "condition": "Évaluation de défaillance",
+      "measurement": "Mesure",
+      "text": "Texte libre",
+      "choice": "Choix"
+    },
+    "inputHint": {
+      "condition": "Le technicien évalue le point selon l'échelle de défaillances.",
+      "measurement": "Enregistre un nombre assorti d'une unité, évalué automatiquement par rapport à une plage.",
+      "text": "Enregistre une observation écrite, par exemple une marque de pneumatique ou un code défaut.",
+      "choice": "Le technicien choisit une réponse parmi une liste fixe."
+    },
+    "cancel": "Annuler",
+    "create": "Créer le modèle",
+    "saveChanges": "Enregistrer les modifications",
+    "created": "Modèle créé",
+    "updated": "Modèle mis à jour",
+    "saveFailed": "Impossible d'enregistrer le modèle",
+    "severityAttention": "Défaillance mineure",
+    "severityFail": "Défaillance majeure",
+    "severityDangerous": "Défaillance critique",
+    "answersPlaceholder": "Complet, Partiel, Aucun"
+  },
+  "packages": {
+    "exportTitle": "Exporter « {name} »",
+    "exportDescription": "Télécharge toute la liste sous forme de fichier : groupes, points, unités et limites. Toute personne utilisant Torqvoice peut l'importer.",
+    "includeWording": "Inclure vos propres formulations",
+    "includeWordingHelp": "Les formulations que votre atelier a ajoutées aux points. Utiles au destinataire, mais ce sont des textes libres saisis à l'établi, qui peuvent nommer un client, un collègue ou un arrangement local. Désactivé sauf si vous les avez relus.",
+    "attributeTo": "Attribuer à (facultatif)",
+    "attributePlaceholder": "p. ex. Egeland Auto",
+    "attributeHelp": "Inscrit dans le fichier pour que la personne qui l'installe sache d'où il vient. Rien n'est repris de votre compte.",
+    "download": "Télécharger",
+    "exported": "Modèle exporté",
+    "exportFailed": "Impossible d'exporter ce modèle",
+    "importTitle": "Importer une liste",
+    "importDescription": "Ajoute une liste depuis un fichier de paquet Torqvoice. Elle arrive comme un modèle ordinaire que vous pouvez modifier, et ne remplace jamais un modèle existant.",
+    "chooseFile": "Choisir un fichier de paquet",
+    "chooseAnother": "Choisir un autre fichier",
+    "unreadable": "Ce fichier n'a pas pu être lu. Un paquet Torqvoice est un fichier .json exporté depuis un modèle.",
+    "from": "De {author}",
+    "limitsWarning": "Les limites d'une liste partagée sont celles définies par son auteur. Vérifiez-les au regard de votre réglementation nationale avant d'en délivrer quoi que ce soit.",
+    "import": "Importer",
+    "imported": "{count} modèle(s) importé(s)",
+    "importFailed": "Impossible d'importer ce paquet",
+    "cancel": "Annuler"
+  },
+  "list": {
+    "tabAll": "Toutes",
+    "tabInProgress": "En cours",
+    "tabCompleted": "Terminées",
+    "search": "Rechercher des inspections…",
+    "new": "Nouvelle inspection",
+    "empty": "Aucune inspection trouvée.",
+    "vehicle": "Véhicule",
+    "template": "Modèle",
+    "progress": "Avancement",
+    "status": "Statut",
+    "date": "Date",
+    "statusInProgress": "En cours",
+    "statusCompleted": "Terminée"
+  },
+  "new": {
+    "title": "Nouvelle inspection",
+    "vehicle": "Véhicule",
+    "searchVehicles": "Rechercher des véhicules…",
+    "loadingVehicles": "Chargement des véhicules…",
+    "noVehicles": "Aucun véhicule trouvé.",
+    "template": "Modèle",
+    "selectTemplate": "Choisir un modèle",
+    "manageTemplates": "Gérer les modèles",
+    "cancel": "Annuler",
+    "create": "Créer l'inspection",
+    "created": "Inspection créée",
+    "createFailed": "Impossible de créer l'inspection"
+  },
+  "shareDialog": {
+    "title": "Partager l'inspection",
+    "description": "Partagez une vue en lecture seule de cette inspection avec votre client.",
+    "copyLink": "Copier le lien",
+    "copied": "Lien copié dans le presse-papiers",
+    "generated": "Lien de partage créé",
+    "revoked": "Lien de partage révoqué"
+  }
+}

+ 29 - 2
messages/fr/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "Messagerie SMS",
-    "featureDescription": "Envoyez et recevez des SMS avec vos clients directement depuis Torqvoice."
+    "featureDescription": "Envoyez et recevez des SMS avec vos clients directement depuis Torqvoice.",
+    "tabs": {
+      "inbox": "Boîte de réception",
+      "scheduled": "Programmés"
+    },
+    "smsNotConfiguredTitle": "Le SMS n'est pas configuré",
+    "smsNotConfiguredHint": "Connectez un fournisseur SMS pour envoyer et recevoir des messages ici. Les e-mails programmés fonctionnent sans cela.",
+    "goToSmsSettings": "Aller aux réglages SMS"
   },
   "notConfigured": {
     "title": "SMS non configuré",
@@ -20,7 +27,10 @@
     "deleted": "Conversation supprimée",
     "deleteError": "Impossible de supprimer la conversation",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Rechercher des conversations",
+    "noSearchResults": "Aucune conversation ne correspond à la recherche",
+    "now": "maintenant"
   },
   "conversation": {
     "noPhone": "Aucun numéro de téléphone enregistré pour {name}. Ajoutez un numéro de téléphone pour commencer à envoyer des messages.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS envoyé",
     "sentTo": "{label} a été envoyé à {name} ({phone})",
     "sendError": "Impossible d'envoyer le SMS"
+  },
+  "compose": {
+    "newMessage": "Nouveau message",
+    "title": "Nouveau message",
+    "searchPlaceholder": "Rechercher un client par nom ou numéro",
+    "noMatches": "Aucun client ne correspond à la recherche",
+    "noRecipients": "Aucun client avec un numéro de téléphone",
+    "noRecipientsHint": "Ajoutez un numéro au client pour lui écrire.",
+    "changeRecipient": "Choisir quelqu'un d'autre",
+    "messageLabel": "Message",
+    "messagePlaceholder": "Message à {name}...",
+    "segments": "{chars} caractères · {segments} SMS",
+    "send": "Envoyer",
+    "scheduleInstead": "Programmer plutôt",
+    "sent": "Envoyé à {name}",
+    "sendError": "Impossible d'envoyer le message",
+    "templates": "Modèles"
   }
 }

+ 2 - 3
messages/fr/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Rechercher…",
   "shortcut": "Ctrl+K",
+  "readMore": "En savoir plus",
   "newWorkOrder": "Nouvel ordre de travail",
   "quickCreate": {
     "title": "Ajouter",
@@ -77,7 +78,6 @@
     "clients": "Clients",
     "customers": "Clients",
     "messages": "Messages",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Atelier",
     "vehicles": "Véhicules",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "ex. Garage Auto Dupont",
     "cancel": "Annuler",
     "createCompany": "Créer l'entreprise",
-    "lightMode": "Mode clair",
-    "darkMode": "Mode sombre",
+    "theme": "Thème",
     "signOut": "Se déconnecter",
     "more": "Plus",
     "auditLog": "Journal d'audit",

+ 31 - 1
messages/fr/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Notes",
     "footerText": "Inspection du véhicule — {shopName}",
     "viewPortal": "Consultez votre portail : {url}",
-    "tel": "Tél. : {phone}"
+    "tel": "Tél. : {phone}",
+    "euPass": "Aucune défaillance",
+    "euAttention": "Défaillance mineure",
+    "euFail": "Défaillance majeure",
+    "euDangerous": "Défaillance critique",
+    "basicPass": "Conforme",
+    "basicAttention": "Attention",
+    "basicFail": "Non conforme",
+    "basicDangerous": "Dangereux",
+    "resultPass": "Favorable",
+    "resultPassMinor": "Favorable avec défaillances mineures",
+    "resultFail": "Défavorable — défaillances majeures",
+    "resultFailDangerous": "Défavorable — défaillances critiques",
+    "resultIncomplete": "Non terminé",
+    "testDetails": "Détails du contrôle",
+    "testDate": "Date du contrôle",
+    "testLocation": "Lieu du contrôle",
+    "inspector": "Contrôleur",
+    "certificateNumber": "Numéro de certificat",
+    "vehicleCategory": "Catégorie du véhicule",
+    "nextTestDue": "Prochain contrôle",
+    "limit": "Limite",
+    "overallResult": "Résultat du contrôle",
+    "deficiencies": "Défaillances constatées",
+    "reading": "Mesure",
+    "noDeficiencies": "Aucune défaillance n'a été enregistrée.",
+    "resultDetailPass": "Aucune défaillance n'a été constatée.",
+    "resultDetailPassMinor": "Le véhicule est accepté. Réparez les défaillances mineures sans délai excessif.",
+    "resultDetailFail": "Le véhicule est refusé. Les défaillances doivent être réparées et le véhicule doit repasser au contrôle.",
+    "resultDetailFailDangerous": "Le véhicule ne doit pas circuler sur la voie publique tant que les défaillances critiques ne sont pas réparées.",
+    "resultDetailIncomplete": "Ce contrôle est toujours en cours."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "HISTORIQUE D'ENTRETIEN",

+ 76 - 0
messages/fr/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Programmer un message",
+    "editTitle": "Modifier le message programmé",
+    "channelLabel": "Envoyer par",
+    "channels": {
+      "email": "E-mail",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "Note dans l'app"
+    },
+    "repeatLabel": "Répéter",
+    "frequencies": {
+      "once": "Une fois",
+      "daily": "Chaque jour",
+      "weekly": "Chaque semaine",
+      "biweekly": "Toutes les 2 semaines",
+      "monthly": "Chaque mois",
+      "yearly": "Chaque année"
+    },
+    "customerLabel": "Client",
+    "selectCustomer": "Sélectionner un client",
+    "none": "Aucun",
+    "recipientEmail": "Adresse e-mail",
+    "recipientPhone": "Numéro de téléphone",
+    "recipientChat": "Identifiant de chat Telegram",
+    "recipientOverride": "Envoyer à une autre adresse",
+    "recipientHintCustomer": "Laissez vide pour utiliser les coordonnées enregistrées.",
+    "recipientHintDirect": "Choisissez un client ou saisissez la destination.",
+    "subjectLabel": "Objet",
+    "subjectPlaceholder": "ex. Votre voiture est prête",
+    "messageLabel": "Message",
+    "messagePlaceholder": "Que voulez-vous dire ?",
+    "characters": "{count} / {max} caractères",
+    "dateLabel": "Date",
+    "timeLabel": "Heure",
+    "endDateLabel": "Répéter jusqu'au",
+    "endDateHint": "Laissez vide pour répéter sans fin.",
+    "schedule": "Programmer",
+    "scheduled": "Message programmé",
+    "updated": "Message programmé mis à jour",
+    "saveError": "Impossible d'enregistrer le message"
+  },
+  "list": {
+    "scheduleMessage": "Programmer un message",
+    "scheduleForCustomer": "Programmer un message",
+    "filters": {
+      "upcoming": "À venir",
+      "sent": "Envoyés",
+      "failed": "Échecs",
+      "cancelled": "Annulés",
+      "all": "Tous"
+    },
+    "status": {
+      "scheduled": "Programmé",
+      "sent": "Envoyé",
+      "failed": "Échec",
+      "cancelled": "Annulé"
+    },
+    "empty": "Rien de programmé",
+    "emptyHint": "Faites un clic droit sur un jour du calendrier, ou utilisez Programmer un message.",
+    "noRecipient": "Aucun destinataire",
+    "sentCount": "envoyé {count}x",
+    "rowMenu": "Menu du message",
+    "sendNow": "Envoyer maintenant",
+    "cancel": "Annuler l'envoi",
+    "sentNow": "Message envoyé",
+    "sendError": "Impossible d'envoyer le message",
+    "cancelled": "Envoi annulé",
+    "cancelError": "Impossible d'annuler le message",
+    "deleted": "Message supprimé",
+    "deleteError": "Impossible de supprimer le message",
+    "deleteTitle": "Supprimer ce message ?",
+    "deleteDescription": "Le message programmé est supprimé définitivement. Ce qui a déjà été envoyé reste dans la conversation."
+  }
+}

Разница между файлами не показана из-за своего большого размера
+ 262 - 250
messages/fr/settings.json


+ 47 - 1
messages/fr/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "Télécharger le PDF",
     "notes": "Notes",
     "quoteCancelled": "Demande de devis annulée",
-    "cancelFailed": "Échec de l'annulation de la demande"
+    "cancelFailed": "Échec de l'annulation de la demande",
+    "eu": {
+      "pass": "Aucune défaillance",
+      "attention": "Défaillance mineure",
+      "fail": "Défaillance majeure",
+      "dangerous": "Défaillance critique",
+      "not_inspected": "Non contrôlé"
+    },
+    "basic": {
+      "pass": "Conforme",
+      "attention": "Attention",
+      "fail": "Non conforme",
+      "dangerous": "Dangereux",
+      "not_inspected": "Non contrôlé"
+    },
+    "result": {
+      "pass": "Favorable",
+      "pass_minor": "Favorable avec défaillances mineures",
+      "fail": "Défavorable — défaillances majeures",
+      "fail_dangerous": "Défavorable — défaillances critiques",
+      "incomplete": "Non terminé"
+    },
+    "resultDetail": {
+      "pass": "Aucune défaillance n'a été constatée.",
+      "pass_minor": "Le véhicule est accepté. Réparez les défaillances mineures sans délai excessif.",
+      "fail": "Le véhicule est refusé. Les défaillances doivent être réparées et le véhicule doit repasser au contrôle.",
+      "fail_dangerous": "Le véhicule ne doit pas circuler sur la voie publique tant que les défaillances critiques ne sont pas réparées.",
+      "incomplete": "Ce contrôle est toujours en cours."
+    },
+    "testDetails": "Détails du contrôle",
+    "testDate": "Date du contrôle",
+    "certificateNumber": "Numéro de certificat",
+    "vehicleCategory": "Catégorie du véhicule",
+    "inspector": "Contrôleur",
+    "testLocation": "Lieu du contrôle",
+    "nextTestDue": "Prochain contrôle",
+    "vesselLabel": "Bateau",
+    "plateLabel": "Immatriculation",
+    "odometerLabel": "Compteur",
+    "engineHoursLabel": "Heures moteur",
+    "summary": "Synthèse",
+    "progressLabel": "{graded} points contrôlés",
+    "limit": "Limite",
+    "viewPhoto": "Voir la photo",
+    "deficienciesFound": "Défaillances constatées ({count})",
+    "allResults": "Tous les résultats",
+    "privacyNotice": "Ce rapport vous est communiqué par l'atelier qui a réalisé le contrôle. Toute personne disposant de ce lien peut le consulter : merci de ne pas le transmettre. Contactez l'atelier pour faire retirer le lien ou effacer vos données."
   },
   "terms": {
     "title": "Conditions de vente (Salgsvilkår)",

+ 9 - 8
messages/fr/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Rapports d'état",
+    "readMore": "En savoir plus",
     "newReport": "Nouveau rapport",
     "empty": "Aucun rapport d'état",
     "emptyDescription": "Créez un rapport d'état pour informer votre client de l'état du véhicule.",
@@ -76,17 +77,17 @@
     "deleteTitle": "Supprimer le rapport d'état",
     "deleteFailed": "Échec de la suppression du rapport d'état",
     "cancel": "Annuler",
-  "feedback": "Commentaire",
-  "hasComment": "Reçu",
-  "noFeedback": "Aucun commentaire",
-  "sentAt": "Envoyé",
-  "sentVia": "Envoyé via",
-  "messageLabel": "Message",
-  "videoLabel": "Vidéo"
+    "feedback": "Commentaire",
+    "hasComment": "Reçu",
+    "noFeedback": "Aucun commentaire",
+    "sentAt": "Envoyé",
+    "sentVia": "Envoyé via",
+    "messageLabel": "Message",
+    "videoLabel": "Vidéo"
   },
   "notify": {
     "defaultMessage": "Bonjour {name}, nous avons une mise à jour de l'état de votre {vehicle}. Consultez-la ici : {url}",
     "emailSubject": "Mise à jour de l'état du véhicule - {vehicle}",
-  "viewReport": "Voir le rapport ici : {url}"
+    "viewReport": "Voir le rapport ici : {url}"
   }
 }

+ 3 - 3
messages/fr/vehicles.json

@@ -134,7 +134,7 @@
     "dueMileagePlaceholder": "ex. 50000",
     "reminderUpdated": "Rappel mis à jour",
     "reminderCreated": "Rappel créé",
-    "saveError": "Échec de {action} du rappel",
+    "saveError": "Échec de l'enregistrement du rappel",
     "notifyLabel": "Me notifier à l'échéance",
     "notifyInApp": "Notification dans l'app",
     "notifyEmail": "E-mail"
@@ -201,7 +201,7 @@
     "noteUpdated": "Note mise à jour",
     "noteCreated": "Note créée",
     "titleRequired": "Le titre et le contenu sont obligatoires",
-    "saveError": "Échec de {action} de la note",
+    "saveError": "Échec de l'enregistrement de la note",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",
@@ -249,7 +249,7 @@
     "findingUpdated": "Observation mise à jour",
     "findingResolved": "Observation résolue",
     "findingDeleted": "Observation supprimée",
-    "saveError": "Échec de l'observation",
+    "saveError": "Échec de l'enregistrement de l'observation",
     "deleteError": "Échec de suppression",
     "resolveError": "Échec de résolution",
     "showing": "Affichage de {start}-{end} sur {total}",

+ 11 - 1
messages/it/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Webhook creato",
     "webhook_update": "Webhook aggiornato",
     "webhook_delete": "Webhook eliminato",
-    "webhook_rotateSecret": "Segreto webhook ruotato"
+    "webhook_rotateSecret": "Segreto webhook ruotato",
+    "inspection_reopen": "Ispezione riaperta",
+    "inspectionTemplate_import": "Modello di ispezione importato",
+    "scheduled_message_create": "Messaggio pianificato creato",
+    "scheduled_message_update": "Messaggio pianificato aggiornato",
+    "scheduled_message_delete": "Messaggio pianificato eliminato",
+    "scheduled_message_cancel": "Messaggio pianificato annullato",
+    "scheduled_message_send_now": "Messaggio pianificato inviato",
+    "settings_applyTaxRate": "Aliquota applicata",
+    "settings_convertToExclusive": "Prezzi convertiti in imponibile",
+    "settings_convertToInclusive": "Prezzi convertiti in ivato"
   }
 }

+ 4 - 4
messages/it/billing.json

@@ -79,9 +79,9 @@
     "failedDelete": "Eliminazione fallita",
     "processed": "{count} fattura/e elaborata/e",
     "failedProcess": "Elaborazione fallita",
-    "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "pause": "Pausa",
+    "resume": "Riprendi",
+    "delete": "Elimina",
+    "removeRow": "Rimuovi riga"
   }
 }

+ 16 - 3
messages/it/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Servizi",
     "reminders": "Promemoria",
-    "quotes": "Preventivi"
+    "quotes": "Preventivi",
+    "messages": "Messaggi"
   },
   "selectVehicle": "Seleziona veicolo per ordine di lavoro",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} altri",
+  "monthTotal": "{count} eventi questo mese",
+  "contextMenu": {
+    "newWorkOrder": "Nuovo ordine di lavoro",
+    "newReminder": "Nuovo promemoria",
+    "newQuote": "Nuovo preventivo",
+    "openEvent": "Apri ({count})",
+    "hint": "Suggerimento: fai clic con il tasto destro su un giorno per le azioni",
+    "scheduleMessage": "Pianifica messaggio"
+  },
   "events": {
     "status": {
       "completed": "Completato",
@@ -54,12 +64,15 @@
       "draft": "Bozza",
       "done": "Fatto",
       "overdue": "Scaduto",
-      "upcoming": "In arrivo"
+      "upcoming": "In arrivo",
+      "failed": "Non riuscito",
+      "queued": "In coda"
     },
     "type": {
       "service": "Servizio",
       "reminder": "Promemoria",
-      "quote": "Preventivo"
+      "quote": "Preventivo",
+      "message": "Messaggio"
     },
     "noEvents": "Nessun evento",
     "selectDay": "Seleziona un giorno con eventi o crea un nuovo ordine di lavoro."

+ 24 - 0
messages/it/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice è stato aggiornato alla versione {version}",
     "whatsNew": "Scopri le novità",
     "dismiss": "Chiudi"
+  },
+  "pagination": {
+    "showing": "{start}–{end} di {total}",
+    "perPage": "per pagina",
+    "pageOf": "Pagina {page} di {pages}",
+    "first": "Prima pagina",
+    "previous": "Pagina precedente",
+    "next": "Pagina successiva",
+    "last": "Ultima pagina"
+  },
+  "shared": {
+    "close": "Chiudi",
+    "viewPlans": "Vedi i piani",
+    "manageLicense": "Gestisci licenza",
+    "installOwn": "Installa la tua",
+    "install": "Installa",
+    "installApp": "Installa l'app",
+    "installTorqvoice": "Installa Torqvoice",
+    "dismiss": "Chiudi",
+    "useCamera": "Usa la fotocamera",
+    "enterManually": "Inserisci manualmente",
+    "enterBarcode": "Inserisci codice a barre…",
+    "scanHint": "Punta la fotocamera su un codice a barre oppure inseriscilo manualmente",
+    "iosInstallHint": "Tocca Condividi > Aggiungi a Home"
   }
 }

+ 396 - 0
messages/it/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Nessuna carenza",
+      "attention": "Carenza lieve",
+      "fail": "Carenza grave",
+      "dangerous": "Carenza pericolosa",
+      "not_inspected": "Non controllato"
+    },
+    "basic": {
+      "pass": "Superato",
+      "attention": "Attenzione",
+      "fail": "Non superato",
+      "dangerous": "Pericoloso",
+      "not_inspected": "Non controllato"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Lieve",
+      "fail": "Grave",
+      "dangerous": "Pericolosa",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Conforme ai requisiti. Nulla da segnalare.",
+      "attention": "Nessun effetto rilevante sulla sicurezza. Il veicolo è idoneo; riparare quando conviene.",
+      "fail": "Può pregiudicare la sicurezza o incidere sull'ambiente. Il veicolo non è idoneo; riparare e ricontrollare.",
+      "dangerous": "Pericolo diretto e immediato per la sicurezza stradale. Il veicolo non deve circolare.",
+      "not_inspected": "Questo punto non è stato eseguito."
+    }
+  },
+  "results": {
+    "pass": "Esito favorevole",
+    "pass_minor": "Favorevole con carenze lievi",
+    "fail": "Non favorevole — carenze gravi",
+    "fail_dangerous": "Non favorevole — carenze pericolose",
+    "incomplete": "Non completato",
+    "detail": {
+      "pass": "Non sono state riscontrate carenze.",
+      "pass_minor": "Il veicolo è idoneo. Riparare le carenze lievi senza indebito ritardo.",
+      "fail": "Il veicolo non è idoneo. Le carenze devono essere riparate e il veicolo deve essere ricontrollato.",
+      "fail_dangerous": "Il veicolo non deve circolare su strada pubblica finché le carenze pericolose non sono riparate.",
+      "incomplete": "Questo controllo è ancora in corso."
+    }
+  },
+  "page": {
+    "back": "Ispezioni",
+    "statusInProgress": "In corso",
+    "statusCompleted": "Chiusa",
+    "complete": "Chiudi",
+    "reopen": "Riapri",
+    "share": "Condividi",
+    "save": "Salva",
+    "saving": "Salvataggio…",
+    "savedAt": "Salvato {time}",
+    "savesAsYouGo": "Salva mentre lavori",
+    "saveFailed": "Alcune modifiche non sono state salvate",
+    "allSaved": "Tutte le modifiche sono salvate",
+    "moreActions": "Altre azioni",
+    "downloadCertificate": "Scarica il verbale",
+    "manageTemplates": "Gestisci modelli",
+    "delete": "Elimina",
+    "createWorkOrder": "Crea commessa",
+    "viewWorkOrder": "Vedi commessa",
+    "createQuote": "Crea preventivo",
+    "viewQuote": "Vedi preventivo",
+    "needsDefect": "Disponibile quando è registrata una carenza",
+    "workOrderRaised": "Commessa {number} creata da questa ispezione il {date}",
+    "open": "Apri",
+    "quoteCreated": "Preventivo creato da {name} il {date}",
+    "quoteRequested": "Il cliente ha chiesto un preventivo su {count} punto/i",
+    "stillToGrade": "Restano {count} punti su {total} da valutare.",
+    "progress": "Avanzamento",
+    "checksGraded": "punti valutati",
+    "progressLabel": "{graded} punti su {total} valutati: {pass} nessuna carenza, {attention} lievi, {fail} gravi, {dangerous} pericolose.",
+    "sections": "Gruppi",
+    "graded": "{graded}/{total} valutati",
+    "vehicle": "Veicolo",
+    "vessel": "Imbarcazione",
+    "customer": "Cliente",
+    "plate": "Targa",
+    "registration": "Immatricolazione",
+    "template": "Modello",
+    "scaleEu": "Valutato secondo la scala delle carenze UE della direttiva 2014/45/UE.",
+    "scaleBasic": "Valutato superato / attenzione / non superato.",
+    "country": "Paese: {code}.",
+    "manageInspectionTemplates": "Gestisci i modelli di ispezione",
+    "readMore": "Scopri di più",
+    "odometer": "Contachilometri",
+    "engineHours": "Ore motore",
+    "completeTitle": "Chiudere questa ispezione?",
+    "completeBody": "I punti vengono bloccati alla chiusura e l'esito diventa «{result}».",
+    "completeBlocked": "Restano {count} punto/i che il modello indica come obbligatori.",
+    "completeUngraded": "{count} punto/i non sono stati valutati.",
+    "completeDangerous": "{count} carenza/e pericolosa/e registrata/e. Il veicolo non deve circolare su strada pubblica.",
+    "reopenTitle": "Riaprire questa ispezione?",
+    "reopenBody": "I punti tornano modificabili e l'esito torna a in corso. Ispettore, numero del verbale e data della prossima revisione vengono mantenuti.",
+    "reopenShared": "Il link del cliente resta attivo e mostrerà l'esito cambiare mentre lavori. Un verbale già scaricato mantiene l'esito precedente.",
+    "deleteTitle": "Eliminare questa ispezione?",
+    "deleteBody": "Questo elimina definitivamente l'ispezione, le valutazioni, le note e le foto. L'operazione non è reversibile.",
+    "cancel": "Annulla",
+    "completed": "Ispezione chiusa",
+    "reopened": "Ispezione riaperta",
+    "deleted": "Ispezione eliminata",
+    "completeFailed": "Impossibile chiudere l'ispezione",
+    "reopenFailed": "Impossibile riaprire l'ispezione",
+    "deleteFailed": "Impossibile eliminare l'ispezione",
+    "quoteFailed": "Impossibile creare il preventivo",
+    "workOrderFailed": "Impossibile creare la commessa"
+  },
+  "item": {
+    "required": "(obbligatorio)",
+    "saving": "Salvataggio",
+    "addNote": "Aggiungi nota",
+    "hideNote": "Nascondi nota",
+    "addPhoto": "Aggiungi foto o video a {name}",
+    "notesFor": "Note per {name}",
+    "describeDefect": "Descrivi la carenza — comparirà sul rapporto",
+    "optionalNote": "Aggiungi una nota (facoltativo)",
+    "notesRequired": "Descrivi la carenza prima che questa valutazione venga salvata.",
+    "photoRequired": "Qui è richiesta una foto della carenza. L'ispezione non può essere chiusa finché non ne viene allegata una.",
+    "reading": "Misura",
+    "readingUnit": "Misura ({unit})",
+    "limit": "Limite: {range}",
+    "recordedValue": "Valore registrato",
+    "answer": "Risposta",
+    "selectAnswer": "Scegli una risposta",
+    "viewPhoto": "Vedi la foto {index} di {name} a dimensione piena",
+    "photoAlt": "{name}, foto {index}",
+    "removePhoto": "Rimuovi la foto {index} da {name}",
+    "clearTitle": "Cancellare questa valutazione?",
+    "clearBody": "La nota registrata su «{name}» verrà rimossa e il punto tornerà a non controllato.",
+    "clear": "Cancella",
+    "cancel": "Annulla",
+    "saveFailed": "Impossibile salvare questo punto",
+    "uploadFailed": "Caricamento non riuscito",
+    "uploadFailedFor": "Impossibile caricare {name}"
+  },
+  "suggestions": {
+    "title": "Carenze frequenti",
+    "add": "Aggiungi «{text}» e valuta come {grade}",
+    "more": "Altre ({count})",
+    "search": "Cerca una formulazione",
+    "empty": "Nessuna formulazione corrispondente.",
+    "source": {
+      "workshop": "La tua officina",
+      "history": "Già usata",
+      "regulation": "Direttiva 2014/45/UE",
+      "general": "Generale"
+    }
+  },
+  "media": {
+    "viewer": "Immagine {index} di {total}: {caption}",
+    "close": "Chiudi il visualizzatore",
+    "previous": "Immagine precedente",
+    "next": "Immagine successiva"
+  },
+  "certificate": {
+    "title": "Dati del verbale",
+    "description": "Richiesti su un verbale di revisione ai sensi della direttiva 2014/45/UE, allegato IV.",
+    "inspector": "Ispettore",
+    "notRecorded": "Non registrato",
+    "addTechnician": "Aggiungi tecnico…",
+    "recordedAs": "Registrato come {name}",
+    "vehicleCategory": "Categoria del veicolo",
+    "mileageAtTest": "{label} al momento del controllo",
+    "reportReference": "Riferimento del rapporto",
+    "reportReferenceHelp": "Il tuo riferimento per questo rapporto. Se sei un centro autorizzato che emette un verbale ufficiale, inserisci qui il suo numero così i due coincidono. Altrimenti lascia vuoto.",
+    "optional": "Facoltativo",
+    "placeOfTest": "Luogo del controllo",
+    "placeholderAddress": "Centro di controllo o indirizzo dell'officina",
+    "fromSettings": "Dalle impostazioni della tua officina.",
+    "change": "Modifica",
+    "differsFromWorkshop": "Diverso dall'indirizzo della tua officina.",
+    "useWorkshopAddress": "Usa l'indirizzo dell'officina",
+    "noWorkshopAddress": "Non è impostato alcun indirizzo dell'officina.",
+    "addOne": "Aggiungine uno",
+    "nextTestDue": "Prossima revisione",
+    "notSet": "Non impostata",
+    "intervalGroup": "Imposta la data della prossima revisione a partire da questo controllo",
+    "intervalHelp": "Calcolato dalla data di questo controllo. Due anni è il riferimento dell'Unione per autovetture e veicoli commerciali leggeri; verifica la periodicità applicata nel tuo paese.",
+    "months6": "6 mesi",
+    "years1": "1 anno",
+    "years2": "2 anni",
+    "years3": "3 anni",
+    "years4": "4 anni",
+    "unsaved": "Modifiche non salvate",
+    "saveDetails": "Salva i dati",
+    "saved": "Dati salvati",
+    "saveFailed": "Impossibile salvare i dati",
+    "addTechnicianTitle": "Aggiungi tecnico",
+    "addTechnicianBody": "Entra nell'elenco dell'officina e può ricevere sia lavori sia ispezioni.",
+    "technicianName": "Nome",
+    "technicianPlaceholder": "es. Anna Berg",
+    "addAndSelect": "Aggiungi e seleziona",
+    "technicianAdded": "{name} aggiunto e selezionato",
+    "technicianFailed": "Impossibile aggiungere il tecnico",
+    "cancel": "Annulla"
+  },
+  "templates": {
+    "title": "Modelli di ispezione",
+    "description": "Le liste di controllo che i tuoi tecnici percorrono. Creane una per paese, per tipo di veicolo o per servizio che vendi.",
+    "import": "Importa",
+    "browse": "Sfoglia le liste",
+    "new": "Nuovo modello",
+    "restoreBanner": "{count} liste già pronte sono state rimosse dal tuo elenco. Puoi rimetterle.",
+    "restore": "Ripristina",
+    "restored": "{count} lista/e ripristinata/e",
+    "allPresent": "Tutte le liste sono già presenti",
+    "restoreFailed": "Impossibile aggiungere le liste",
+    "emptyTitle": "Ancora nessun modello",
+    "emptyBody": "Le liste già pronte, inclusa la revisione periodica UE, sono state tutte rimosse. Rimettile o costruisci la tua da zero.",
+    "restoreChecklists": "Ripristina le liste",
+    "buildMyOwn": "Costruisci la mia",
+    "default": "Predefinito",
+    "actionsFor": "Azioni per {name}",
+    "edit": "Modifica",
+    "duplicate": "Duplica",
+    "export": "Esporta…",
+    "delete": "Elimina",
+    "sections": "{count} gruppo/i",
+    "checks": "{count} punto/i",
+    "measured": "{count} misurati",
+    "euScale": "Scala delle carenze UE",
+    "basicScale": "Superato / attenzione / non superato",
+    "deleteTitle": "Eliminare «{name}»?",
+    "deleteBody": "Questo elimina definitivamente il modello. Le ispezioni già eseguite con esso mantengono la propria copia della lista e non ne risentono.",
+    "deleted": "Modello eliminato",
+    "deleteFailed": "Impossibile eliminare il modello",
+    "duplicated": "Modello duplicato",
+    "duplicateFailed": "Impossibile duplicare il modello",
+    "cancel": "Annulla",
+    "srSections": "Gruppi",
+    "srChecks": "Punti",
+    "srMeasurements": "Misure"
+  },
+  "presets": {
+    "title": "Partire da un modello",
+    "description": "Ogni modello viene copiato nella tua officina come modello ordinario. Rinomina i gruppi, sposta i punti e cambia qualsiasi limite per adattarlo al tuo paese e alla tua attrezzatura.",
+    "search": "Cerca per nome, paese o norma",
+    "searchLabel": "Cerca modelli",
+    "inYourList": "Nel tuo elenco",
+    "counts": "{sections} gruppi · {checks} punti",
+    "noMatch": "Nessun modello corrisponde a «{query}».",
+    "warning": "I modelli normativi riportano i limiti usuali dell'UE. Verificali rispetto alla normativa nazionale prima di emettere un verbale.",
+    "cancel": "Annulla",
+    "add": "Aggiungi modello",
+    "added": "Modello aggiunto. Adattalo alla tua officina.",
+    "addFailed": "Impossibile aggiungere il modello",
+    "group": {
+      "regulatory": "Normativo",
+      "workshop": "Officina",
+      "specialist": "Specialistico"
+    },
+    "groupDescription": {
+      "regulatory": "Liste di revisione periodica basate sulla direttiva 2014/45/UE.",
+      "workshop": "Liste generali di assistenza e vendita non legate a una normativa.",
+      "specialist": "Liste per motorizzazioni e imbarcazioni che richiedono una procedura propria."
+    },
+    "euScale": "Scala delle carenze UE",
+    "basicScale": "Superato / attenzione / non superato"
+  },
+  "builder": {
+    "newTitle": "Nuovo modello",
+    "editTitle": "Modifica modello",
+    "description": "Costruisci la lista che la tua officina usa davvero. Trascina per riordinare e configura ogni punto per registrare una valutazione, una misura, una nota scritta o una risposta fissa.",
+    "name": "Nome",
+    "namePlaceholder": "es. Revisione periodica",
+    "templateDescription": "Descrizione",
+    "descriptionPlaceholder": "A cosa serve questa lista e quando si usa.",
+    "country": "Paese",
+    "notCountrySpecific": "Non specifico per paese",
+    "countryHelp": "Registrato sul rapporto così un'officina che lavora oltre confine distingue le proprie liste.",
+    "defectScale": "Scala delle carenze",
+    "scaleEu": "Lieve / grave / pericolosa (UE)",
+    "scaleBasic": "Superato / attenzione / non superato",
+    "scaleEuHelp": "Le categorie dell'articolo 7, paragrafo 2, della direttiva 2014/45/UE. Un veicolo con sole carenze lievi resta idoneo.",
+    "scaleBasicHelp": "Una semplice scala a tre livelli per liste di assistenza che non sono un controllo obbligatorio.",
+    "defaultTemplate": "Modello predefinito",
+    "defaultHelp": "Preselezionato quando un tecnico avvia una nuova ispezione.",
+    "summary": "{sections} gruppo/i · {checks} punto/i",
+    "renumber": "Rinumera i riferimenti",
+    "renumberHelp": "Numera ogni gruppo e ogni punto in ordine: 1, 1.1, 1.2, 2. Le nuove righe vengono numerate all'aggiunta, quindi serve solo dopo aver spostato qualcosa.",
+    "renumberWarning": "Questa lista usa riferimenti normativi come 1.1.13. La rinumerazione li sostituisce.",
+    "addSection": "Aggiungi gruppo",
+    "addCheck": "Aggiungi punto",
+    "ref": "Rif.",
+    "sectionName": "Nome del gruppo, es. Impianto frenante",
+    "sectionNote": "Nota facoltativa mostrata sopra i punti di questo gruppo",
+    "checkName": "Nome del punto, es. Pastiglie freno",
+    "reorderSection": "Riordina il gruppo {name}",
+    "reorderCheck": "Riordina il punto {name}",
+    "removeSection": "Rimuovi il gruppo {name}",
+    "removeCheck": "Rimuovi il punto {name}",
+    "duplicateCheck": "Duplica il punto {name}",
+    "configure": "Configura {name}",
+    "hideSettings": "Nascondi le impostazioni di {name}",
+    "howRecorded": "Come viene registrato?",
+    "guidance": "Indicazione per il tecnico",
+    "guidancePlaceholder": "Mostrata sotto il nome del punto nel modulo di ispezione.",
+    "measurement": "Misura",
+    "unit": "Unità",
+    "minimum": "Minimo",
+    "maximum": "Massimo",
+    "outOfRange": "Carenza fuori intervallo",
+    "rangeHelp": "Lascia un estremo vuoto per un limite unilaterale, per esempio un minimo di 1,6 mm senza massimo. Le misure fuori intervallo sono valutate automaticamente.",
+    "answers": "Risposte",
+    "answersHelp": "Separa le risposte con le virgole.",
+    "mustComplete": "Deve essere compilato",
+    "photoRequired": "Foto richiesta quando viene registrata una carenza",
+    "commonWording": "Formulazioni frequenti",
+    "commonWordingHelp": "Una formulazione per riga. Sono proposte per prime quando un tecnico registra qui una carenza, prima dei testi predefiniti, così la tua officina può accordarsi su come descrivere un guasto.",
+    "inputType": {
+      "condition": "Valutazione della carenza",
+      "measurement": "Misura",
+      "text": "Testo libero",
+      "choice": "Scelta"
+    },
+    "inputHint": {
+      "condition": "Il tecnico valuta il punto secondo la scala delle carenze.",
+      "measurement": "Registra un numero con unità, valutato automaticamente rispetto a un intervallo.",
+      "text": "Registra un'osservazione scritta, per esempio una marca di pneumatico o un codice guasto.",
+      "choice": "Il tecnico sceglie una risposta da un elenco fisso."
+    },
+    "cancel": "Annulla",
+    "create": "Crea modello",
+    "saveChanges": "Salva le modifiche",
+    "created": "Modello creato",
+    "updated": "Modello aggiornato",
+    "saveFailed": "Impossibile salvare il modello",
+    "severityAttention": "Carenza lieve",
+    "severityFail": "Carenza grave",
+    "severityDangerous": "Carenza pericolosa",
+    "answersPlaceholder": "Completo, Parziale, Nessuno"
+  },
+  "packages": {
+    "exportTitle": "Esporta «{name}»",
+    "exportDescription": "Scarica l'intera lista come file: gruppi, punti, unità e limiti. Chiunque usi Torqvoice può importarla.",
+    "includeWording": "Includi le tue formulazioni",
+    "includeWordingHelp": "Le formulazioni che la tua officina ha aggiunto ai punti. Utili a chi le riceve, ma sono testo libero scritto al banco e possono nominare un cliente, un collega o un accordo locale. Disattivato a meno che tu non le abbia rilette.",
+    "attributeTo": "Attribuisci a (facoltativo)",
+    "attributePlaceholder": "es. Egeland Auto",
+    "attributeHelp": "Scritto nel file così chi lo installa vede da dove proviene. Nulla viene preso dal tuo account.",
+    "download": "Scarica",
+    "exported": "Modello esportato",
+    "exportFailed": "Impossibile esportare questo modello",
+    "importTitle": "Importa una lista",
+    "importDescription": "Aggiunge una lista da un file pacchetto Torqvoice. Arriva come modello ordinario modificabile e non sostituisce mai uno che hai già.",
+    "chooseFile": "Scegli un file pacchetto",
+    "chooseAnother": "Scegli un altro file",
+    "unreadable": "Impossibile leggere quel file. Un pacchetto Torqvoice è un file .json esportato da un modello.",
+    "from": "Da {author}",
+    "limitsWarning": "I limiti di una lista condivisa sono quelli impostati dal suo autore. Verificali rispetto alla normativa nazionale prima di emettere qualsiasi cosa.",
+    "import": "Importa",
+    "imported": "{count} modello/i importato/i",
+    "importFailed": "Impossibile importare questo pacchetto",
+    "cancel": "Annulla"
+  },
+  "list": {
+    "tabAll": "Tutte",
+    "tabInProgress": "In corso",
+    "tabCompleted": "Chiuse",
+    "search": "Cerca ispezioni…",
+    "new": "Nuova ispezione",
+    "empty": "Nessuna ispezione trovata.",
+    "vehicle": "Veicolo",
+    "template": "Modello",
+    "progress": "Avanzamento",
+    "status": "Stato",
+    "date": "Data",
+    "statusInProgress": "In corso",
+    "statusCompleted": "Chiusa"
+  },
+  "new": {
+    "title": "Nuova ispezione",
+    "vehicle": "Veicolo",
+    "searchVehicles": "Cerca veicoli…",
+    "loadingVehicles": "Caricamento veicoli…",
+    "noVehicles": "Nessun veicolo trovato.",
+    "template": "Modello",
+    "selectTemplate": "Scegli un modello",
+    "manageTemplates": "Gestisci modelli",
+    "cancel": "Annulla",
+    "create": "Crea ispezione",
+    "created": "Ispezione creata",
+    "createFailed": "Impossibile creare l'ispezione"
+  },
+  "shareDialog": {
+    "title": "Condividi ispezione",
+    "description": "Condividi con il cliente una vista in sola lettura di questa ispezione.",
+    "copyLink": "Copia link",
+    "copied": "Link copiato negli appunti",
+    "generated": "Link di condivisione creato",
+    "revoked": "Link di condivisione revocato"
+  }
+}

+ 29 - 2
messages/it/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "Messaggi SMS",
-    "featureDescription": "Invia e ricevi messaggi SMS con i tuoi clienti direttamente da Torqvoice."
+    "featureDescription": "Invia e ricevi messaggi SMS con i tuoi clienti direttamente da Torqvoice.",
+    "tabs": {
+      "inbox": "In arrivo",
+      "scheduled": "Pianificati"
+    },
+    "smsNotConfiguredTitle": "L'SMS non è configurato",
+    "smsNotConfiguredHint": "Collega un provider SMS per inviare e ricevere messaggi qui. Le email pianificate funzionano comunque.",
+    "goToSmsSettings": "Vai alle impostazioni SMS"
   },
   "notConfigured": {
     "title": "SMS non configurato",
@@ -20,7 +27,10 @@
     "deleted": "Conversazione eliminata",
     "deleteError": "Impossibile eliminare la conversazione",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Cerca conversazioni",
+    "noSearchResults": "Nessuna conversazione corrisponde alla ricerca",
+    "now": "ora"
   },
   "conversation": {
     "noPhone": "Nessun numero di telefono registrato per {name}. Aggiungi un numero di telefono per iniziare a inviare messaggi.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS inviato",
     "sentTo": "{label} è stato inviato a {name} ({phone})",
     "sendError": "Impossibile inviare l'SMS"
+  },
+  "compose": {
+    "newMessage": "Nuovo messaggio",
+    "title": "Nuovo messaggio",
+    "searchPlaceholder": "Cerca clienti per nome o numero",
+    "noMatches": "Nessun cliente corrisponde alla ricerca",
+    "noRecipients": "Nessun cliente con numero di telefono",
+    "noRecipientsHint": "Aggiungi un numero al cliente per scrivergli.",
+    "changeRecipient": "Scegli un'altra persona",
+    "messageLabel": "Messaggio",
+    "messagePlaceholder": "Messaggio a {name}...",
+    "segments": "{chars} caratteri · {segments} SMS",
+    "send": "Invia",
+    "scheduleInstead": "Pianifica invece",
+    "sent": "Inviato a {name}",
+    "sendError": "Impossibile inviare il messaggio",
+    "templates": "Modelli"
   }
 }

+ 2 - 3
messages/it/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Cerca...",
   "shortcut": "Ctrl+K",
+  "readMore": "Scopri di più",
   "newWorkOrder": "Nuovo ordine di lavoro",
   "quickCreate": {
     "title": "Aggiungi",
@@ -77,7 +78,6 @@
     "clients": "Clienti",
     "customers": "Clienti",
     "messages": "Messaggi",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Officina",
     "vehicles": "Veicoli",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "es. Officina Mario Rossi",
     "cancel": "Annulla",
     "createCompany": "Crea azienda",
-    "lightMode": "Modalità chiara",
-    "darkMode": "Modalità scura",
+    "theme": "Tema",
     "signOut": "Esci",
     "more": "Altro",
     "auditLog": "Registro attività",

+ 31 - 1
messages/it/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Note",
     "footerText": "Ispezione Veicolo — {shopName}",
     "viewPortal": "Visualizza il tuo portale: {url}",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "euPass": "Nessuna carenza",
+    "euAttention": "Carenza lieve",
+    "euFail": "Carenza grave",
+    "euDangerous": "Carenza pericolosa",
+    "basicPass": "Superato",
+    "basicAttention": "Attenzione",
+    "basicFail": "Non superato",
+    "basicDangerous": "Pericoloso",
+    "resultPass": "Esito favorevole",
+    "resultPassMinor": "Favorevole con carenze lievi",
+    "resultFail": "Non favorevole — carenze gravi",
+    "resultFailDangerous": "Non favorevole — carenze pericolose",
+    "resultIncomplete": "Non completato",
+    "testDetails": "Dati del controllo",
+    "testDate": "Data del controllo",
+    "testLocation": "Luogo del controllo",
+    "inspector": "Ispettore",
+    "certificateNumber": "Numero del certificato",
+    "vehicleCategory": "Categoria del veicolo",
+    "nextTestDue": "Prossima revisione",
+    "limit": "Limite",
+    "overallResult": "Esito del controllo",
+    "deficiencies": "Carenze riscontrate",
+    "reading": "Misura",
+    "noDeficiencies": "Non sono state registrate carenze.",
+    "resultDetailPass": "Non sono state riscontrate carenze.",
+    "resultDetailPassMinor": "Il veicolo è idoneo. Riparare le carenze lievi senza indebito ritardo.",
+    "resultDetailFail": "Il veicolo non è idoneo. Le carenze devono essere riparate e il veicolo deve essere ricontrollato.",
+    "resultDetailFailDangerous": "Il veicolo non deve circolare su strada pubblica finché le carenze pericolose non sono riparate.",
+    "resultDetailIncomplete": "Questo controllo è ancora in corso."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "STORICO ASSISTENZA",

+ 76 - 0
messages/it/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Pianifica un messaggio",
+    "editTitle": "Modifica messaggio pianificato",
+    "channelLabel": "Invia tramite",
+    "channels": {
+      "email": "Email",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "Nota nell'app"
+    },
+    "repeatLabel": "Ripeti",
+    "frequencies": {
+      "once": "Una volta",
+      "daily": "Ogni giorno",
+      "weekly": "Ogni settimana",
+      "biweekly": "Ogni 2 settimane",
+      "monthly": "Ogni mese",
+      "yearly": "Ogni anno"
+    },
+    "customerLabel": "Cliente",
+    "selectCustomer": "Seleziona cliente",
+    "none": "Nessuno",
+    "recipientEmail": "Indirizzo email",
+    "recipientPhone": "Numero di telefono",
+    "recipientChat": "ID chat Telegram",
+    "recipientOverride": "Invia a un altro indirizzo",
+    "recipientHintCustomer": "Lascia vuoto per usare i dati salvati.",
+    "recipientHintDirect": "Scegli un cliente o scrivi la destinazione.",
+    "subjectLabel": "Oggetto",
+    "subjectPlaceholder": "es. La tua auto è pronta",
+    "messageLabel": "Messaggio",
+    "messagePlaceholder": "Cosa vuoi dire?",
+    "characters": "{count} / {max} caratteri",
+    "dateLabel": "Data",
+    "timeLabel": "Ora",
+    "endDateLabel": "Ripeti fino al",
+    "endDateHint": "Lascia vuoto per ripetere sempre.",
+    "schedule": "Pianifica",
+    "scheduled": "Messaggio pianificato",
+    "updated": "Messaggio pianificato aggiornato",
+    "saveError": "Impossibile salvare il messaggio"
+  },
+  "list": {
+    "scheduleMessage": "Pianifica messaggio",
+    "scheduleForCustomer": "Pianifica un messaggio",
+    "filters": {
+      "upcoming": "In arrivo",
+      "sent": "Inviati",
+      "failed": "Non riusciti",
+      "cancelled": "Annullati",
+      "all": "Tutti"
+    },
+    "status": {
+      "scheduled": "Pianificato",
+      "sent": "Inviato",
+      "failed": "Non riuscito",
+      "cancelled": "Annullato"
+    },
+    "empty": "Niente in programma",
+    "emptyHint": "Fai clic destro su un giorno del calendario, o usa Pianifica messaggio.",
+    "noRecipient": "Nessun destinatario",
+    "sentCount": "inviato {count}x",
+    "rowMenu": "Menu messaggio",
+    "sendNow": "Invia ora",
+    "cancel": "Annulla invio",
+    "sentNow": "Messaggio inviato",
+    "sendError": "Impossibile inviare il messaggio",
+    "cancelled": "Invio annullato",
+    "cancelError": "Impossibile annullare il messaggio",
+    "deleted": "Messaggio eliminato",
+    "deleteError": "Impossibile eliminare il messaggio",
+    "deleteTitle": "Eliminare questo messaggio?",
+    "deleteDescription": "Il messaggio pianificato viene rimosso definitivamente. Quanto già inviato resta nella conversazione."
+  }
+}

+ 15 - 3
messages/it/settings.json

@@ -856,8 +856,18 @@
   "appearance": {
     "title": "Aspetto",
     "description": "Personalizza l'aspetto di Torqvoice.",
-    "darkMode": "Modalita scura",
-    "darkModeHint": "Passa tra tema chiaro e scuro",
+    "themeLabel": "Tema",
+    "themeHint": "Scegli la combinazione di colori dell'app. La scelta viene salvata su questo dispositivo.",
+    "themes": {
+      "light": "Chiaro",
+      "dark": "Scuro",
+      "graphite": "Grafite",
+      "ocean": "Oceano",
+      "forest": "Foresta",
+      "midnight": "Mezzanotte",
+      "carbon": "Carbonio",
+      "system": "Sistema"
+    },
     "dateTimeTitle": "Data e ora",
     "dateTimeDescription": "Configura come date e orari vengono visualizzati nell'applicazione.",
     "dateFormat": "Formato data",
@@ -901,6 +911,8 @@
     "optAuditLogsDesc": "Cronologia delle attività e delle modifiche",
     "optSmsMessages": "Messaggi SMS",
     "optSmsMessagesDesc": "Messaggi SMS inviati e ricevuti",
+    "optScheduledMessages": "Messaggi pianificati",
+    "optScheduledMessagesDesc": "Messaggi in coda e ricorrenti in attesa di essere inviati",
     "optNotifications": "Notifiche",
     "optNotificationsDesc": "Notifiche di sistema",
     "optCustomFields": "Campi personalizzati",
@@ -1179,7 +1191,7 @@
   },
   "ai": {
     "title": "Assistente IA",
-    "readMore": "Read More",
+    "readMore": "Scopri di più",
     "description": "Configura l'IA per generare automaticamente note di servizio e riassumere la cronologia del veicolo.",
     "enableLabel": "Abilita IA",
     "enableHint": "Usa le funzionalita basate sull'IA in tutta l'applicazione",

+ 47 - 1
messages/it/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "Scarica PDF",
     "notes": "Note",
     "quoteCancelled": "Richiesta di preventivo annullata",
-    "cancelFailed": "Annullamento della richiesta non riuscito"
+    "cancelFailed": "Annullamento della richiesta non riuscito",
+    "eu": {
+      "pass": "Nessuna carenza",
+      "attention": "Carenza lieve",
+      "fail": "Carenza grave",
+      "dangerous": "Carenza pericolosa",
+      "not_inspected": "Non controllato"
+    },
+    "basic": {
+      "pass": "Superato",
+      "attention": "Attenzione",
+      "fail": "Non superato",
+      "dangerous": "Pericoloso",
+      "not_inspected": "Non controllato"
+    },
+    "result": {
+      "pass": "Esito favorevole",
+      "pass_minor": "Favorevole con carenze lievi",
+      "fail": "Non favorevole — carenze gravi",
+      "fail_dangerous": "Non favorevole — carenze pericolose",
+      "incomplete": "Non completato"
+    },
+    "resultDetail": {
+      "pass": "Non sono state riscontrate carenze.",
+      "pass_minor": "Il veicolo è idoneo. Riparare le carenze lievi senza indebito ritardo.",
+      "fail": "Il veicolo non è idoneo. Le carenze devono essere riparate e il veicolo deve essere ricontrollato.",
+      "fail_dangerous": "Il veicolo non deve circolare su strada pubblica finché le carenze pericolose non sono riparate.",
+      "incomplete": "Questo controllo è ancora in corso."
+    },
+    "testDetails": "Dati del controllo",
+    "testDate": "Data del controllo",
+    "certificateNumber": "Numero del certificato",
+    "vehicleCategory": "Categoria del veicolo",
+    "inspector": "Ispettore",
+    "testLocation": "Luogo del controllo",
+    "nextTestDue": "Prossima revisione",
+    "vesselLabel": "Imbarcazione",
+    "plateLabel": "Targa",
+    "odometerLabel": "Contachilometri",
+    "engineHoursLabel": "Ore motore",
+    "summary": "Riepilogo",
+    "progressLabel": "{graded} controlli valutati",
+    "limit": "Limite",
+    "viewPhoto": "Vedi foto",
+    "deficienciesFound": "Carenze riscontrate ({count})",
+    "allResults": "Tutti i risultati",
+    "privacyNotice": "Questo rapporto le viene fornito dall'officina che ha eseguito il controllo. È consultabile da chiunque disponga di questo link: la preghiamo di non inoltrarlo. Contatti l'officina per revocare il link o cancellare i suoi dati."
   },
   "terms": {
     "title": "Condizioni di Vendita (Salgsvilkår)",

+ 9 - 8
messages/it/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Rapporti di stato",
+    "readMore": "Scopri di più",
     "newReport": "Nuovo rapporto",
     "empty": "Nessun rapporto di stato",
     "emptyDescription": "Crea un rapporto di stato per aggiornare il cliente sullo stato del veicolo.",
@@ -76,17 +77,17 @@
     "deleteTitle": "Elimina rapporto di stato",
     "deleteFailed": "Impossibile eliminare il rapporto di stato",
     "cancel": "Annulla",
-  "feedback": "Commento",
-  "hasComment": "Ricevuto",
-  "noFeedback": "Nessun commento",
-  "sentAt": "Inviato",
-  "sentVia": "Inviato tramite",
-  "messageLabel": "Messaggio",
-  "videoLabel": "Video"
+    "feedback": "Commento",
+    "hasComment": "Ricevuto",
+    "noFeedback": "Nessun commento",
+    "sentAt": "Inviato",
+    "sentVia": "Inviato tramite",
+    "messageLabel": "Messaggio",
+    "videoLabel": "Video"
   },
   "notify": {
     "defaultMessage": "Ciao {name}, abbiamo un aggiornamento sullo stato del suo {vehicle}. Visualizzalo qui: {url}",
     "emailSubject": "Aggiornamento stato veicolo - {vehicle}",
-  "viewReport": "Visualizza il rapporto qui: {url}"
+    "viewReport": "Visualizza il rapporto qui: {url}"
   }
 }

+ 2 - 2
messages/it/vehicles.json

@@ -134,7 +134,7 @@
     "dueMileagePlaceholder": "es. 50000",
     "reminderUpdated": "Promemoria aggiornato",
     "reminderCreated": "Promemoria creato",
-    "saveError": "Impossibile {action} il promemoria",
+    "saveError": "Impossibile salvare il promemoria",
     "notifyLabel": "Avvisami alla scadenza",
     "notifyInApp": "Notifica in app",
     "notifyEmail": "E-mail"
@@ -201,7 +201,7 @@
     "noteUpdated": "Nota aggiornata",
     "noteCreated": "Nota creata",
     "titleRequired": "Titolo e contenuto sono obbligatori",
-    "saveError": "Impossibile {action} la nota",
+    "saveError": "Impossibile salvare la nota",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",

+ 11 - 1
messages/lt/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Sukurtas webhook’as",
     "webhook_update": "Atnaujintas webhook’as",
     "webhook_delete": "Ištrintas webhook’as",
-    "webhook_rotateSecret": "Atnaujintas webhook’o slaptasis raktas"
+    "webhook_rotateSecret": "Atnaujintas webhook’o slaptasis raktas",
+    "inspection_reopen": "Apžiūra atverta iš naujo",
+    "inspectionTemplate_import": "Importuotas apžiūros šablonas",
+    "scheduled_message_create": "Sukurta suplanuota žinutė",
+    "scheduled_message_update": "Atnaujinta suplanuota žinutė",
+    "scheduled_message_delete": "Ištrinta suplanuota žinutė",
+    "scheduled_message_cancel": "Atšaukta suplanuota žinutė",
+    "scheduled_message_send_now": "Išsiųsta suplanuota žinutė",
+    "settings_applyTaxRate": "Pritaikytas mokesčio tarifas",
+    "settings_convertToExclusive": "Kainos konvertuotos be mokesčio",
+    "settings_convertToInclusive": "Kainos konvertuotos su mokesčiu"
   }
 }

+ 4 - 4
messages/lt/billing.json

@@ -79,9 +79,9 @@
     "failedDelete": "Nepavyko ištrinti",
     "processed": "Apdorota {count} sąskaita(-ų)",
     "failedProcess": "Nepavyko apdoroti",
-    "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "pause": "Pristabdyti",
+    "resume": "Tęsti",
+    "delete": "Ištrinti",
+    "removeRow": "Pašalinti eilutę"
   }
 }

+ 16 - 3
messages/lt/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Paslaugos",
     "reminders": "Priminimai",
-    "quotes": "Pasiūlymai"
+    "quotes": "Pasiūlymai",
+    "messages": "Žinutės"
   },
   "selectVehicle": "Pasirinkite transporto priemonę darbo užsakymui",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Naudoti šiandienos datą"
   },
   "more": "+ {count} daugiau",
+  "monthTotal": "{count} įvykių šį mėnesį",
+  "contextMenu": {
+    "newWorkOrder": "Naujas darbo užsakymas",
+    "newReminder": "Naujas priminimas",
+    "newQuote": "Naujas pasiūlymas",
+    "openEvent": "Atidaryti ({count})",
+    "hint": "Patarimas: spustelėkite dieną dešiniuoju pelės mygtuku, kad pamatytumėte veiksmus",
+    "scheduleMessage": "Suplanuoti žinutę"
+  },
   "events": {
     "status": {
       "completed": "Užbaigta",
@@ -54,12 +64,15 @@
       "draft": "Juodraštis",
       "done": "Atlikta",
       "overdue": "Vėluoja",
-      "upcoming": "Artėja"
+      "upcoming": "Artėja",
+      "failed": "Nepavyko",
+      "queued": "Eilėje"
     },
     "type": {
       "service": "Paslauga",
       "reminder": "Priminimas",
-      "quote": "Pasiūlymas"
+      "quote": "Pasiūlymas",
+      "message": "Žinutė"
     },
     "noEvents": "Įvykių nėra",
     "selectDay": "Pasirinkite dieną su įvykiais arba sukurkite naują darbo užsakymą."

+ 24 - 0
messages/lt/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice atnaujinta į {version}",
     "whatsNew": "Žiūrėti naujienas",
     "dismiss": "Uždaryti"
+  },
+  "pagination": {
+    "showing": "Rodoma {start}–{end} iš {total}",
+    "perPage": "puslapyje",
+    "pageOf": "Puslapis {page} iš {pages}",
+    "first": "Pirmas puslapis",
+    "previous": "Ankstesnis puslapis",
+    "next": "Kitas puslapis",
+    "last": "Paskutinis puslapis"
+  },
+  "shared": {
+    "close": "Uždaryti",
+    "viewPlans": "Peržiūrėti planus",
+    "manageLicense": "Tvarkyti licenciją",
+    "installOwn": "Įdiekite savo",
+    "install": "Įdiegti",
+    "installApp": "Įdiegti programą",
+    "installTorqvoice": "Įdiegti Torqvoice",
+    "dismiss": "Atmesti",
+    "useCamera": "Naudoti kamerą",
+    "enterManually": "Įvesti ranka",
+    "enterBarcode": "Įveskite brūkšninį kodą…",
+    "scanHint": "Nukreipkite kamerą į brūkšninį kodą arba įveskite jį ranka",
+    "iosInstallHint": "Palieskite Bendrinti > Įtraukti į pradžios ekraną"
   }
 }

+ 396 - 0
messages/lt/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Trūkumų nėra",
+      "attention": "Nedidelis trūkumas",
+      "fail": "Didelis trūkumas",
+      "dangerous": "Pavojingas trūkumas",
+      "not_inspected": "Netikrinta"
+    },
+    "basic": {
+      "pass": "Tinkama",
+      "attention": "Dėmesio",
+      "fail": "Netinkama",
+      "dangerous": "Pavojinga",
+      "not_inspected": "Netikrinta"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Nedidelis",
+      "fail": "Didelis",
+      "dangerous": "Pavojingas",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Atitinka reikalavimus. Pastabų nėra.",
+      "attention": "Reikšmingos įtakos saugai neturi. Transporto priemonė tinkama; pašalinkite progai pasitaikius.",
+      "fail": "Gali pakenkti saugai arba aplinkai. Netinkama; pašalinkite ir atlikite pakartotinę apžiūrą.",
+      "dangerous": "Tiesioginis ir neatidėliotinas pavojus eismo saugumui. Transporto priemone važiuoti negalima.",
+      "not_inspected": "Šis punktas nebuvo atliktas."
+    }
+  },
+  "results": {
+    "pass": "Teigiamas",
+    "pass_minor": "Teigiamas su nedideliais trūkumais",
+    "fail": "Neigiamas — dideli trūkumai",
+    "fail_dangerous": "Neigiamas — pavojingi trūkumai",
+    "incomplete": "Nebaigta",
+    "detail": {
+      "pass": "Trūkumų nenustatyta.",
+      "pass_minor": "Transporto priemonė tinkama naudoti. Nedelsdami pašalinkite nedidelius trūkumus.",
+      "fail": "Transporto priemonė netinkama. Trūkumus reikia pašalinti ir atlikti pakartotinę apžiūrą.",
+      "fail_dangerous": "Transporto priemone draudžiama važiuoti viešaisiais keliais, kol nebus pašalinti pavojingi trūkumai.",
+      "incomplete": "Ši apžiūra dar vyksta."
+    }
+  },
+  "page": {
+    "back": "Apžiūros",
+    "statusInProgress": "Vyksta",
+    "statusCompleted": "Baigta",
+    "complete": "Užbaigti",
+    "reopen": "Atverti iš naujo",
+    "share": "Bendrinti",
+    "save": "Įrašyti",
+    "saving": "Įrašoma…",
+    "savedAt": "Įrašyta {time}",
+    "savesAsYouGo": "Įrašo jums dirbant",
+    "saveFailed": "Kai kurie pakeitimai neįrašyti",
+    "allSaved": "Visi pakeitimai įrašyti",
+    "moreActions": "Daugiau veiksmų",
+    "downloadCertificate": "Atsisiųsti pažymą",
+    "manageTemplates": "Tvarkyti šablonus",
+    "delete": "Šalinti",
+    "createWorkOrder": "Sukurti darbo užsakymą",
+    "viewWorkOrder": "Žiūrėti darbo užsakymą",
+    "createQuote": "Sukurti pasiūlymą",
+    "viewQuote": "Žiūrėti pasiūlymą",
+    "needsDefect": "Galima, kai užfiksuojamas trūkumas",
+    "workOrderRaised": "Darbo užsakymas {number} sukurtas iš šios apžiūros {date}",
+    "open": "Atverti",
+    "quoteCreated": "Pasiūlymą sukūrė {name} {date}",
+    "quoteRequested": "Klientas paprašė pasiūlymo dėl {count} punkto (-ų)",
+    "stillToGrade": "Liko įvertinti {count} iš {total} punktų.",
+    "progress": "Eiga",
+    "checksGraded": "punktų įvertinta",
+    "progressLabel": "Įvertinta {graded} iš {total} punktų: {pass} be trūkumų, {attention} nedideli, {fail} dideli, {dangerous} pavojingi.",
+    "sections": "Grupės",
+    "graded": "{graded}/{total} įvertinta",
+    "vehicle": "Transporto priemonė",
+    "vessel": "Laivas",
+    "customer": "Klientas",
+    "plate": "Valstybinis numeris",
+    "registration": "Registracija",
+    "template": "Šablonas",
+    "scaleEu": "Vertinama pagal ES trūkumų skalę iš Direktyvos 2014/45/ES.",
+    "scaleBasic": "Vertinama tinkama / dėmesio / netinkama.",
+    "country": "Šalis: {code}.",
+    "manageInspectionTemplates": "Tvarkyti apžiūrų šablonus",
+    "readMore": "Skaityti daugiau",
+    "odometer": "Rida",
+    "engineHours": "Variklio valandos",
+    "completeTitle": "Užbaigti šią apžiūrą?",
+    "completeBody": "Užbaigus punktai užrakinami, o rezultatas tampa „{result}“.",
+    "completeBlocked": "Liko {count} punktas (-ai), kuriuos šablonas žymi kaip privalomus.",
+    "completeUngraded": "{count} punktas (-ai) neįvertinti.",
+    "completeDangerous": "Užfiksuota pavojingų trūkumų: {count}. Transporto priemone važiuoti viešaisiais keliais draudžiama.",
+    "reopenTitle": "Atverti šią apžiūrą iš naujo?",
+    "reopenBody": "Punktus vėl bus galima redaguoti, o rezultatas grįš į vyksta. Kontrolierius, pažymos numeris ir kitos apžiūros data išsaugomi.",
+    "reopenShared": "Kliento nuoroda lieka veikianti ir rodys, kaip rezultatas keičiasi jums redaguojant. Jau atsisiųsta pažyma išlaiko ankstesnį rezultatą.",
+    "deleteTitle": "Šalinti šią apžiūrą?",
+    "deleteBody": "Tai visam laikui pašalins apžiūrą, jos įvertinimus, pastabas ir nuotraukas. Veiksmo atšaukti negalima.",
+    "cancel": "Atšaukti",
+    "completed": "Apžiūra užbaigta",
+    "reopened": "Apžiūra atverta iš naujo",
+    "deleted": "Apžiūra pašalinta",
+    "completeFailed": "Nepavyko užbaigti apžiūros",
+    "reopenFailed": "Nepavyko atverti apžiūros iš naujo",
+    "deleteFailed": "Nepavyko pašalinti apžiūros",
+    "quoteFailed": "Nepavyko sukurti pasiūlymo",
+    "workOrderFailed": "Nepavyko sukurti darbo užsakymo"
+  },
+  "item": {
+    "required": "(privaloma)",
+    "saving": "Įrašoma",
+    "addNote": "Pridėti pastabą",
+    "hideNote": "Slėpti pastabą",
+    "addPhoto": "Pridėti nuotrauką ar vaizdo įrašą prie „{name}“",
+    "notesFor": "Pastabos apie „{name}“",
+    "describeDefect": "Aprašykite trūkumą — jis atsiras ataskaitoje",
+    "optionalNote": "Pridėti pastabą (nebūtina)",
+    "notesRequired": "Aprašykite trūkumą, kad šis įvertinimas būtų įrašytas.",
+    "photoRequired": "Čia būtina trūkumo nuotrauka. Apžiūros užbaigti negalima, kol ji nepridėta.",
+    "reading": "Rodmuo",
+    "readingUnit": "Rodmuo ({unit})",
+    "limit": "Ribinė vertė: {range}",
+    "recordedValue": "Įrašyta reikšmė",
+    "answer": "Atsakymas",
+    "selectAnswer": "Pasirinkite atsakymą",
+    "viewPhoto": "Žiūrėti „{name}“ {index} nuotrauką visu dydžiu",
+    "photoAlt": "{name}, nuotrauka {index}",
+    "removePhoto": "Pašalinti {index} nuotrauką iš „{name}“",
+    "clearTitle": "Išvalyti šį įvertinimą?",
+    "clearBody": "Prie „{name}“ įrašyta pastaba bus pašalinta, o punktas grįš į netikrinta.",
+    "clear": "Išvalyti",
+    "cancel": "Atšaukti",
+    "saveFailed": "Nepavyko įrašyti šio punkto",
+    "uploadFailed": "Nepavyko įkelti",
+    "uploadFailedFor": "Nepavyko įkelti {name}"
+  },
+  "suggestions": {
+    "title": "Dažni trūkumai",
+    "add": "Pridėti „{text}“ ir įvertinti kaip {grade}",
+    "more": "Daugiau ({count})",
+    "search": "Ieškoti formuluotės",
+    "empty": "Tinkamų formuluočių nėra.",
+    "source": {
+      "workshop": "Jūsų dirbtuvės",
+      "history": "Naudota anksčiau",
+      "regulation": "Direktyva 2014/45/ES",
+      "general": "Bendra"
+    }
+  },
+  "media": {
+    "viewer": "Vaizdas {index} iš {total}: {caption}",
+    "close": "Uždaryti peržiūrą",
+    "previous": "Ankstesnis vaizdas",
+    "next": "Kitas vaizdas"
+  },
+  "certificate": {
+    "title": "Pažymos duomenys",
+    "description": "Privalomi techninės apžiūros pažymoje pagal Direktyvos 2014/45/ES IV priedą.",
+    "inspector": "Kontrolierius",
+    "notRecorded": "Neįrašyta",
+    "addTechnician": "Pridėti mechaniką…",
+    "recordedAs": "Įrašyta kaip {name}",
+    "vehicleCategory": "Transporto priemonės kategorija",
+    "mileageAtTest": "{label} apžiūros metu",
+    "reportReference": "Ataskaitos nuoroda",
+    "reportReferenceHelp": "Jūsų pačių nuoroda šiai ataskaitai. Jei esate įgaliota techninės apžiūros stotis, išduodanti oficialią pažymą, įrašykite čia jos numerį, kad abu sutaptų. Kitu atveju palikite tuščią.",
+    "optional": "Nebūtina",
+    "placeOfTest": "Apžiūros vieta",
+    "placeholderAddress": "Apžiūros stotis arba dirbtuvių adresas",
+    "fromSettings": "Iš jūsų dirbtuvių nustatymų.",
+    "change": "Keisti",
+    "differsFromWorkshop": "Skiriasi nuo jūsų dirbtuvių adreso.",
+    "useWorkshopAddress": "Naudoti dirbtuvių adresą",
+    "noWorkshopAddress": "Dirbtuvių adresas nenurodytas.",
+    "addOne": "Pridėti adresą",
+    "nextTestDue": "Kita apžiūra",
+    "notSet": "Nenustatyta",
+    "intervalGroup": "Nustatyti kitos apžiūros datą nuo šios apžiūros",
+    "intervalHelp": "Skaičiuojama nuo šios apžiūros datos. Dveji metai – Sąjungos atskaitos taškas lengviesiems ir lengviesiems krovininiams automobiliams; pasitikrinkite savo šalyje taikomą periodiškumą.",
+    "months6": "6 mėnesiai",
+    "years1": "1 metai",
+    "years2": "2 metai",
+    "years3": "3 metai",
+    "years4": "4 metai",
+    "unsaved": "Neįrašyti pakeitimai",
+    "saveDetails": "Įrašyti duomenis",
+    "saved": "Duomenys įrašyti",
+    "saveFailed": "Nepavyko įrašyti duomenų",
+    "addTechnicianTitle": "Pridėti mechaniką",
+    "addTechnicianBody": "Jis įtraukiamas į dirbtuvių sąrašą, jam galima skirti ir darbus, ir apžiūras.",
+    "technicianName": "Vardas",
+    "technicianPlaceholder": "pvz., Anna Berg",
+    "addAndSelect": "Pridėti ir pasirinkti",
+    "technicianAdded": "{name} pridėtas ir pasirinktas",
+    "technicianFailed": "Nepavyko pridėti mechaniko",
+    "cancel": "Atšaukti"
+  },
+  "templates": {
+    "title": "Apžiūrų šablonai",
+    "description": "Tikrinimo sąrašai, kuriuos peržiūri jūsų mechanikai. Sukurkite po vieną kiekvienai šaliai, transporto priemonės tipui ar paslaugai, kurią parduodate.",
+    "import": "Importuoti",
+    "browse": "Naršyti sąrašus",
+    "new": "Naujas šablonas",
+    "restoreBanner": "Iš jūsų sąrašo pašalinta paruoštų sąrašų: {count}. Galite juos grąžinti.",
+    "restore": "Atkurti",
+    "restored": "Atkurta sąrašų: {count}",
+    "allPresent": "Visi sąrašai jau čia",
+    "restoreFailed": "Nepavyko pridėti sąrašų",
+    "emptyTitle": "Šablonų dar nėra",
+    "emptyBody": "Visi paruošti sąrašai, įskaitant ES periodinę techninę apžiūrą, buvo pašalinti. Grąžinkite juos arba susikurkite savo nuo nulio.",
+    "restoreChecklists": "Atkurti sąrašus",
+    "buildMyOwn": "Kurti savo",
+    "default": "Numatytasis",
+    "actionsFor": "Veiksmai su „{name}“",
+    "edit": "Redaguoti",
+    "duplicate": "Dubliuoti",
+    "export": "Eksportuoti…",
+    "delete": "Šalinti",
+    "sections": "grupių: {count}",
+    "checks": "punktų: {count}",
+    "measured": "su matavimu: {count}",
+    "euScale": "ES trūkumų skalė",
+    "basicScale": "Tinkama / dėmesio / netinkama",
+    "deleteTitle": "Šalinti „{name}“?",
+    "deleteBody": "Tai visam laikui pašalins šabloną. Jau atliktos apžiūros išlaiko savo sąrašo kopiją ir nenukenčia.",
+    "deleted": "Šablonas pašalintas",
+    "deleteFailed": "Nepavyko pašalinti šablono",
+    "duplicated": "Šablonas dubliuotas",
+    "duplicateFailed": "Nepavyko dubliuoti šablono",
+    "cancel": "Atšaukti",
+    "srSections": "Grupės",
+    "srChecks": "Punktai",
+    "srMeasurements": "Matavimai"
+  },
+  "presets": {
+    "title": "Pradėti nuo šablono",
+    "description": "Kiekvienas šablonas nukopijuojamas į jūsų dirbtuves kaip įprastas šablonas. Pervadinkite grupes, perkelkite punktus ir keiskite bet kurią ribinę vertę pagal savo šalį ir savo įrangą.",
+    "search": "Ieškoti pagal pavadinimą, šalį ar normą",
+    "searchLabel": "Ieškoti šablonų",
+    "inYourList": "Jūsų sąraše",
+    "counts": "grupių: {sections} · punktų: {checks}",
+    "noMatch": "Nė vienas šablonas neatitinka „{query}“.",
+    "warning": "Teisės aktais grįsti šablonai turi įprastas ES ribines vertes. Prieš išduodami pažymą patikrinkite jas pagal savo šalies taisykles.",
+    "cancel": "Atšaukti",
+    "add": "Pridėti šabloną",
+    "added": "Šablonas pridėtas. Pritaikykite jį savo dirbtuvėms.",
+    "addFailed": "Nepavyko pridėti šablono",
+    "group": {
+      "regulatory": "Teisės aktai",
+      "workshop": "Dirbtuvės",
+      "specialist": "Specializuoti"
+    },
+    "groupDescription": {
+      "regulatory": "Periodinės techninės apžiūros sąrašai, parengti pagal Direktyvą 2014/45/ES.",
+      "workshop": "Bendri serviso ir pardavimo sąrašai, nesusieti su teisės aktais.",
+      "specialist": "Sąrašai pavaroms ir laivams, kuriems reikia atskiros procedūros."
+    },
+    "euScale": "ES trūkumų skalė",
+    "basicScale": "Tinkama / dėmesio / netinkama"
+  },
+  "builder": {
+    "newTitle": "Naujas šablonas",
+    "editTitle": "Redaguoti šabloną",
+    "description": "Sukurkite sąrašą, kurį jūsų dirbtuvės iš tikrųjų naudoja. Vilkite, kad pertvarkytumėte, ir nustatykite kiekvieną punktą taip, kad jis fiksuotų įvertinimą, matavimą, įrašytą pastabą ar nustatytą atsakymą.",
+    "name": "Pavadinimas",
+    "namePlaceholder": "pvz., Periodinė techninė apžiūra",
+    "templateDescription": "Aprašymas",
+    "descriptionPlaceholder": "Kam šis sąrašas skirtas ir kada jį naudoti.",
+    "country": "Šalis",
+    "notCountrySpecific": "Nesusieta su šalimi",
+    "countryHelp": "Įrašoma ataskaitoje, kad dirbtuvės, dirbančios keliose šalyse, atskirtų savo sąrašus.",
+    "defectScale": "Trūkumų skalė",
+    "scaleEu": "Nedidelis / didelis / pavojingas (ES)",
+    "scaleBasic": "Tinkama / dėmesio / netinkama",
+    "scaleEuHelp": "Direktyvos 2014/45/ES 7 straipsnio 2 dalies kategorijos. Transporto priemonė, turinti tik nedidelių trūkumų, vis tiek vertinama teigiamai.",
+    "scaleBasicHelp": "Paprasta trijų pakopų skalė serviso sąrašams, kurie nėra privaloma apžiūra.",
+    "defaultTemplate": "Numatytasis šablonas",
+    "defaultHelp": "Pasirenkamas iš anksto, kai mechanikas pradeda naują apžiūrą.",
+    "summary": "grupių: {sections} · punktų: {checks}",
+    "renumber": "Pernumeruoti nuorodas",
+    "renumberHelp": "Numeruoja kiekvieną grupę ir punktą iš eilės: 1, 1.1, 1.2, 2. Naujos eilutės numeruojamos jas pridedant, tad to prireiks tik po perkėlimų.",
+    "renumberWarning": "Šiame sąraše naudojamos teisės aktų nuorodos, pavyzdžiui 1.1.13. Pernumeravimas jas pakeis.",
+    "addSection": "Pridėti grupę",
+    "addCheck": "Pridėti punktą",
+    "ref": "Nuor.",
+    "sectionName": "Grupės pavadinimas, pvz., Stabdžių sistema",
+    "sectionNote": "Nebūtina pastaba, rodoma virš šios grupės punktų",
+    "checkName": "Punkto pavadinimas, pvz., Stabdžių kaladėlės",
+    "reorderSection": "Pertvarkyti grupę „{name}“",
+    "reorderCheck": "Pertvarkyti punktą „{name}“",
+    "removeSection": "Pašalinti grupę „{name}“",
+    "removeCheck": "Pašalinti punktą „{name}“",
+    "duplicateCheck": "Dubliuoti punktą „{name}“",
+    "configure": "Konfigūruoti „{name}“",
+    "hideSettings": "Slėpti „{name}“ nustatymus",
+    "howRecorded": "Kaip tai fiksuojama?",
+    "guidance": "Nurodymas mechanikui",
+    "guidancePlaceholder": "Rodomas po punkto pavadinimu apžiūros formoje.",
+    "measurement": "Matavimas",
+    "unit": "Vienetas",
+    "minimum": "Mažiausia",
+    "maximum": "Didžiausia",
+    "outOfRange": "Trūkumas už intervalo ribų",
+    "rangeHelp": "Palikite vieną ribą tuščią, jei reikalavimas vienpusis, pavyzdžiui mažiausiai 1,6 mm be didžiausios ribos. Rodmenys už intervalo ribų vertinami automatiškai.",
+    "answers": "Atsakymai",
+    "answersHelp": "Atsakymus atskirkite kableliais.",
+    "mustComplete": "Privaloma užpildyti",
+    "photoRequired": "Fiksuojant trūkumą būtina nuotrauka",
+    "commonWording": "Dažnos formuluotės",
+    "commonWordingHelp": "Po vieną formuluotę eilutėje. Jos siūlomos pirmiausia, kai mechanikas čia fiksuoja trūkumą, pirmiau už įtaisytus tekstus, kad jūsų dirbtuvės sutartų dėl gedimo aprašymo.",
+    "inputType": {
+      "condition": "Trūkumo įvertinimas",
+      "measurement": "Matavimas",
+      "text": "Laisvas tekstas",
+      "choice": "Pasirinkimas"
+    },
+    "inputHint": {
+      "condition": "Mechanikas vertina punktą pagal trūkumų skalę.",
+      "measurement": "Fiksuoja skaičių su matavimo vienetu, automatiškai vertinamą pagal intervalą.",
+      "text": "Fiksuoja įrašytą pastebėjimą, pavyzdžiui padangos markę ar gedimo kodą.",
+      "choice": "Mechanikas pasirenka vieną atsakymą iš nustatyto sąrašo."
+    },
+    "cancel": "Atšaukti",
+    "create": "Sukurti šabloną",
+    "saveChanges": "Įrašyti pakeitimus",
+    "created": "Šablonas sukurtas",
+    "updated": "Šablonas atnaujintas",
+    "saveFailed": "Nepavyko įrašyti šablono",
+    "severityAttention": "Nedidelis trūkumas",
+    "severityFail": "Didelis trūkumas",
+    "severityDangerous": "Pavojingas trūkumas",
+    "answersPlaceholder": "Pilna, Dalinė, Nėra"
+  },
+  "packages": {
+    "exportTitle": "Eksportuoti „{name}“",
+    "exportDescription": "Atsisiunčia visą sąrašą kaip failą: grupes, punktus, vienetus ir ribines vertes. Importuoti gali kiekvienas, naudojantis Torqvoice.",
+    "includeWording": "Įtraukti savo formuluotes",
+    "includeWordingHelp": "Formuluotės, kurias jūsų dirbtuvės pridėjo prie punktų. Naudingos gavėjui, tačiau tai laisvas tekstas, surinktas prie stalo, ir jame gali būti paminėtas klientas, kolega ar vietinis susitarimas. Išjungta, nebent jas perskaitėte.",
+    "attributeTo": "Priskirti (nebūtina)",
+    "attributePlaceholder": "pvz., Egeland Auto",
+    "attributeHelp": "Įrašoma į failą, kad diegiantysis matytų, iš kur jis. Iš jūsų paskyros nieko neimama.",
+    "download": "Atsisiųsti",
+    "exported": "Šablonas eksportuotas",
+    "exportFailed": "Nepavyko eksportuoti šio šablono",
+    "importTitle": "Importuoti sąrašą",
+    "importDescription": "Prideda sąrašą iš Torqvoice paketo failo. Jis atkeliauja kaip įprastas redaguojamas šablonas ir niekada nepakeičia jau turimo.",
+    "chooseFile": "Pasirinkite paketo failą",
+    "chooseAnother": "Pasirinkite kitą failą",
+    "unreadable": "Šio failo nepavyko perskaityti. Torqvoice paketas – tai iš šablono eksportuotas .json failas.",
+    "from": "Iš {author}",
+    "limitsWarning": "Bendrinamo sąrašo ribinės vertės yra tos, kurias nustatė jo autorius. Prieš ką nors pagal jį išduodami, patikrinkite jas pagal savo šalies taisykles.",
+    "import": "Importuoti",
+    "imported": "Importuota šablonų: {count}",
+    "importFailed": "Nepavyko importuoti šio paketo",
+    "cancel": "Atšaukti"
+  },
+  "list": {
+    "tabAll": "Visos",
+    "tabInProgress": "Vyksta",
+    "tabCompleted": "Baigtos",
+    "search": "Ieškoti apžiūrų…",
+    "new": "Nauja apžiūra",
+    "empty": "Apžiūrų nerasta.",
+    "vehicle": "Transporto priemonė",
+    "template": "Šablonas",
+    "progress": "Eiga",
+    "status": "Būsena",
+    "date": "Data",
+    "statusInProgress": "Vyksta",
+    "statusCompleted": "Baigta"
+  },
+  "new": {
+    "title": "Nauja apžiūra",
+    "vehicle": "Transporto priemonė",
+    "searchVehicles": "Ieškoti transporto priemonių…",
+    "loadingVehicles": "Įkeliamos transporto priemonės…",
+    "noVehicles": "Transporto priemonių nerasta.",
+    "template": "Šablonas",
+    "selectTemplate": "Pasirinkite šabloną",
+    "manageTemplates": "Tvarkyti šablonus",
+    "cancel": "Atšaukti",
+    "create": "Sukurti apžiūrą",
+    "created": "Apžiūra sukurta",
+    "createFailed": "Nepavyko sukurti apžiūros"
+  },
+  "shareDialog": {
+    "title": "Bendrinti apžiūrą",
+    "description": "Bendrinkite su klientu tik skaitymui skirtą šios apžiūros rodinį.",
+    "copyLink": "Kopijuoti nuorodą",
+    "copied": "Nuoroda nukopijuota į iškarpinę",
+    "generated": "Bendrinimo nuoroda sukurta",
+    "revoked": "Bendrinimo nuoroda atšaukta"
+  }
+}

+ 29 - 2
messages/lt/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "SMS žinutės",
-    "featureDescription": "Siųskite ir gaukite SMS žinutes su klientais tiesiogiai iš Torqvoice."
+    "featureDescription": "Siųskite ir gaukite SMS žinutes su klientais tiesiogiai iš Torqvoice.",
+    "tabs": {
+      "inbox": "Gauta",
+      "scheduled": "Suplanuota"
+    },
+    "smsNotConfiguredTitle": "SMS nesukonfigūruotas",
+    "smsNotConfiguredHint": "Prijunkite SMS tiekėją, kad galėtumėte siųsti ir gauti žinutes čia. Suplanuoti el. laiškai veikia ir be to.",
+    "goToSmsSettings": "Eiti į SMS nustatymus"
   },
   "notConfigured": {
     "title": "SMS nesukonfigūruotas",
@@ -20,7 +27,10 @@
     "deleted": "Pokalbis ištrintas",
     "deleteError": "Nepavyko ištrinti pokalbio",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Ieškoti pokalbių",
+    "noSearchResults": "Nėra pokalbių pagal paiešką",
+    "now": "dabar"
   },
   "conversation": {
     "noPhone": "{name} neturi telefono numerio. Pridėkite telefono numerį, kad pradėtumėte susirašinėti.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS išsiųsta",
     "sentTo": "{label} išsiųsta {name} ({phone})",
     "sendError": "Nepavyko išsiųsti SMS"
+  },
+  "compose": {
+    "newMessage": "Nauja žinutė",
+    "title": "Nauja žinutė",
+    "searchPlaceholder": "Ieškoti klientų pagal vardą ar numerį",
+    "noMatches": "Nėra klientų pagal paiešką",
+    "noRecipients": "Nėra klientų su telefono numeriu",
+    "noRecipientsHint": "Pridėkite klientui telefono numerį, kad galėtumėte rašyti.",
+    "changeRecipient": "Pasirinkti kitą",
+    "messageLabel": "Žinutė",
+    "messagePlaceholder": "Žinutė {name}...",
+    "segments": "{chars} simbolių · {segments} SMS",
+    "send": "Siųsti",
+    "scheduleInstead": "Geriau suplanuoti",
+    "sent": "Išsiųsta {name}",
+    "sendError": "Nepavyko išsiųsti žinutės",
+    "templates": "Šablonai"
   }
 }

+ 2 - 3
messages/lt/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Ieškoti...",
   "shortcut": "Ctrl+K",
+  "readMore": "Skaityti daugiau",
   "newWorkOrder": "Naujas darbo užsakymas",
   "quickCreate": {
     "title": "Greitas pridėjimas",
@@ -77,7 +78,6 @@
     "clients": "Klientai",
     "customers": "Klientai",
     "messages": "Žinutės",
-    "smsMessages": "SMS žinutės",
     "telegram": "Telegram",
     "workshop": "Dirbtuvės",
     "vehicles": "Transporto priemonės",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "pvz., Jono autoservisas",
     "cancel": "Atšaukti",
     "createCompany": "Sukurti įmonę",
-    "lightMode": "Šviesus režimas",
-    "darkMode": "Tamsus režimas",
+    "theme": "Tema",
     "signOut": "Atsijungti",
     "more": "Daugiau",
     "auditLog": "Audito žurnalas",

+ 31 - 1
messages/lt/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Pastabos",
     "footerText": "Transporto priemonės apžiūra — {shopName}",
     "viewPortal": "Peržiūrėkite savo portalą: {url}",
-    "tel": "Tel.: {phone}"
+    "tel": "Tel.: {phone}",
+    "euPass": "Trūkumų nėra",
+    "euAttention": "Nedidelis trūkumas",
+    "euFail": "Didelis trūkumas",
+    "euDangerous": "Pavojingas trūkumas",
+    "basicPass": "Tinkama",
+    "basicAttention": "Dėmesio",
+    "basicFail": "Netinkama",
+    "basicDangerous": "Pavojinga",
+    "resultPass": "Teigiamas",
+    "resultPassMinor": "Teigiamas su nedideliais trūkumais",
+    "resultFail": "Neigiamas — dideli trūkumai",
+    "resultFailDangerous": "Neigiamas — pavojingi trūkumai",
+    "resultIncomplete": "Nebaigta",
+    "testDetails": "Apžiūros duomenys",
+    "testDate": "Apžiūros data",
+    "testLocation": "Apžiūros vieta",
+    "inspector": "Kontrolierius",
+    "certificateNumber": "Pažymos numeris",
+    "vehicleCategory": "Transporto priemonės kategorija",
+    "nextTestDue": "Kita apžiūra",
+    "limit": "Ribinė vertė",
+    "overallResult": "Apžiūros rezultatas",
+    "deficiencies": "Nustatyti trūkumai",
+    "reading": "Rodmuo",
+    "noDeficiencies": "Trūkumų neužfiksuota.",
+    "resultDetailPass": "Trūkumų nenustatyta.",
+    "resultDetailPassMinor": "Transporto priemonė tinkama naudoti. Nedelsdami pašalinkite nedidelius trūkumus.",
+    "resultDetailFail": "Transporto priemonė netinkama. Trūkumus reikia pašalinti ir atlikti pakartotinę apžiūrą.",
+    "resultDetailFailDangerous": "Transporto priemone draudžiama važiuoti viešaisiais keliais, kol nebus pašalinti pavojingi trūkumai.",
+    "resultDetailIncomplete": "Ši apžiūra dar vyksta."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "PASLAUGŲ ISTORIJA",

+ 76 - 0
messages/lt/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Suplanuoti žinutę",
+    "editTitle": "Redaguoti suplanuotą žinutę",
+    "channelLabel": "Siųsti per",
+    "channels": {
+      "email": "El. paštas",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "Pastaba programoje"
+    },
+    "repeatLabel": "Kartoti",
+    "frequencies": {
+      "once": "Vieną kartą",
+      "daily": "Kasdien",
+      "weekly": "Kas savaitę",
+      "biweekly": "Kas 2 savaites",
+      "monthly": "Kas mėnesį",
+      "yearly": "Kasmet"
+    },
+    "customerLabel": "Klientas",
+    "selectCustomer": "Pasirinkite klientą",
+    "none": "Nėra",
+    "recipientEmail": "El. pašto adresas",
+    "recipientPhone": "Telefono numeris",
+    "recipientChat": "Telegram pokalbio ID",
+    "recipientOverride": "Siųsti kitu adresu",
+    "recipientHintCustomer": "Palikite tuščią, kad būtų naudojami išsaugoti duomenys.",
+    "recipientHintDirect": "Pasirinkite klientą arba įrašykite gavėją.",
+    "subjectLabel": "Tema",
+    "subjectPlaceholder": "pvz. Jūsų automobilis paruoštas",
+    "messageLabel": "Žinutė",
+    "messagePlaceholder": "Ką norite pasakyti?",
+    "characters": "{count} / {max} simbolių",
+    "dateLabel": "Data",
+    "timeLabel": "Laikas",
+    "endDateLabel": "Kartoti iki",
+    "endDateHint": "Palikite tuščią, kad kartotųsi be pabaigos.",
+    "schedule": "Suplanuoti",
+    "scheduled": "Žinutė suplanuota",
+    "updated": "Suplanuota žinutė atnaujinta",
+    "saveError": "Nepavyko išsaugoti žinutės"
+  },
+  "list": {
+    "scheduleMessage": "Suplanuoti žinutę",
+    "scheduleForCustomer": "Suplanuoti žinutę",
+    "filters": {
+      "upcoming": "Būsimos",
+      "sent": "Išsiųstos",
+      "failed": "Nepavykusios",
+      "cancelled": "Atšauktos",
+      "all": "Visos"
+    },
+    "status": {
+      "scheduled": "Suplanuota",
+      "sent": "Išsiųsta",
+      "failed": "Nepavyko",
+      "cancelled": "Atšaukta"
+    },
+    "empty": "Nieko nesuplanuota",
+    "emptyHint": "Spustelėkite dieną kalendoriuje dešiniuoju mygtuku arba pasirinkite Suplanuoti žinutę.",
+    "noRecipient": "Nėra gavėjo",
+    "sentCount": "išsiųsta {count}x",
+    "rowMenu": "Žinutės meniu",
+    "sendNow": "Siųsti dabar",
+    "cancel": "Atšaukti siuntimą",
+    "sentNow": "Žinutė išsiųsta",
+    "sendError": "Nepavyko išsiųsti žinutės",
+    "cancelled": "Siuntimas atšauktas",
+    "cancelError": "Nepavyko atšaukti žinutės",
+    "deleted": "Žinutė ištrinta",
+    "deleteError": "Nepavyko ištrinti žinutės",
+    "deleteTitle": "Ištrinti šią žinutę?",
+    "deleteDescription": "Suplanuota žinutė pašalinama visam laikui. Kas jau išsiųsta, lieka pokalbyje."
+  }
+}

+ 14 - 2
messages/lt/settings.json

@@ -856,8 +856,18 @@
   "appearance": {
     "title": "Išvaizda",
     "description": "Pritaikykite, kaip atrodo ir jaučiasi Torqvoice.",
-    "darkMode": "Tamsus režimas",
-    "darkModeHint": "Perjungti tarp šviesios ir tamsios temos",
+    "themeLabel": "Tema",
+    "themeHint": "Pasirinkite programos spalvų schemą. Pasirinkimas išsaugomas šiame įrenginyje.",
+    "themes": {
+      "light": "Šviesi",
+      "dark": "Tamsi",
+      "graphite": "Grafitas",
+      "ocean": "Vandenynas",
+      "forest": "Miškas",
+      "midnight": "Vidurnaktis",
+      "carbon": "Karbonas",
+      "system": "Sistemos"
+    },
     "dateTimeTitle": "Data ir laikas",
     "dateTimeDescription": "Konfigūruokite, kaip datos ir laikai rodomi visoje programoje.",
     "dateFormat": "Datos formatas",
@@ -901,6 +911,8 @@
     "optAuditLogsDesc": "Veiklos ir pakeitimų istorija",
     "optSmsMessages": "SMS žinutės",
     "optSmsMessagesDesc": "Išsiųstos ir gautos SMS žinutės",
+    "optScheduledMessages": "Suplanuotos žinutės",
+    "optScheduledMessagesDesc": "Eilėje esančios ir pasikartojančios žinutės, laukiančios išsiuntimo",
     "optNotifications": "Pranešimai",
     "optNotificationsDesc": "Sistemos pranešimai",
     "optCustomFields": "Pasirinktiniai laukai",

+ 47 - 1
messages/lt/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "Atsisiųsti PDF",
     "notes": "Pastabos",
     "quoteCancelled": "Pasiūlymo užklausa atšaukta",
-    "cancelFailed": "Nepavyko atšaukti užklausos"
+    "cancelFailed": "Nepavyko atšaukti užklausos",
+    "eu": {
+      "pass": "Trūkumų nėra",
+      "attention": "Nedidelis trūkumas",
+      "fail": "Didelis trūkumas",
+      "dangerous": "Pavojingas trūkumas",
+      "not_inspected": "Netikrinta"
+    },
+    "basic": {
+      "pass": "Tinkama",
+      "attention": "Dėmesio",
+      "fail": "Netinkama",
+      "dangerous": "Pavojinga",
+      "not_inspected": "Netikrinta"
+    },
+    "result": {
+      "pass": "Teigiamas",
+      "pass_minor": "Teigiamas su nedideliais trūkumais",
+      "fail": "Neigiamas — dideli trūkumai",
+      "fail_dangerous": "Neigiamas — pavojingi trūkumai",
+      "incomplete": "Nebaigta"
+    },
+    "resultDetail": {
+      "pass": "Trūkumų nenustatyta.",
+      "pass_minor": "Transporto priemonė tinkama naudoti. Nedelsdami pašalinkite nedidelius trūkumus.",
+      "fail": "Transporto priemonė netinkama. Trūkumus reikia pašalinti ir atlikti pakartotinę apžiūrą.",
+      "fail_dangerous": "Transporto priemone draudžiama važiuoti viešaisiais keliais, kol nebus pašalinti pavojingi trūkumai.",
+      "incomplete": "Ši apžiūra dar vyksta."
+    },
+    "testDetails": "Apžiūros duomenys",
+    "testDate": "Apžiūros data",
+    "certificateNumber": "Pažymos numeris",
+    "vehicleCategory": "Transporto priemonės kategorija",
+    "inspector": "Kontrolierius",
+    "testLocation": "Apžiūros vieta",
+    "nextTestDue": "Kita apžiūra",
+    "vesselLabel": "Laivas",
+    "plateLabel": "Valstybinis numeris",
+    "odometerLabel": "Rida",
+    "engineHoursLabel": "Variklio valandos",
+    "summary": "Santrauka",
+    "progressLabel": "Įvertinta patikrų: {graded}",
+    "limit": "Ribinė vertė",
+    "viewPhoto": "Žiūrėti nuotrauką",
+    "deficienciesFound": "Nustatyti trūkumai ({count})",
+    "allResults": "Visi rezultatai",
+    "privacyNotice": "Šią ataskaitą jums pateikia dirbtuvės, atlikusios apžiūrą. Ją gali peržiūrėti kiekvienas, turintis šią nuorodą, todėl neperduokite jos kitiems. Kreipkitės į dirbtuves, jei norite, kad nuoroda būtų panaikinta arba jūsų duomenys ištrinti."
   },
   "terms": {
     "title": "Pardavimo sąlygos",

+ 1 - 0
messages/lt/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Būsenos ataskaitos",
+    "readMore": "Skaityti daugiau",
     "newReport": "Nauja būsenos ataskaita",
     "empty": "Būsenos ataskaitų dar nėra",
     "emptyDescription": "Sukurkite būsenos ataskaitą, kad informuotumėte klientą apie transporto priemonės būseną.",

+ 3 - 3
messages/lt/vehicles.json

@@ -134,7 +134,7 @@
     "dueMileagePlaceholder": "pvz., 50000",
     "reminderUpdated": "Priminimas atnaujintas",
     "reminderCreated": "Priminimas sukurtas",
-    "saveError": "Nepavyko {action} priminimo",
+    "saveError": "Nepavyko išsaugoti priminimo",
     "notifyLabel": "Pranešti suėjus terminui",
     "notifyInApp": "Pranešimas programoje",
     "notifyEmail": "El. paštas"
@@ -201,7 +201,7 @@
     "noteUpdated": "Pastaba atnaujinta",
     "noteCreated": "Pastaba sukurta",
     "titleRequired": "Pavadinimas ir turinys yra privalomi",
-    "saveError": "Nepavyko {action} pastabos",
+    "saveError": "Nepavyko išsaugoti pastabos",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",
@@ -249,7 +249,7 @@
     "findingUpdated": "Pastebėjimas atnaujintas",
     "findingResolved": "Pastebėjimas išspręstas",
     "findingDeleted": "Pastebėjimas ištrintas",
-    "saveError": "Nepavyko {action} pastebėjimo",
+    "saveError": "Nepavyko išsaugoti pastebėjimo",
     "deleteError": "Nepavyko ištrinti pastebėjimo",
     "resolveError": "Nepavyko išspręsti pastebėjimo",
     "showing": "Rodoma {start}–{end} iš {total}",

+ 11 - 1
messages/nb/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Opprettet webhook",
     "webhook_update": "Oppdatert webhook",
     "webhook_delete": "Slettet webhook",
-    "webhook_rotateSecret": "Roterte webhook-hemmelighet"
+    "webhook_rotateSecret": "Roterte webhook-hemmelighet",
+    "inspection_reopen": "Gjenåpnet inspeksjon",
+    "inspectionTemplate_import": "Importerte inspeksjonsmal",
+    "scheduled_message_create": "Opprettet planlagt melding",
+    "scheduled_message_update": "Oppdaterte planlagt melding",
+    "scheduled_message_delete": "Slettet planlagt melding",
+    "scheduled_message_cancel": "Avbrøt planlagt melding",
+    "scheduled_message_send_now": "Sendte planlagt melding",
+    "settings_applyTaxRate": "Brukte avgiftssats",
+    "settings_convertToExclusive": "Konverterte priser til eks. avgift",
+    "settings_convertToInclusive": "Konverterte priser til inkl. avgift"
   }
 }

+ 3 - 3
messages/nb/billing.json

@@ -80,8 +80,8 @@
     "processed": "{count} faktura(er) behandlet",
     "failedProcess": "Kunne ikke behandle",
     "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "resume": "Gjenoppta",
+    "delete": "Slett",
+    "removeRow": "Fjern rad"
   }
 }

+ 16 - 3
messages/nb/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Tjenester",
     "reminders": "Påminnelser",
-    "quotes": "Tilbud"
+    "quotes": "Tilbud",
+    "messages": "Meldinger"
   },
   "selectVehicle": "Velg kjøretøy for arbeidsordre",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} flere",
+  "monthTotal": "{count} hendelser denne måneden",
+  "contextMenu": {
+    "newWorkOrder": "Ny arbeidsordre",
+    "newReminder": "Ny påminnelse",
+    "newQuote": "Nytt tilbud",
+    "openEvent": "Åpne ({count})",
+    "hint": "Tips: høyreklikk en dag for handlinger",
+    "scheduleMessage": "Planlegg melding"
+  },
   "events": {
     "status": {
       "completed": "Fullført",
@@ -54,12 +64,15 @@
       "draft": "Utkast",
       "done": "Ferdig",
       "overdue": "Forfalt",
-      "upcoming": "Kommende"
+      "upcoming": "Kommende",
+      "failed": "Mislyktes",
+      "queued": "I kø"
     },
     "type": {
       "service": "Tjeneste",
       "reminder": "Påminnelse",
-      "quote": "Tilbud"
+      "quote": "Tilbud",
+      "message": "Melding"
     },
     "noEvents": "Ingen hendelser",
     "selectDay": "Velg en dag med hendelser eller opprett en ny arbeidsordre."

+ 24 - 0
messages/nb/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice er oppdatert til {version}",
     "whatsNew": "Se hva som er nytt",
     "dismiss": "Lukk"
+  },
+  "pagination": {
+    "showing": "Viser {start}–{end} av {total}",
+    "perPage": "per side",
+    "pageOf": "Side {page} av {pages}",
+    "first": "Første side",
+    "previous": "Forrige side",
+    "next": "Neste side",
+    "last": "Siste side"
+  },
+  "shared": {
+    "close": "Lukk",
+    "viewPlans": "Se abonnementer",
+    "manageLicense": "Administrer lisens",
+    "installOwn": "Installer din egen",
+    "install": "Installer",
+    "installApp": "Installer app",
+    "installTorqvoice": "Installer Torqvoice",
+    "dismiss": "Lukk",
+    "useCamera": "Bruk kamera",
+    "enterManually": "Skriv inn manuelt",
+    "enterBarcode": "Skriv inn strekkode…",
+    "scanHint": "Rett kameraet mot en strekkode, eller skriv den inn manuelt",
+    "iosInstallHint": "Trykk Del > Legg til på Hjem-skjerm"
   }
 }

+ 396 - 0
messages/nb/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Ingen mangel",
+      "attention": "Mindre mangel",
+      "fail": "Vesentlig mangel",
+      "dangerous": "Farlig mangel",
+      "not_inspected": "Ikke kontrollert"
+    },
+    "basic": {
+      "pass": "Godkjent",
+      "attention": "Merknad",
+      "fail": "Ikke godkjent",
+      "dangerous": "Farlig",
+      "not_inspected": "Ikke kontrollert"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Mindre",
+      "fail": "Vesentlig",
+      "dangerous": "Farlig",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Oppfyller kravene. Ingenting å melde.",
+      "attention": "Ingen vesentlig betydning for sikkerheten. Kjøretøyet godkjennes; utbedres ved anledning.",
+      "fail": "Kan svekke sikkerheten eller påvirke miljøet. Kjøretøyet godkjennes ikke; utbedres og etterkontrolleres.",
+      "dangerous": "Direkte og umiddelbar fare for trafikksikkerheten. Kjøretøyet skal ikke kjøres.",
+      "not_inspected": "Dette punktet er ikke kontrollert."
+    }
+  },
+  "results": {
+    "pass": "Godkjent",
+    "pass_minor": "Godkjent med mindre mangler",
+    "fail": "Ikke godkjent — vesentlige mangler",
+    "fail_dangerous": "Ikke godkjent — farlige mangler",
+    "incomplete": "Ikke fullført",
+    "detail": {
+      "pass": "Det ble ikke funnet mangler.",
+      "pass_minor": "Kjøretøyet er godkjent. Utbedre de mindre manglene uten unødig opphold.",
+      "fail": "Kjøretøyet er ikke godkjent. Manglene må utbedres og kjøretøyet kontrolleres på nytt.",
+      "fail_dangerous": "Kjøretøyet må ikke brukes på offentlig vei før de farlige manglene er utbedret.",
+      "incomplete": "Denne kontrollen pågår fortsatt."
+    }
+  },
+  "page": {
+    "back": "Inspeksjoner",
+    "statusInProgress": "Pågår",
+    "statusCompleted": "Fullført",
+    "complete": "Fullfør",
+    "reopen": "Gjenåpne",
+    "share": "Del",
+    "save": "Lagre",
+    "saving": "Lagrer…",
+    "savedAt": "Lagret {time}",
+    "savesAsYouGo": "Lagrer underveis",
+    "saveFailed": "Noen endringer ble ikke lagret",
+    "allSaved": "Alle endringer er lagret",
+    "moreActions": "Flere handlinger",
+    "downloadCertificate": "Last ned kontrollseddel",
+    "manageTemplates": "Administrer maler",
+    "delete": "Slett",
+    "createWorkOrder": "Opprett arbeidsordre",
+    "viewWorkOrder": "Vis arbeidsordre",
+    "createQuote": "Opprett tilbud",
+    "viewQuote": "Vis tilbud",
+    "needsDefect": "Tilgjengelig når en mangel er registrert",
+    "workOrderRaised": "Arbeidsordre {number} opprettet fra denne inspeksjonen {date}",
+    "open": "Åpne",
+    "quoteCreated": "Tilbud opprettet av {name} {date}",
+    "quoteRequested": "Kunden ba om tilbud på {count} punkt(er)",
+    "stillToGrade": "{count} av {total} punkter gjenstår å vurdere.",
+    "progress": "Fremdrift",
+    "checksGraded": "punkter vurdert",
+    "progressLabel": "{graded} av {total} punkter vurdert: {pass} ingen mangel, {attention} mindre, {fail} vesentlige, {dangerous} farlige.",
+    "sections": "Grupper",
+    "graded": "{graded}/{total} vurdert",
+    "vehicle": "Kjøretøy",
+    "vessel": "Fartøy",
+    "customer": "Kunde",
+    "plate": "Kjennemerke",
+    "registration": "Registrering",
+    "template": "Mal",
+    "scaleEu": "Vurdert etter EUs mangelskala fra direktiv 2014/45/EU.",
+    "scaleBasic": "Vurdert godkjent / merknad / ikke godkjent.",
+    "country": "Land: {code}.",
+    "manageInspectionTemplates": "Administrer inspeksjonsmaler",
+    "readMore": "Les mer",
+    "odometer": "Kilometerstand",
+    "engineHours": "Motortimer",
+    "completeTitle": "Fullføre denne inspeksjonen?",
+    "completeBody": "Punktene låses når inspeksjonen fullføres, og resultatet blir «{result}».",
+    "completeBlocked": "{count} punkt(er) som malen krever, gjenstår.",
+    "completeUngraded": "{count} punkt(er) er ikke vurdert.",
+    "completeDangerous": "{count} farlig(e) mangel(er) registrert. Kjøretøyet skal ikke brukes på offentlig vei.",
+    "reopenTitle": "Gjenåpne denne inspeksjonen?",
+    "reopenBody": "Punktene kan redigeres igjen og resultatet går tilbake til pågår. Kontrollør, sertifikatnummer og neste kontroll beholdes.",
+    "reopenShared": "Kundelenken er fortsatt aktiv og vil vise at resultatet endrer seg mens du redigerer. En kontrollseddel som allerede er lastet ned, beholder det gamle resultatet.",
+    "deleteTitle": "Slette denne inspeksjonen?",
+    "deleteBody": "Dette sletter inspeksjonen, vurderingene, merknadene og bildene permanent. Handlingen kan ikke angres.",
+    "cancel": "Avbryt",
+    "completed": "Inspeksjonen er fullført",
+    "reopened": "Inspeksjonen er gjenåpnet",
+    "deleted": "Inspeksjonen er slettet",
+    "completeFailed": "Kunne ikke fullføre inspeksjonen",
+    "reopenFailed": "Kunne ikke gjenåpne inspeksjonen",
+    "deleteFailed": "Kunne ikke slette inspeksjonen",
+    "quoteFailed": "Kunne ikke opprette tilbud",
+    "workOrderFailed": "Kunne ikke opprette arbeidsordre"
+  },
+  "item": {
+    "required": "(påkrevd)",
+    "saving": "Lagrer",
+    "addNote": "Legg til merknad",
+    "hideNote": "Skjul merknad",
+    "addPhoto": "Legg til bilde eller video for {name}",
+    "notesFor": "Merknader for {name}",
+    "describeDefect": "Beskriv mangelen — dette vises på rapporten",
+    "optionalNote": "Legg til en merknad (valgfritt)",
+    "notesRequired": "Beskriv mangelen før denne vurderingen lagres.",
+    "photoRequired": "Det kreves bilde av mangelen her. Inspeksjonen kan ikke fullføres før et bilde er lagt ved.",
+    "reading": "Måling",
+    "readingUnit": "Måling ({unit})",
+    "limit": "Grense: {range}",
+    "recordedValue": "Registrert verdi",
+    "answer": "Svar",
+    "selectAnswer": "Velg et svar",
+    "viewPhoto": "Vis bilde {index} av {name} i full størrelse",
+    "photoAlt": "{name}, bilde {index}",
+    "removePhoto": "Fjern bilde {index} fra {name}",
+    "clearTitle": "Fjerne denne vurderingen?",
+    "clearBody": "Merknaden som er registrert på «{name}» fjernes, og punktet settes tilbake til ikke kontrollert.",
+    "clear": "Fjern",
+    "cancel": "Avbryt",
+    "saveFailed": "Kunne ikke lagre dette punktet",
+    "uploadFailed": "Opplasting mislyktes",
+    "uploadFailedFor": "Kunne ikke laste opp {name}"
+  },
+  "suggestions": {
+    "title": "Vanlige mangler",
+    "add": "Legg til «{text}» og sett vurdering {grade}",
+    "more": "Flere ({count})",
+    "search": "Søk i mangelbeskrivelser",
+    "empty": "Ingen treff.",
+    "source": {
+      "workshop": "Ditt verksted",
+      "history": "Brukt før",
+      "regulation": "Direktiv 2014/45/EU",
+      "general": "Generelt"
+    }
+  },
+  "media": {
+    "viewer": "Bilde {index} av {total}: {caption}",
+    "close": "Lukk bildevisning",
+    "previous": "Forrige bilde",
+    "next": "Neste bilde"
+  },
+  "certificate": {
+    "title": "Kontrollseddel",
+    "description": "Påkrevd på en kontrollseddel etter direktiv 2014/45/EU, vedlegg IV.",
+    "inspector": "Kontrollør",
+    "notRecorded": "Ikke registrert",
+    "addTechnician": "Legg til mekaniker…",
+    "recordedAs": "Registrert som {name}",
+    "vehicleCategory": "Kjøretøygruppe",
+    "mileageAtTest": "{label} ved kontrolltidspunktet",
+    "reportReference": "Rapportreferanse",
+    "reportReferenceHelp": "Din egen referanse for denne rapporten. Er du en godkjent kontrollorganisasjon som utsteder kontrollseddel, skriv inn nummeret her slik at de stemmer overens. Ellers kan feltet stå tomt.",
+    "optional": "Valgfritt",
+    "placeOfTest": "Kontrollsted",
+    "placeholderAddress": "Kontrollsted eller verkstedsadresse",
+    "fromSettings": "Fra verkstedinnstillingene dine.",
+    "change": "Endre",
+    "differsFromWorkshop": "Avviker fra verkstedsadressen din.",
+    "useWorkshopAddress": "Bruk verkstedsadressen",
+    "noWorkshopAddress": "Ingen verkstedsadresse er satt.",
+    "addOne": "Legg til en",
+    "nextTestDue": "Neste kontroll",
+    "notSet": "Ikke satt",
+    "intervalGroup": "Sett dato for neste kontroll ut fra denne kontrollen",
+    "intervalHelp": "Regnes fra datoen for denne kontrollen. To år er EUs utgangspunkt for personbiler og lette varebiler; sjekk intervallet som gjelder i ditt land.",
+    "months6": "6 måneder",
+    "years1": "1 år",
+    "years2": "2 år",
+    "years3": "3 år",
+    "years4": "4 år",
+    "unsaved": "Ulagrede endringer",
+    "saveDetails": "Lagre opplysninger",
+    "saved": "Opplysningene er lagret",
+    "saveFailed": "Kunne ikke lagre opplysningene",
+    "addTechnicianTitle": "Legg til mekaniker",
+    "addTechnicianBody": "Vedkommende legges til i verkstedets liste og kan tildeles både arbeid og inspeksjoner.",
+    "technicianName": "Navn",
+    "technicianPlaceholder": "f.eks. Anna Berg",
+    "addAndSelect": "Legg til og velg",
+    "technicianAdded": "{name} er lagt til og valgt",
+    "technicianFailed": "Kunne ikke legge til mekanikeren",
+    "cancel": "Avbryt"
+  },
+  "templates": {
+    "title": "Inspeksjonsmaler",
+    "description": "Sjekklistene mekanikerne dine går gjennom. Lag én per land, per kjøretøytype eller per tjeneste du selger.",
+    "import": "Importer",
+    "browse": "Bla i sjekklister",
+    "new": "Ny mal",
+    "restoreBanner": "{count} ferdige sjekklister er fjernet fra listen din. Du kan legge dem tilbake.",
+    "restore": "Gjenopprett",
+    "restored": "Gjenopprettet {count} sjekkliste(r)",
+    "allPresent": "Alle sjekklister er allerede her",
+    "restoreFailed": "Kunne ikke legge til sjekklistene",
+    "emptyTitle": "Ingen maler ennå",
+    "emptyBody": "De ferdige sjekklistene, inkludert EUs periodiske kjøretøykontroll, er alle fjernet. Legg dem tilbake, eller bygg din egen fra bunnen.",
+    "restoreChecklists": "Gjenopprett sjekklister",
+    "buildMyOwn": "Bygg min egen",
+    "default": "Standard",
+    "actionsFor": "Handlinger for {name}",
+    "edit": "Rediger",
+    "duplicate": "Dupliser",
+    "export": "Eksporter…",
+    "delete": "Slett",
+    "sections": "{count} gruppe(r)",
+    "checks": "{count} punkt(er)",
+    "measured": "{count} målt",
+    "euScale": "EUs mangelskala",
+    "basicScale": "Godkjent / merknad / ikke godkjent",
+    "deleteTitle": "Slette «{name}»?",
+    "deleteBody": "Dette sletter malen permanent. Inspeksjoner som allerede er utført med den, beholder sin egen kopi av sjekklisten og påvirkes ikke.",
+    "deleted": "Malen er slettet",
+    "deleteFailed": "Kunne ikke slette malen",
+    "duplicated": "Malen er duplisert",
+    "duplicateFailed": "Kunne ikke duplisere malen",
+    "cancel": "Avbryt",
+    "srSections": "Grupper",
+    "srChecks": "Punkter",
+    "srMeasurements": "Målinger"
+  },
+  "presets": {
+    "title": "Start fra en mal",
+    "description": "Hver ferdigmal kopieres inn i verkstedet ditt som en vanlig mal. Endre navn på grupper, flytt punkter og juster alle grenser slik at de passer landet ditt og utstyret ditt.",
+    "search": "Søk på navn, land eller standard",
+    "searchLabel": "Søk i maler",
+    "inYourList": "I listen din",
+    "counts": "{sections} grupper · {checks} punkter",
+    "noMatch": "Ingen mal treffer «{query}».",
+    "warning": "De lovpålagte malene har de vanlige EU-grensene. Kontroller dem mot nasjonale regler før du utsteder en kontrollseddel.",
+    "cancel": "Avbryt",
+    "add": "Legg til mal",
+    "added": "Malen er lagt til. Tilpass den til verkstedet ditt.",
+    "addFailed": "Kunne ikke legge til malen",
+    "group": {
+      "regulatory": "Lovpålagt",
+      "workshop": "Verksted",
+      "specialist": "Spesialist"
+    },
+    "groupDescription": {
+      "regulatory": "Sjekklister for periodisk kjøretøykontroll bygget på direktiv 2014/45/EU.",
+      "workshop": "Generelle service- og salgssjekklister som ikke er knyttet til et regelverk.",
+      "specialist": "Sjekklister for drivlinjer og fartøy som krever egen prosedyre."
+    },
+    "euScale": "EUs mangelskala",
+    "basicScale": "Godkjent / merknad / ikke godkjent"
+  },
+  "builder": {
+    "newTitle": "Ny mal",
+    "editTitle": "Rediger mal",
+    "description": "Bygg sjekklisten verkstedet ditt faktisk bruker. Dra for å endre rekkefølge, og still inn hvert punkt til å registrere en vurdering, en måling, en skreven merknad eller et fast svar.",
+    "name": "Navn",
+    "namePlaceholder": "f.eks. Periodisk kjøretøykontroll",
+    "templateDescription": "Beskrivelse",
+    "descriptionPlaceholder": "Hva sjekklisten brukes til og når.",
+    "country": "Land",
+    "notCountrySpecific": "Ikke landsspesifikk",
+    "countryHelp": "Registreres på rapporten slik at et verksted som jobber over landegrenser kan skille sjekklistene fra hverandre.",
+    "defectScale": "Mangelskala",
+    "scaleEu": "Mindre / vesentlig / farlig (EU)",
+    "scaleBasic": "Godkjent / merknad / ikke godkjent",
+    "scaleEuHelp": "Kategoriene i artikkel 7 nr. 2 i direktiv 2014/45/EU. Et kjøretøy med bare mindre mangler blir fortsatt godkjent.",
+    "scaleBasicHelp": "En enkel treetrinnsskala for servicesjekklister som ikke er en lovpålagt kontroll.",
+    "defaultTemplate": "Standardmal",
+    "defaultHelp": "Forhåndsvalgt når en mekaniker starter en ny inspeksjon.",
+    "summary": "{sections} gruppe(r) · {checks} punkt(er)",
+    "renumber": "Nummerer referanser på nytt",
+    "renumberHelp": "Nummererer hver gruppe og hvert punkt i rekkefølge: 1, 1.1, 1.2, 2. Nye rader nummereres når du legger dem til, så dette trengs bare etter at du har flyttet på ting.",
+    "renumberWarning": "Denne sjekklisten bruker regelverkshenvisninger som 1.1.13. Ny nummerering erstatter dem.",
+    "addSection": "Legg til gruppe",
+    "addCheck": "Legg til punkt",
+    "ref": "Ref.",
+    "sectionName": "Gruppenavn, f.eks. Bremser",
+    "sectionNote": "Valgfri merknad som vises over punktene i denne gruppen",
+    "checkName": "Punktnavn, f.eks. Bremsebelegg",
+    "reorderSection": "Endre rekkefølge på gruppen {name}",
+    "reorderCheck": "Endre rekkefølge på punktet {name}",
+    "removeSection": "Fjern gruppen {name}",
+    "removeCheck": "Fjern punktet {name}",
+    "duplicateCheck": "Dupliser punktet {name}",
+    "configure": "Still inn {name}",
+    "hideSettings": "Skjul innstillinger for {name}",
+    "howRecorded": "Hvordan registreres det?",
+    "guidance": "Veiledning til mekanikeren",
+    "guidancePlaceholder": "Vises under punktnavnet på inspeksjonsskjemaet.",
+    "measurement": "Måling",
+    "unit": "Benevning",
+    "minimum": "Minimum",
+    "maximum": "Maksimum",
+    "outOfRange": "Mangel utenfor intervallet",
+    "rangeHelp": "La en grense stå tom for et ensidig krav, for eksempel minimum 1,6 mm uten maksimum. Målinger utenfor intervallet vurderes automatisk.",
+    "answers": "Svar",
+    "answersHelp": "Skill svarene med komma.",
+    "mustComplete": "Må fylles ut",
+    "photoRequired": "Bilde kreves når det registreres en mangel",
+    "commonWording": "Vanlige mangelbeskrivelser",
+    "commonWordingHelp": "Én formulering per linje. Disse tilbys først når en mekaniker registrerer en mangel her, foran de innebygde, slik at verkstedet ditt kan bli enige om hvordan en feil beskrives.",
+    "inputType": {
+      "condition": "Mangelvurdering",
+      "measurement": "Måling",
+      "text": "Fritekst",
+      "choice": "Valg"
+    },
+    "inputHint": {
+      "condition": "Mekanikeren vurderer punktet etter mangelskalaen.",
+      "measurement": "Registrerer et tall med benevning, vurdert automatisk mot et intervall.",
+      "text": "Registrerer en skreven observasjon, for eksempel et dekkmerke eller en feilkode.",
+      "choice": "Mekanikeren velger ett av flere faste svar."
+    },
+    "cancel": "Avbryt",
+    "create": "Opprett mal",
+    "saveChanges": "Lagre endringer",
+    "created": "Malen er opprettet",
+    "updated": "Malen er oppdatert",
+    "saveFailed": "Kunne ikke lagre malen",
+    "severityAttention": "Mindre mangel",
+    "severityFail": "Vesentlig mangel",
+    "severityDangerous": "Farlig mangel",
+    "answersPlaceholder": "Full, Delvis, Ingen"
+  },
+  "packages": {
+    "exportTitle": "Eksporter «{name}»",
+    "exportDescription": "Laster ned hele sjekklisten som en fil: grupper, punkter, benevninger og grenser. Alle som kjører Torqvoice kan importere den.",
+    "includeWording": "Ta med verkstedets egne mangelbeskrivelser",
+    "includeWordingHelp": "Formuleringene verkstedet ditt har lagt til på punktene. Nyttige for den som mottar filen, men de er fritekst skrevet ved benken og kan navngi en kunde, en kollega eller en lokal ordning. Av med mindre du har lest gjennom dem.",
+    "attributeTo": "Tilskriv (valgfritt)",
+    "attributePlaceholder": "f.eks. Egeland Auto",
+    "attributeHelp": "Skrives inn i filen slik at den som installerer den ser hvor den kommer fra. Ingenting hentes fra kontoen din.",
+    "download": "Last ned",
+    "exported": "Malen er eksportert",
+    "exportFailed": "Kunne ikke eksportere denne malen",
+    "importTitle": "Importer en sjekkliste",
+    "importDescription": "Legger til en sjekkliste fra en Torqvoice-pakkefil. Den kommer inn som en vanlig mal du kan redigere, og erstatter aldri en du allerede har.",
+    "chooseFile": "Velg en pakkefil",
+    "chooseAnother": "Velg en annen fil",
+    "unreadable": "Filen kunne ikke leses. En Torqvoice-pakke er en .json-fil eksportert fra en mal.",
+    "from": "Fra {author}",
+    "limitsWarning": "Grensene i en delt sjekkliste er de forfatteren satte. Kontroller dem mot nasjonale regler før du utsteder noe fra den.",
+    "import": "Importer",
+    "imported": "Importerte {count} mal(er)",
+    "importFailed": "Kunne ikke importere denne pakken",
+    "cancel": "Avbryt"
+  },
+  "list": {
+    "tabAll": "Alle",
+    "tabInProgress": "Pågår",
+    "tabCompleted": "Fullført",
+    "search": "Søk i inspeksjoner…",
+    "new": "Ny inspeksjon",
+    "empty": "Ingen inspeksjoner funnet.",
+    "vehicle": "Kjøretøy",
+    "template": "Mal",
+    "progress": "Fremdrift",
+    "status": "Status",
+    "date": "Dato",
+    "statusInProgress": "Pågår",
+    "statusCompleted": "Fullført"
+  },
+  "new": {
+    "title": "Ny inspeksjon",
+    "vehicle": "Kjøretøy",
+    "searchVehicles": "Søk i kjøretøy…",
+    "loadingVehicles": "Laster kjøretøy…",
+    "noVehicles": "Ingen kjøretøy funnet.",
+    "template": "Mal",
+    "selectTemplate": "Velg mal",
+    "manageTemplates": "Administrer maler",
+    "cancel": "Avbryt",
+    "create": "Opprett inspeksjon",
+    "created": "Inspeksjonen er opprettet",
+    "createFailed": "Kunne ikke opprette inspeksjonen"
+  },
+  "shareDialog": {
+    "title": "Del inspeksjon",
+    "description": "Del en skrivebeskyttet visning av denne inspeksjonen med kunden.",
+    "copyLink": "Kopier lenke",
+    "copied": "Lenken er kopiert",
+    "generated": "Delingslenke opprettet",
+    "revoked": "Delingslenke trukket tilbake"
+  }
+}

+ 29 - 2
messages/nb/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "SMS-meldinger",
-    "featureDescription": "Send og motta SMS-meldinger med kundene dine direkte fra Torqvoice."
+    "featureDescription": "Send og motta SMS-meldinger med kundene dine direkte fra Torqvoice.",
+    "tabs": {
+      "inbox": "Innboks",
+      "scheduled": "Planlagt"
+    },
+    "smsNotConfiguredTitle": "SMS er ikke satt opp",
+    "smsNotConfiguredHint": "Koble til en SMS-leverandør for å sende og motta meldinger her. Planlagt e-post fungerer uansett.",
+    "goToSmsSettings": "Gå til SMS-innstillinger"
   },
   "notConfigured": {
     "title": "SMS ikke konfigurert",
@@ -20,7 +27,10 @@
     "deleted": "Samtale slettet",
     "deleteError": "Kunne ikke slette samtalen",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Søk i samtaler",
+    "noSearchResults": "Ingen samtaler treffer søket",
+    "now": "nå"
   },
   "conversation": {
     "noPhone": "Ingen telefonnummer registrert for {name}. Legg til et telefonnummer for å starte meldinger.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS sendt",
     "sentTo": "{label} har blitt sendt til {name} ({phone})",
     "sendError": "Kunne ikke sende SMS"
+  },
+  "compose": {
+    "newMessage": "Ny melding",
+    "title": "Ny melding",
+    "searchPlaceholder": "Søk kunder på navn eller nummer",
+    "noMatches": "Ingen kunder treffer søket",
+    "noRecipients": "Ingen kunder med telefonnummer",
+    "noRecipientsHint": "Legg til et telefonnummer på kunden for å sende SMS.",
+    "changeRecipient": "Velg en annen",
+    "messageLabel": "Melding",
+    "messagePlaceholder": "Melding til {name} ...",
+    "segments": "{chars} tegn · {segments} SMS",
+    "send": "Send",
+    "scheduleInstead": "Planlegg i stedet",
+    "sent": "Sendt til {name}",
+    "sendError": "Kunne ikke sende meldingen",
+    "templates": "Maler"
   }
 }

+ 2 - 3
messages/nb/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Søk...",
   "shortcut": "Ctrl+K",
+  "readMore": "Les mer",
   "newWorkOrder": "Ny arbeidsordre",
   "quickCreate": {
     "title": "Legg til",
@@ -77,7 +78,6 @@
     "clients": "Klienter",
     "customers": "Kunder",
     "messages": "Meldinger",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Verksted",
     "vehicles": "Kjøretøy",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "f.eks. Olas Bilverksted",
     "cancel": "Avbryt",
     "createCompany": "Opprett firma",
-    "lightMode": "Lyst modus",
-    "darkMode": "Mørkt modus",
+    "theme": "Tema",
     "signOut": "Logg ut",
     "more": "Mer",
     "auditLog": "Aktivitetslogg",

+ 31 - 1
messages/nb/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Notater",
     "footerText": "Kjøretøykontroll — {shopName}",
     "viewPortal": "Se portalen din: {url}",
-    "tel": "Tlf: {phone}"
+    "tel": "Tlf: {phone}",
+    "euPass": "Ingen mangel",
+    "euAttention": "Mindre mangel",
+    "euFail": "Vesentlig mangel",
+    "euDangerous": "Farlig mangel",
+    "basicPass": "Godkjent",
+    "basicAttention": "Merknad",
+    "basicFail": "Ikke godkjent",
+    "basicDangerous": "Farlig",
+    "resultPass": "Godkjent",
+    "resultPassMinor": "Godkjent med mindre mangler",
+    "resultFail": "Ikke godkjent — vesentlige mangler",
+    "resultFailDangerous": "Ikke godkjent — farlige mangler",
+    "resultIncomplete": "Ikke fullført",
+    "testDetails": "Kontrollopplysninger",
+    "testDate": "Kontrolldato",
+    "testLocation": "Kontrollsted",
+    "inspector": "Kontrollør",
+    "certificateNumber": "Sertifikatnummer",
+    "vehicleCategory": "Kjøretøygruppe",
+    "nextTestDue": "Neste kontroll",
+    "limit": "Grenseverdi",
+    "overallResult": "Kontrollresultat",
+    "deficiencies": "Mangler funnet",
+    "reading": "Måleverdi",
+    "noDeficiencies": "Ingen mangler ble registrert.",
+    "resultDetailPass": "Det ble ikke funnet mangler.",
+    "resultDetailPassMinor": "Kjøretøyet er godkjent. Utbedre de mindre manglene uten unødig opphold.",
+    "resultDetailFail": "Kjøretøyet er ikke godkjent. Manglene må utbedres og kjøretøyet kontrolleres på nytt.",
+    "resultDetailFailDangerous": "Kjøretøyet må ikke brukes på offentlig vei før de farlige manglene er utbedret.",
+    "resultDetailIncomplete": "Denne kontrollen pågår fortsatt."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "SERVICEHISTORIKK",

+ 76 - 0
messages/nb/scheduledMessages.json

@@ -0,0 +1,76 @@
+{
+  "dialog": {
+    "title": "Planlegg en melding",
+    "editTitle": "Rediger planlagt melding",
+    "channelLabel": "Send med",
+    "channels": {
+      "email": "E-post",
+      "sms": "SMS",
+      "telegram": "Telegram",
+      "in_app": "Notat i appen"
+    },
+    "repeatLabel": "Gjenta",
+    "frequencies": {
+      "once": "Én gang",
+      "daily": "Daglig",
+      "weekly": "Ukentlig",
+      "biweekly": "Annenhver uke",
+      "monthly": "Månedlig",
+      "yearly": "Årlig"
+    },
+    "customerLabel": "Kunde",
+    "selectCustomer": "Velg kunde",
+    "none": "Ingen",
+    "recipientEmail": "E-postadresse",
+    "recipientPhone": "Telefonnummer",
+    "recipientChat": "Telegram chat-id",
+    "recipientOverride": "Send til en annen adresse",
+    "recipientHintCustomer": "La stå tom for å bruke det som er registrert.",
+    "recipientHintDirect": "Velg en kunde, eller skriv hvor den skal.",
+    "subjectLabel": "Emne",
+    "subjectPlaceholder": "f.eks. Bilen din er klar",
+    "messageLabel": "Melding",
+    "messagePlaceholder": "Hva skal vi si?",
+    "characters": "{count} / {max} tegn",
+    "dateLabel": "Dato",
+    "timeLabel": "Tid",
+    "endDateLabel": "Gjenta til",
+    "endDateHint": "La stå tom for å fortsette.",
+    "schedule": "Planlegg",
+    "scheduled": "Melding planlagt",
+    "updated": "Planlagt melding oppdatert",
+    "saveError": "Kunne ikke lagre meldingen"
+  },
+  "list": {
+    "scheduleMessage": "Planlegg melding",
+    "scheduleForCustomer": "Planlegg en melding",
+    "filters": {
+      "upcoming": "Kommende",
+      "sent": "Sendt",
+      "failed": "Mislyktes",
+      "cancelled": "Avbrutt",
+      "all": "Alle"
+    },
+    "status": {
+      "scheduled": "Planlagt",
+      "sent": "Sendt",
+      "failed": "Mislyktes",
+      "cancelled": "Avbrutt"
+    },
+    "empty": "Ingenting planlagt",
+    "emptyHint": "Høyreklikk en dag i kalenderen, eller bruk Planlegg melding.",
+    "noRecipient": "Ingen mottaker",
+    "sentCount": "sendt {count}x",
+    "rowMenu": "Meldingsmeny",
+    "sendNow": "Send nå",
+    "cancel": "Avbryt sending",
+    "sentNow": "Melding sendt",
+    "sendError": "Kunne ikke sende meldingen",
+    "cancelled": "Sending avbrutt",
+    "cancelError": "Kunne ikke avbryte meldingen",
+    "deleted": "Melding slettet",
+    "deleteError": "Kunne ikke slette meldingen",
+    "deleteTitle": "Slette denne meldingen?",
+    "deleteDescription": "Den planlagte meldingen fjernes for godt. Det som allerede er sendt blir liggende i samtalen."
+  }
+}

+ 49 - 37
messages/nb/settings.json

@@ -185,7 +185,7 @@
     "failedUpdateProfile": "Kunne ikke oppdatere profil",
     "failedUpdateEmail": "Kunne ikke oppdatere e-post",
     "changePasswordTitle": "Endre passord",
-    "changePasswordDescription": "Skriv inn ditt navarende passord og velg et nytt.",
+    "changePasswordDescription": "Skriv inn ditt nåværende passord og velg et nytt.",
     "currentPassword": "Navarende passord",
     "newPassword": "Nytt passord",
     "confirmNewPassword": "Bekreft nytt passord",
@@ -229,13 +229,13 @@
     "twoFactorEnabledSuccess": "Tofaktorautentisering aktivert",
     "dangerZone": "Faresone",
     "deleteContentTitle": "Slett innhold",
-    "deleteContentDescription": "Slett selektivt organisasjonsdata som kjoretoy, kunder, tilbud eller inventar. Kontoen og innstillingene dine forblir intakte.",
+    "deleteContentDescription": "Slett selektivt organisasjonsdata som kjøretøy, kunder, tilbud eller inventar. Kontoen og innstillingene dine forblir intakte.",
     "deleteContentButton": "Slett innhold",
     "deleteAccountTitle": "Slett konto",
-    "deleteAccountDescription": "Slett kontoen din og alle tilknyttede data permanent, inkludert kjoretoy, servicehistorikk, arbeidsordrer, fakturaer, kunder, filer og betalinger. Denne handlingen kan ikke angres.",
+    "deleteAccountDescription": "Slett kontoen din og alle tilknyttede data permanent, inkludert kjøretøy, servicehistorikk, arbeidsordrer, fakturaer, kunder, filer og betalinger. Denne handlingen kan ikke angres.",
     "deleteAccountButton": "Slett konto",
     "deleteAccountDialogTitle": "Slett konto",
-    "deleteAccountDialogDescription": "Dette vil permanent slette kontoen din og alle tilknyttede data. Denne handlingen er irreversibel. Alle kjoretoy, servicehistorikk, arbeidsordrer, tilbud, kunder, filer og betalingshistorikk vil bli permanent fjernet.",
+    "deleteAccountDialogDescription": "Dette vil permanent slette kontoen din og alle tilknyttede data. Denne handlingen er irreversibel. Alle kjøretøy, servicehistorikk, arbeidsordrer, tilbud, kunder, filer og betalingshistorikk vil bli permanent fjernet.",
     "deleteAccountConfirmPhrase": "delete me",
     "deleteAccountConfirmPrompt": "Skriv <bold>delete me</bold> for a bekrefte",
     "permanentlyDelete": "Slett permanent",
@@ -243,10 +243,10 @@
     "failedDeleteAccount": "Kunne ikke slette konto",
     "deleteContentDialogTitle": "Slett innhold",
     "deleteContentDialogDescription": "Velg innholdet du vil slette permanent. Denne handlingen kan ikke angres.",
-    "contentVehicles": "Kjoretoy",
-    "contentVehiclesDescription": "Alle kjoretoy og deres servicehistorikk, notater, paminnelser, drivstofflogger og gjentakende fakturaer",
+    "contentVehicles": "Kjøretøy",
+    "contentVehiclesDescription": "Alle kjøretøy og deres servicehistorikk, notater, påminnelser, drivstofflogger og gjentakende fakturaer",
     "contentCustomers": "Kunder",
-    "contentCustomersDescription": "Alle kunderegistre. Kjoretoy knyttet til slettede kunder vil bli frakoblet.",
+    "contentCustomersDescription": "Alle kunderegistre. Kjøretøy knyttet til slettede kunder vil bli frakoblet.",
     "contentQuotes": "Tilbud",
     "contentQuotesDescription": "Alle tilbud og deres linjer",
     "contentInventory": "Inventar",
@@ -357,7 +357,7 @@
     "fullAccess": "Full tilgang",
     "permissionCount": "{count} tillatelse",
     "permissionCountPlural": "{count} tillatelser",
-    "noCustomRoles": "Ingen egendefinerte roller enna. Opprett en for a definere detaljerte tillatelser for teammedlemmer.",
+    "noCustomRoles": "Ingen egendefinerte roller ennå. Opprett en for å definere detaljerte tillatelser for teammedlemmer.",
     "presetAll": "Alle",
     "presetViewOnly": "Kun visning",
     "presetWriteAll": "Les og skriv",
@@ -491,7 +491,7 @@
   },
   "templates": {
     "title": "Maler",
-    "invoiceDescription": "Tilpass utseendet pa PDF-fakturaer og tilbud.",
+    "invoiceDescription": "Tilpass utseendet på PDF-fakturaer og tilbud.",
     "inspectionsDescription": "Administrer inspeksjonssjekklister og flerpunktsmaler.",
     "smsDescription": "Tilpass SMS-meldingene som sendes til kunder.",
     "tabs": {
@@ -501,8 +501,8 @@
       "sms": "SMS",
       "layout": "Oppsett"
     },
-    "presets": "Malforandsvisninger",
-    "primaryColor": "Primarfarge",
+    "presets": "Malforhåndsvisninger",
+    "primaryColor": "Primærfarge",
     "fontAndLayout": "Skrift og layout",
     "fontFamily": "Skriftfamilie",
     "helveticaDefault": "Helvetica (Standard)",
@@ -513,10 +513,10 @@
     "standard": "Standard",
     "compact": "Kompakt",
     "modern": "Moderne",
-    "preview": "{name} forhandsvisning",
+    "preview": "{name} forhåndsvisning",
     "billTo": "Faktureres til",
     "preparedFor": "Utarbeidet for",
-    "vehicle": "Kjoretoy",
+    "vehicle": "Kjøretøy",
     "part": "Del",
     "qty": "Ant.",
     "price": "Pris",
@@ -538,24 +538,24 @@
     "quotationTemplateSaved": "Tilbudsmalinnstillinger lagret",
     "failedSave": "Kunne ikke lagre innstillinger",
     "smsTemplates": "SMS-meldingsmaler",
-    "smsTemplatesDescription": "Tilpass tekstmeldingene som sendes til kunder. Bruk variabler som <code>'{companyName}'</code> for a sette inn dynamiske verdier.",
+    "smsTemplatesDescription": "Tilpass tekstmeldingene som sendes til kunder. Bruk variabler som <code>'{companyName}'</code> for å sette inn dynamiske verdier.",
     "reset": "Tilbakestill",
     "invoiceReady": "Faktura klar",
-    "invoiceReadyDescription": "Sendes nar en faktura deles med en kunde.",
+    "invoiceReadyDescription": "Sendes når en faktura deles med en kunde.",
     "quoteReady": "Tilbud klart",
-    "quoteReadyDescription": "Sendes nar et tilbud deles med en kunde.",
+    "quoteReadyDescription": "Sendes når et tilbud deles med en kunde.",
     "inspectionReady": "Inspeksjon klar",
-    "inspectionReadyDescription": "Sendes nar en inspeksjonsrapport deles med en kunde.",
+    "inspectionReadyDescription": "Sendes når en inspeksjonsrapport deles med en kunde.",
     "statusInProgress": "Status: Under arbeid",
-    "statusInProgressDescription": "Sendes nar en arbeidsordre endres til Under arbeid.",
-    "statusWaitingParts": "Status: Venter pa deler",
-    "statusWaitingPartsDescription": "Sendes nar status endres til Venter pa deler.",
+    "statusInProgressDescription": "Sendes når en arbeidsordre endres til Under arbeid.",
+    "statusWaitingParts": "Status: Venter på deler",
+    "statusWaitingPartsDescription": "Sendes når status endres til Venter på deler.",
     "statusReady": "Status: Klar for henting",
-    "statusReadyDescription": "Sendes nar status endres til Klar.",
-    "statusCompleted": "Status: Fullfort",
-    "statusCompletedDescription": "Sendes nar status endres til Fullfort.",
+    "statusReadyDescription": "Sendes når status endres til Klar.",
+    "statusCompleted": "Status: Fullført",
+    "statusCompletedDescription": "Sendes når status endres til Fullført.",
     "paymentReceived": "Betaling mottatt",
-    "paymentReceivedDescription": "Sendes nar en betaling registreres for en faktura.",
+    "paymentReceivedDescription": "Sendes når en betaling registreres for en faktura.",
     "saveSmsTemplates": "Lagre SMS-maler",
     "smsTemplateSaved": "SMS-malinnstillinger lagret",
     "layoutTitle": "Fakturaoppsett",
@@ -575,9 +575,9 @@
     },
     "colorPresets": {
       "amber": "Rav",
-      "blue": "Bla",
+      "blue": "Blå",
       "emerald": "Smaragd",
-      "red": "Rod",
+      "red": "Rød",
       "purple": "Lilla",
       "slate": "Skifer",
       "rose": "Rosa",
@@ -843,7 +843,7 @@
   },
   "maintenance": {
     "title": "Predikert vedlikehold",
-    "description": "Forutsi hvert kjoretoyes navarende kilometerstand fra servicehistorikken og vis kjoretoy som trenger eller narmer seg neste service.",
+    "description": "Forutsi hvert kjøretøys nåværende kilometerstand fra servicehistorikken og vis kjøretøy som trenger eller nærmer seg neste service.",
     "enablePredicted": "Aktiver predikert vedlikehold",
     "enablePredictedHint": "Vis prediksjoner pa kjoretoysdetaljer og dashbord",
     "serviceInterval": "Serviceintervall ({unit})",
@@ -856,8 +856,18 @@
   "appearance": {
     "title": "Utseende",
     "description": "Tilpass hvordan Torqvoice ser ut og foler seg.",
-    "darkMode": "Mork modus",
-    "darkModeHint": "Bytt mellom lyse og morke temaer",
+    "themeLabel": "Tema",
+    "themeHint": "Velg fargetema for appen. Valget lagres på denne enheten.",
+    "themes": {
+      "light": "Lys",
+      "dark": "Mørk",
+      "graphite": "Grafitt",
+      "ocean": "Hav",
+      "forest": "Skog",
+      "midnight": "Midnatt",
+      "carbon": "Karbon",
+      "system": "System"
+    },
     "dateTimeTitle": "Dato og tid",
     "dateTimeDescription": "Konfigurer hvordan datoer og tidspunkter vises i applikasjonen.",
     "dateFormat": "Datoformat",
@@ -887,8 +897,8 @@
     "optSettingsDesc": "Verkstedinfo, fakturaoppsett, betalingsleverandorer",
     "optCustomers": "Kunder",
     "optCustomersDesc": "Kundeposter og kontaktinformasjon",
-    "optVehicles": "Kjoretoy og servicedata",
-    "optVehiclesDesc": "Kjoretoy, notater, drivstofflogger, paminnelser, servicedata",
+    "optVehicles": "Kjøretøy og servicedata",
+    "optVehiclesDesc": "Kjøretøy, notater, drivstofflogger, påminnelser, servicedata",
     "optQuotes": "Tilbud",
     "optQuotesDesc": "Tilbud med deler og arbeid",
     "optInventory": "Inventar",
@@ -901,6 +911,8 @@
     "optAuditLogsDesc": "Aktivitets- og endringshistorikk",
     "optSmsMessages": "SMS-meldinger",
     "optSmsMessagesDesc": "Sendte og mottatte SMS-meldinger",
+    "optScheduledMessages": "Planlagte meldinger",
+    "optScheduledMessagesDesc": "Meldinger i kø og gjentakende meldinger som venter på å bli sendt",
     "optNotifications": "Varsler",
     "optNotificationsDesc": "Systemvarsler",
     "optCustomFields": "Egendefinerte felter",
@@ -909,7 +921,7 @@
     "optFilesDesc": "Bilder, servicevedlegg, logo",
     "filesWarning": "Inkluderer opplastede filer — sikkerhetskopi kan bli storre",
     "downloadBackup": "Last ned sikkerhetskopi",
-    "exportComplete": "Eksport fullfort",
+    "exportComplete": "Eksport fullført",
     "exportCompleteMessage": "Sikkerhetskopifilen din er lastet ned.",
     "exportFailed": "Eksport mislyktes",
     "exportFailedMessage": "Kunne ikke eksportere dataene dine. Vennligst prov igjen.",
@@ -917,7 +929,7 @@
     "importWarning": "Importering vil <bold>erstatte alle eksisterende data</bold> med innholdet i sikkerhetskopifilen. Denne handlingen kan ikke angres.",
     "importFileHint": "Stotter bade .zip (v2) og .json (v1) sikkerhetskopifiler.",
     "uploadRestore": "Last opp og gjenopprett",
-    "importComplete": "Import fullfort",
+    "importComplete": "Import fullført",
     "importCompleteMessage": "Alle data er gjenopprettet fra sikkerhetskopifilen.",
     "importFailed": "Import mislyktes",
     "importFromOther": "Importer fra andre tjenester",
@@ -930,11 +942,11 @@
     "lubelogStep4": "Last opp den nedlastede zip-filen nedenfor",
     "lubelogAddNote": "Dette vil <bold>legge til data ved siden av</bold> eksisterende poster — ingenting vil bli slettet.",
     "lubelogImported": "Hva som importeres:",
-    "lubelogVehicles": "Kjoretoy",
+    "lubelogVehicles": "Kjøretøy",
     "lubelogServiceRecords": "Servicedata med vedlegg",
     "lubelogNotes": "Notater",
     "lubelogFileHint": "Filer opp til 200MB stottet.",
-    "lubelogImportComplete": "LubeLog-import fullfort",
+    "lubelogImportComplete": "LubeLog-import fullført",
     "cancel": "Avbryt",
     "import": "Importer",
     "invoiceNinjaTitle": "Importer fra Invoice Ninja",
@@ -951,7 +963,7 @@
     "invoiceNinjaDocuments": "Dokumenter og vedlegg",
     "invoiceNinjaPayments": "Betalinger",
     "invoiceNinjaFileHint": "Last opp en Invoice Ninja zip-eksportfil. Filer opp til 200MB stottet.",
-    "invoiceNinjaImportComplete": "Invoice Ninja-import fullfort",
+    "invoiceNinjaImportComplete": "Invoice Ninja-import fullført",
     "backupStatus": {
       "title": "Databeskyttelse",
       "description": "Vi tar dataene dine på alvor. Alle organisasjonens data, inkludert kunder, kjøretøy, arbeidsordrer, fakturaer og opplastede filer, sikkerhetskopieres automatisk hver time. Sikkerhetskopiene beskyttes med AES-256-kryptering før de forlater infrastrukturen vår og lagres på et separat, sikkert sted, slik at ingen utenforstående kan lese dem.",
@@ -1179,7 +1191,7 @@
   },
   "ai": {
     "title": "AI-assistent",
-    "readMore": "Read More",
+    "readMore": "Les mer",
     "description": "Konfigurer AI for automatisk generering av servicenotater og oppsummering av kjøretøyhistorikk.",
     "enableLabel": "Aktiver AI",
     "enableHint": "Bruk AI-drevne funksjoner i applikasjonen",

+ 47 - 1
messages/nb/share.json

@@ -149,7 +149,53 @@
     "downloadPdf": "Last ned PDF",
     "notes": "Notater",
     "quoteCancelled": "Tilbudsforespørsel avbrutt",
-    "cancelFailed": "Kunne ikke avbryte forespørselen"
+    "cancelFailed": "Kunne ikke avbryte forespørselen",
+    "eu": {
+      "pass": "Ingen mangel",
+      "attention": "Mindre mangel",
+      "fail": "Vesentlig mangel",
+      "dangerous": "Farlig mangel",
+      "not_inspected": "Ikke kontrollert"
+    },
+    "basic": {
+      "pass": "Godkjent",
+      "attention": "Merknad",
+      "fail": "Ikke godkjent",
+      "dangerous": "Farlig",
+      "not_inspected": "Ikke kontrollert"
+    },
+    "result": {
+      "pass": "Godkjent",
+      "pass_minor": "Godkjent med mindre mangler",
+      "fail": "Ikke godkjent — vesentlige mangler",
+      "fail_dangerous": "Ikke godkjent — farlige mangler",
+      "incomplete": "Ikke fullført"
+    },
+    "resultDetail": {
+      "pass": "Det ble ikke funnet mangler.",
+      "pass_minor": "Kjøretøyet er godkjent. Utbedre de mindre manglene uten unødig opphold.",
+      "fail": "Kjøretøyet er ikke godkjent. Manglene må utbedres og kjøretøyet kontrolleres på nytt.",
+      "fail_dangerous": "Kjøretøyet må ikke brukes på offentlig vei før de farlige manglene er utbedret.",
+      "incomplete": "Denne kontrollen pågår fortsatt."
+    },
+    "testDetails": "Kontrollopplysninger",
+    "testDate": "Kontrolldato",
+    "certificateNumber": "Sertifikatnummer",
+    "vehicleCategory": "Kjøretøygruppe",
+    "inspector": "Kontrollør",
+    "testLocation": "Kontrollsted",
+    "nextTestDue": "Neste kontroll",
+    "vesselLabel": "Fartøy",
+    "plateLabel": "Kjennemerke",
+    "odometerLabel": "Kilometerstand",
+    "engineHoursLabel": "Motortimer",
+    "summary": "Sammendrag",
+    "progressLabel": "{graded} punkter vurdert",
+    "limit": "Grenseverdi",
+    "viewPhoto": "Se bilde",
+    "deficienciesFound": "Mangler funnet ({count})",
+    "allResults": "Alle resultater",
+    "privacyNotice": "Denne rapporten deles med deg av verkstedet som utførte kontrollen. Alle som har lenken kan se den, så ikke send den videre. Ta kontakt med verkstedet for å trekke tilbake lenken eller få slettet opplysningene dine."
   },
   "terms": {
     "title": "Salgsbetingelser (Salgsvilkår)",

+ 9 - 8
messages/nb/statusReport.json

@@ -55,6 +55,7 @@
   },
   "list": {
     "title": "Statusrapporter",
+    "readMore": "Les mer",
     "newReport": "Ny statusrapport",
     "empty": "Ingen statusrapporter ennå",
     "emptyDescription": "Opprett en statusrapport for å oppdatere kunden om kjøretøyets tilstand.",
@@ -76,17 +77,17 @@
     "deleteTitle": "Slett statusrapport",
     "deleteFailed": "Kunne ikke slette statusrapport",
     "cancel": "Avbryt",
-  "feedback": "Tilbakemelding",
-  "hasComment": "Mottatt",
-  "noFeedback": "Ingen tilbakemelding ennå",
-  "sentAt": "Sendt",
-  "sentVia": "Sendt via",
-  "messageLabel": "Melding",
-  "videoLabel": "Video"
+    "feedback": "Tilbakemelding",
+    "hasComment": "Mottatt",
+    "noFeedback": "Ingen tilbakemelding ennå",
+    "sentAt": "Sendt",
+    "sentVia": "Sendt via",
+    "messageLabel": "Melding",
+    "videoLabel": "Video"
   },
   "notify": {
     "defaultMessage": "Hei {name}, vi har en statusoppdatering på din {vehicle}. Se den her: {url}",
     "emailSubject": "Statusoppdatering for kjøretøy - {vehicle}",
-  "viewReport": "Se rapporten her: {url}"
+    "viewReport": "Se rapporten her: {url}"
   }
 }

+ 44 - 44
messages/nb/vehicles.json

@@ -3,13 +3,13 @@
     "active": "Aktive",
     "archived": "Arkivert",
     "searchPlaceholder": "Sok etter skilt, merke, modell, VIN...",
-    "addVehicle": "Legg til kjoretoy",
-    "emptySearch": "Ingen kjoretoy samsvarer med soket ditt.",
-    "emptyArchived": "Ingen arkiverte kjoretoy.",
-    "empty": "Ingen kjoretoy enna.",
+    "addVehicle": "Legg til kjøretøy",
+    "emptySearch": "Ingen kjøretøy samsvarer med søket ditt.",
+    "emptyArchived": "Ingen arkiverte kjøretøy.",
+    "empty": "Ingen kjøretøy ennå.",
     "table": {
       "plate": "Skilt",
-      "vehicle": "Kjoretoy",
+      "vehicle": "Kjøretøy",
       "customer": "Kunde",
       "mileage": "Kilometerstand",
       "mileageMarine": "Motortimer",
@@ -19,14 +19,14 @@
     "archive": "Arkiver",
     "unarchive": "Gjenopprett",
     "delete": "Slett",
-    "deleteTitle": "Slett kjoretoy",
-    "deleteDescription": "Slette {name}? Dette vil fjerne alle tilknyttede serviceoppforinger og notater.",
-    "unarchiveTitle": "Gjenopprett kjoretoy",
-    "unarchiveDescription": "Gjenopprette {name} til listen over aktive kjoretoy?",
-    "vehicleUnarchived": "Kjoretoy gjenopprettet",
-    "unarchiveError": "Kunne ikke gjenopprette kjoretoy",
-    "deleteError": "Kunne ikke slette kjoretoy",
-    "error": "Kunne ikke laste kjoretoy",
+    "deleteTitle": "Slett kjøretøy",
+    "deleteDescription": "Slette {name}? Dette vil fjerne alle tilknyttede serviceoppføringer og notater.",
+    "unarchiveTitle": "Gjenopprett kjøretøy",
+    "unarchiveDescription": "Gjenopprette {name} til listen over aktive kjøretøy?",
+    "vehicleUnarchived": "Kjøretøy gjenopprettet",
+    "unarchiveError": "Kunne ikke gjenopprette kjøretøy",
+    "deleteError": "Kunne ikke slette kjøretøy",
+    "error": "Kunne ikke laste kjøretøy",
     "viewTable": "Table view",
     "viewGrid": "Grid view",
     "viewLargeGrid": "Large grid view",
@@ -34,13 +34,13 @@
   },
   "detail": {
     "vehicleArchived": "Dette kjoretoyet er arkivert",
-    "backToVehicles": "Tilbake til kjoretoy",
+    "backToVehicles": "Tilbake til kjøretøy",
     "newWorkOrder": "Ny arbeidsordre",
-    "editVehicle": "Rediger kjoretoy",
+    "editVehicle": "Rediger kjøretøy",
     "unarchive": "Gjenopprett",
     "archive": "Arkiver",
     "delete": "Slett",
-    "notFound": "Kjoretoy ikke funnet",
+    "notFound": "Kjøretøy ikke funnet",
     "predictedKm": "Beregnet km",
     "predictedMileage": "Beregnet kilometerstand",
     "predictedHours": "Beregnede Timer",
@@ -63,12 +63,12 @@
     "noteDeleteError": "Kunne ikke slette",
     "reminderDeleted": "Paminnelse slettet",
     "reminderDeleteError": "Kunne ikke slette",
-    "vehicleUnarchived": "Kjoretoy gjenopprettet",
+    "vehicleUnarchived": "Kjøretøy gjenopprettet",
     "unarchiveError": "Kunne ikke gjenopprette",
-    "vehicleDeleted": "Kjoretoy slettet",
-    "vehicleDeleteError": "Kunne ikke slette kjoretoy",
-    "deleteTitle": "Slette kjoretoy?",
-    "deleteDescription": "Dette vil permanent slette {name} og alle tilknyttede serviceoppforinger, notater og paminnelser. Denne handlingen kan ikke angres.",
+    "vehicleDeleted": "Kjøretøy slettet",
+    "vehicleDeleteError": "Kunne ikke slette kjøretøy",
+    "deleteTitle": "Slette kjøretøy?",
+    "deleteDescription": "Dette vil permanent slette {name} og alle tilknyttede serviceoppføringer, notater og påminnelser. Denne handlingen kan ikke angres.",
     "edit": "Rediger",
     "aiSummary": "AI-sammendrag",
     "aiSummaryTitle": "Servicehistorikk-sammendrag",
@@ -103,28 +103,28 @@
   },
   "inspections": {
     "newInspection": "Ny inspeksjon",
-    "empty": "Ingen inspeksjoner enna",
+    "empty": "Ingen inspeksjoner ennå",
     "template": "Mal",
     "progress": "Fremdrift",
     "status": "Status",
     "date": "Dato",
-    "completed": "Fullfort",
+    "completed": "Fullført",
     "inProgress": "Under arbeid"
   },
   "reminders": {
     "active": "Aktive",
-    "completed": "Fullforte",
+    "completed": "Fullførte",
     "all": "Alle",
-    "addReminder": "Legg til paminnelse",
-    "emptyActive": "Ingen aktive paminnelser",
-    "emptyCompleted": "Ingen fullforte paminnelser",
-    "empty": "Ingen paminnelser enna",
+    "addReminder": "Legg til påminnelse",
+    "emptyActive": "Ingen aktive påminnelser",
+    "emptyCompleted": "Ingen fullførte påminnelser",
+    "empty": "Ingen påminnelser ennå",
     "overdue": "Forfalt",
     "dueSoon": "Forfaller snart",
     "due": "Forfaller {date}",
     "dueAt": "Forfaller ved {mileage} {unit}",
-    "editTitle": "Rediger paminnelse",
-    "addTitle": "Legg til paminnelse",
+    "editTitle": "Rediger påminnelse",
+    "addTitle": "Legg til påminnelse",
     "titleLabel": "Tittel *",
     "titlePlaceholder": "f.eks. Oljeskift",
     "descriptionLabel": "Beskrivelse",
@@ -132,9 +132,9 @@
     "dueDateLabel": "Forfallsdato",
     "dueMileageLabel": "Kilometerstand ved forfall",
     "dueMileagePlaceholder": "f.eks. 50000",
-    "reminderUpdated": "Paminnelse oppdatert",
-    "reminderCreated": "Paminnelse opprettet",
-    "saveError": "Kunne ikke {action} paminnelse",
+    "reminderUpdated": "Påminnelse oppdatert",
+    "reminderCreated": "Påminnelse opprettet",
+    "saveError": "Kunne ikke lagre påminnelse",
     "notifyLabel": "Varsle meg ved forfall",
     "notifyInApp": "Varsel i appen",
     "notifyEmail": "E-post"
@@ -168,8 +168,8 @@
         "none": "N/A"
       }
     },
-    "emptyFiltered": "Ingen serviceoppforinger samsvarer med filtrene dine.",
-    "empty": "Ingen serviceoppforinger enna.",
+    "emptyFiltered": "Ingen serviceoppføringer samsvarer med filtrene dine.",
+    "empty": "Ingen serviceoppføringer ennå.",
     "showing": "Viser {start}-{end} av {total}",
     "perPage": "per side",
     "page": "Side {page} av {totalPages}",
@@ -185,7 +185,7 @@
       "content": "Innhold",
       "date": "Dato"
     },
-    "empty": "Ingen notater enna.",
+    "empty": "Ingen notater ennå.",
     "pin": "Fest",
     "unpin": "Losgior",
     "delete": "Slett",
@@ -201,7 +201,7 @@
     "noteUpdated": "Notat oppdatert",
     "noteCreated": "Notat opprettet",
     "titleRequired": "Tittel og innhold er pakrevd",
-    "saveError": "Kunne ikke {action} notat",
+    "saveError": "Kunne ikke lagre notat",
     "openMenu": "Open menu",
     "firstPage": "First page",
     "previousPage": "Previous page",
@@ -276,8 +276,8 @@
     }
   },
   "form": {
-    "editTitle": "Rediger kjoretoy",
-    "addTitle": "Legg til nytt kjoretoy",
+    "editTitle": "Rediger kjøretøy",
+    "addTitle": "Legg til nytt kjøretøy",
     "photo": "Bilde",
     "clickToUpload": "Klikk for a laste opp et bilde",
     "imageFormats": "JPEG, PNG, WebP opptil 5 MB",
@@ -319,17 +319,17 @@
     "twoStroke": "Totakt",
     "vinMarine": "HIN",
     "licensePlateMarine": "Registreringsnummer",
-    "vehicleUpdated": "Kjoretoy oppdatert",
-    "vehicleAdded": "Kjoretoy lagt til",
-    "saveError": "Kunne ikke lagre kjoretoy"
+    "vehicleUpdated": "Kjøretøy oppdatert",
+    "vehicleAdded": "Kjøretøy lagt til",
+    "saveError": "Kunne ikke lagre kjøretøy"
   },
   "archiveDialog": {
-    "title": "Arkiver kjoretoy",
+    "title": "Arkiver kjøretøy",
     "description": "Arkivere <span>{name}</span>? Det vil bli skjult fra hovedlisten, men all servicehistorikk vil bli bevart.",
     "reasonLabel": "Arsak (valgfritt)",
     "reasonPlaceholder": "f.eks. Solgt, kondemnert, tatt ut av drift...",
     "archived": "{name} arkivert",
-    "archiveError": "Kunne ikke arkivere kjoretoy"
+    "archiveError": "Kunne ikke arkivere kjøretøy"
   },
   "serviceRecords": {
     "firstPage": "First page",

+ 11 - 1
messages/nl/audit.json

@@ -98,6 +98,16 @@
     "webhook_create": "Webhook aangemaakt",
     "webhook_update": "Webhook bijgewerkt",
     "webhook_delete": "Webhook verwijderd",
-    "webhook_rotateSecret": "Webhook-geheim geroteerd"
+    "webhook_rotateSecret": "Webhook-geheim geroteerd",
+    "inspection_reopen": "Inspectie heropend",
+    "inspectionTemplate_import": "Inspectiesjabloon geïmporteerd",
+    "scheduled_message_create": "Gepland bericht aangemaakt",
+    "scheduled_message_update": "Gepland bericht bijgewerkt",
+    "scheduled_message_delete": "Gepland bericht verwijderd",
+    "scheduled_message_cancel": "Gepland bericht geannuleerd",
+    "scheduled_message_send_now": "Gepland bericht verzonden",
+    "settings_applyTaxRate": "Btw-tarief toegepast",
+    "settings_convertToExclusive": "Prijzen omgezet naar exclusief btw",
+    "settings_convertToInclusive": "Prijzen omgezet naar inclusief btw"
   }
 }

+ 4 - 4
messages/nl/billing.json

@@ -79,9 +79,9 @@
     "failedDelete": "Verwijderen mislukt",
     "processed": "{count} factuur/facturen verwerkt",
     "failedProcess": "Verwerking mislukt",
-    "pause": "Pause",
-    "resume": "Resume",
-    "delete": "Delete",
-    "removeRow": "Remove row"
+    "pause": "Pauzeren",
+    "resume": "Hervatten",
+    "delete": "Verwijderen",
+    "removeRow": "Rij verwijderen"
   }
 }

+ 16 - 3
messages/nl/calendar.json

@@ -33,7 +33,8 @@
   "filters": {
     "services": "Diensten",
     "reminders": "Herinneringen",
-    "quotes": "Offertes"
+    "quotes": "Offertes",
+    "messages": "Berichten"
   },
   "selectVehicle": "Selecteer voertuig voor werkorder",
   "dateChoice": {
@@ -43,6 +44,15 @@
     "useToday": "Use today"
   },
   "more": "+ {count} meer",
+  "monthTotal": "{count} items deze maand",
+  "contextMenu": {
+    "newWorkOrder": "Nieuwe werkorder",
+    "newReminder": "Nieuwe herinnering",
+    "newQuote": "Nieuwe offerte",
+    "openEvent": "Openen ({count})",
+    "hint": "Tip: klik met de rechtermuisknop op een dag voor acties",
+    "scheduleMessage": "Bericht plannen"
+  },
   "events": {
     "status": {
       "completed": "Voltooid",
@@ -54,12 +64,15 @@
       "draft": "Concept",
       "done": "Klaar",
       "overdue": "Achterstallig",
-      "upcoming": "Aanstaand"
+      "upcoming": "Aanstaand",
+      "failed": "Mislukt",
+      "queued": "In wachtrij"
     },
     "type": {
       "service": "Dienst",
       "reminder": "Herinnering",
-      "quote": "Offerte"
+      "quote": "Offerte",
+      "message": "Bericht"
     },
     "noEvents": "Geen evenementen",
     "selectDay": "Selecteer een dag met evenementen of maak een nieuwe werkorder aan."

+ 24 - 0
messages/nl/common.json

@@ -52,5 +52,29 @@
     "updated": "Torqvoice is bijgewerkt naar {version}",
     "whatsNew": "Bekijk wat er nieuw is",
     "dismiss": "Sluiten"
+  },
+  "pagination": {
+    "showing": "{start}–{end} van {total} weergegeven",
+    "perPage": "per pagina",
+    "pageOf": "Pagina {page} van {pages}",
+    "first": "Eerste pagina",
+    "previous": "Vorige pagina",
+    "next": "Volgende pagina",
+    "last": "Laatste pagina"
+  },
+  "shared": {
+    "close": "Sluiten",
+    "viewPlans": "Abonnementen bekijken",
+    "manageLicense": "Licentie beheren",
+    "installOwn": "Installeer je eigen",
+    "install": "Installeren",
+    "installApp": "App installeren",
+    "installTorqvoice": "Torqvoice installeren",
+    "dismiss": "Sluiten",
+    "useCamera": "Camera gebruiken",
+    "enterManually": "Handmatig invoeren",
+    "enterBarcode": "Barcode invoeren…",
+    "scanHint": "Richt uw camera op een barcode of voer hem handmatig in",
+    "iosInstallHint": "Tik op Deel > Zet op beginscherm"
   }
 }

+ 396 - 0
messages/nl/inspections.json

@@ -0,0 +1,396 @@
+{
+  "grades": {
+    "eu": {
+      "pass": "Geen gebrek",
+      "attention": "Klein gebrek",
+      "fail": "Groot gebrek",
+      "dangerous": "Gevaarlijk gebrek",
+      "not_inspected": "Niet gekeurd"
+    },
+    "basic": {
+      "pass": "Goedgekeurd",
+      "attention": "Aandacht",
+      "fail": "Afgekeurd",
+      "dangerous": "Gevaarlijk",
+      "not_inspected": "Niet gekeurd"
+    },
+    "short": {
+      "pass": "OK",
+      "attention": "Klein",
+      "fail": "Groot",
+      "dangerous": "Gevaarlijk",
+      "not_inspected": "–"
+    },
+    "hint": {
+      "pass": "Voldoet aan de eisen. Niets te melden.",
+      "attention": "Geen wezenlijk effect op de veiligheid. Voertuig is goedgekeurd; herstel wanneer het uitkomt.",
+      "fail": "Kan de veiligheid schaden of het milieu belasten. Voertuig is afgekeurd; herstellen en opnieuw laten keuren.",
+      "dangerous": "Direct en onmiddellijk gevaar voor de verkeersveiligheid. Het voertuig mag niet rijden.",
+      "not_inspected": "Dit punt is niet uitgevoerd."
+    }
+  },
+  "results": {
+    "pass": "Goedgekeurd",
+    "pass_minor": "Goedgekeurd met kleine gebreken",
+    "fail": "Afgekeurd — grote gebreken",
+    "fail_dangerous": "Afgekeurd — gevaarlijke gebreken",
+    "incomplete": "Niet afgerond",
+    "detail": {
+      "pass": "Er zijn geen gebreken vastgesteld.",
+      "pass_minor": "Het voertuig is goedgekeurd. Herstel de kleine gebreken zonder onnodig uitstel.",
+      "fail": "Het voertuig is afgekeurd. De gebreken moeten worden hersteld en het voertuig opnieuw gekeurd.",
+      "fail_dangerous": "Het voertuig mag niet op de openbare weg worden gebruikt totdat de gevaarlijke gebreken zijn hersteld.",
+      "incomplete": "Deze keuring loopt nog."
+    }
+  },
+  "page": {
+    "back": "Inspecties",
+    "statusInProgress": "Loopt",
+    "statusCompleted": "Afgerond",
+    "complete": "Afronden",
+    "reopen": "Heropenen",
+    "share": "Delen",
+    "save": "Opslaan",
+    "saving": "Opslaan…",
+    "savedAt": "Opgeslagen {time}",
+    "savesAsYouGo": "Slaat op tijdens het werk",
+    "saveFailed": "Sommige wijzigingen zijn niet opgeslagen",
+    "allSaved": "Alle wijzigingen zijn opgeslagen",
+    "moreActions": "Meer acties",
+    "downloadCertificate": "Keuringsrapport downloaden",
+    "manageTemplates": "Sjablonen beheren",
+    "delete": "Verwijderen",
+    "createWorkOrder": "Werkorder aanmaken",
+    "viewWorkOrder": "Werkorder bekijken",
+    "createQuote": "Offerte aanmaken",
+    "viewQuote": "Offerte bekijken",
+    "needsDefect": "Beschikbaar zodra een gebrek is vastgelegd",
+    "workOrderRaised": "Werkorder {number} op {date} vanuit deze inspectie aangemaakt",
+    "open": "Openen",
+    "quoteCreated": "Offerte aangemaakt door {name} op {date}",
+    "quoteRequested": "De klant vroeg een offerte voor {count} punt(en)",
+    "stillToGrade": "{count} van {total} punten moeten nog beoordeeld worden.",
+    "progress": "Voortgang",
+    "checksGraded": "punten beoordeeld",
+    "progressLabel": "{graded} van {total} punten beoordeeld: {pass} geen gebrek, {attention} klein, {fail} groot, {dangerous} gevaarlijk.",
+    "sections": "Groepen",
+    "graded": "{graded}/{total} beoordeeld",
+    "vehicle": "Voertuig",
+    "vessel": "Vaartuig",
+    "customer": "Klant",
+    "plate": "Kenteken",
+    "registration": "Registratie",
+    "template": "Sjabloon",
+    "scaleEu": "Beoordeeld op de EU-gebrekenschaal uit richtlijn 2014/45/EU.",
+    "scaleBasic": "Beoordeeld goedgekeurd / aandacht / afgekeurd.",
+    "country": "Land: {code}.",
+    "manageInspectionTemplates": "Inspectiesjablonen beheren",
+    "readMore": "Meer lezen",
+    "odometer": "Kilometerstand",
+    "engineHours": "Draaiuren",
+    "completeTitle": "Deze inspectie afronden?",
+    "completeBody": "De punten worden bij afronding vergrendeld en de uitkomst wordt “{result}”.",
+    "completeBlocked": "{count} punt(en) die het sjabloon als verplicht markeert, staan nog open.",
+    "completeUngraded": "{count} punt(en) zijn niet beoordeeld.",
+    "completeDangerous": "{count} gevaarlijk(e) gebrek(en) vastgelegd. Het voertuig mag niet de openbare weg op.",
+    "reopenTitle": "Deze inspectie heropenen?",
+    "reopenBody": "De punten worden weer bewerkbaar en de uitkomst gaat terug naar loopt. Keurmeester, certificaatnummer en volgende keuring blijven behouden.",
+    "reopenShared": "De klantlink blijft actief en laat zien hoe de uitkomst verandert terwijl u werkt. Een al gedownload rapport houdt de oude uitkomst.",
+    "deleteTitle": "Deze inspectie verwijderen?",
+    "deleteBody": "Hiermee worden de inspectie, de beoordelingen, notities en foto's definitief verwijderd. Dit kan niet ongedaan worden gemaakt.",
+    "cancel": "Annuleren",
+    "completed": "Inspectie afgerond",
+    "reopened": "Inspectie heropend",
+    "deleted": "Inspectie verwijderd",
+    "completeFailed": "Inspectie kon niet worden afgerond",
+    "reopenFailed": "Inspectie kon niet worden heropend",
+    "deleteFailed": "Inspectie kon niet worden verwijderd",
+    "quoteFailed": "Offerte kon niet worden aangemaakt",
+    "workOrderFailed": "Werkorder kon niet worden aangemaakt"
+  },
+  "item": {
+    "required": "(verplicht)",
+    "saving": "Opslaan",
+    "addNote": "Notitie toevoegen",
+    "hideNote": "Notitie verbergen",
+    "addPhoto": "Foto of video toevoegen aan {name}",
+    "notesFor": "Notities voor {name}",
+    "describeDefect": "Beschrijf het gebrek — dit komt op het rapport",
+    "optionalNote": "Notitie toevoegen (optioneel)",
+    "notesRequired": "Beschrijf het gebrek voordat deze beoordeling wordt opgeslagen.",
+    "photoRequired": "Hier is een foto van het gebrek vereist. De inspectie kan pas worden afgerond als er een is toegevoegd.",
+    "reading": "Meetwaarde",
+    "readingUnit": "Meetwaarde ({unit})",
+    "limit": "Grenswaarde: {range}",
+    "recordedValue": "Vastgelegde waarde",
+    "answer": "Antwoord",
+    "selectAnswer": "Kies een antwoord",
+    "viewPhoto": "Foto {index} van {name} op volledige grootte bekijken",
+    "photoAlt": "{name}, foto {index}",
+    "removePhoto": "Foto {index} van {name} verwijderen",
+    "clearTitle": "Deze beoordeling wissen?",
+    "clearBody": "De notitie bij “{name}” wordt verwijderd en het punt gaat terug naar niet gekeurd.",
+    "clear": "Wissen",
+    "cancel": "Annuleren",
+    "saveFailed": "Dit punt kon niet worden opgeslagen",
+    "uploadFailed": "Uploaden mislukt",
+    "uploadFailedFor": "{name} kon niet worden geüpload"
+  },
+  "suggestions": {
+    "title": "Veelvoorkomende gebreken",
+    "add": "“{text}” toevoegen en beoordelen als {grade}",
+    "more": "Meer ({count})",
+    "search": "Zoek in gebreksomschrijvingen",
+    "empty": "Geen passende omschrijving.",
+    "source": {
+      "workshop": "Uw werkplaats",
+      "history": "Eerder gebruikt",
+      "regulation": "Richtlijn 2014/45/EU",
+      "general": "Algemeen"
+    }
+  },
+  "media": {
+    "viewer": "Afbeelding {index} van {total}: {caption}",
+    "close": "Afbeeldingsweergave sluiten",
+    "previous": "Vorige afbeelding",
+    "next": "Volgende afbeelding"
+  },
+  "certificate": {
+    "title": "Gegevens keuringsrapport",
+    "description": "Vereist op een keuringsrapport volgens richtlijn 2014/45/EU, bijlage IV.",
+    "inspector": "Keurmeester",
+    "notRecorded": "Niet vastgelegd",
+    "addTechnician": "Monteur toevoegen…",
+    "recordedAs": "Vastgelegd als {name}",
+    "vehicleCategory": "Voertuigcategorie",
+    "mileageAtTest": "{label} op het moment van keuring",
+    "reportReference": "Rapportreferentie",
+    "reportReferenceHelp": "Uw eigen referentie voor dit rapport. Bent u een erkende keuringsinstantie die een officieel keuringsrapport afgeeft, vul dan hier het nummer in zodat beide overeenkomen. Laat het anders leeg.",
+    "optional": "Optioneel",
+    "placeOfTest": "Plaats van keuring",
+    "placeholderAddress": "Keuringsstation of werkplaatsadres",
+    "fromSettings": "Uit uw werkplaatsinstellingen.",
+    "change": "Wijzigen",
+    "differsFromWorkshop": "Wijkt af van uw werkplaatsadres.",
+    "useWorkshopAddress": "Werkplaatsadres gebruiken",
+    "noWorkshopAddress": "Er is geen werkplaatsadres ingesteld.",
+    "addOne": "Er een toevoegen",
+    "nextTestDue": "Volgende keuring",
+    "notSet": "Niet ingesteld",
+    "intervalGroup": "Stel de volgende keuringsdatum in vanaf de datum van deze keuring",
+    "intervalHelp": "Gerekend vanaf de datum van deze keuring. Twee jaar is het EU-uitgangspunt voor personenauto's en lichte bedrijfsauto's; controleer welk interval in uw land geldt.",
+    "months6": "6 maanden",
+    "years1": "1 jaar",
+    "years2": "2 jaar",
+    "years3": "3 jaar",
+    "years4": "4 jaar",
+    "unsaved": "Niet-opgeslagen wijzigingen",
+    "saveDetails": "Gegevens opslaan",
+    "saved": "Gegevens opgeslagen",
+    "saveFailed": "De gegevens konden niet worden opgeslagen",
+    "addTechnicianTitle": "Monteur toevoegen",
+    "addTechnicianBody": "Deze persoon komt op de werkplaatslijst en kan zowel werk als inspecties toegewezen krijgen.",
+    "technicianName": "Naam",
+    "technicianPlaceholder": "bijv. Anna Berg",
+    "addAndSelect": "Toevoegen en selecteren",
+    "technicianAdded": "{name} toegevoegd en geselecteerd",
+    "technicianFailed": "De monteur kon niet worden toegevoegd",
+    "cancel": "Annuleren"
+  },
+  "templates": {
+    "title": "Inspectiesjablonen",
+    "description": "De checklists die uw monteurs doorlopen. Maak er één per land, per voertuigtype of per dienst die u verkoopt.",
+    "import": "Importeren",
+    "browse": "Checklists doorzoeken",
+    "new": "Nieuw sjabloon",
+    "restoreBanner": "{count} kant-en-klare checklists zijn uit uw lijst verwijderd. U kunt ze terugzetten.",
+    "restore": "Terugzetten",
+    "restored": "{count} checklist(s) teruggezet",
+    "allPresent": "Alle checklists staan er al",
+    "restoreFailed": "De checklists konden niet worden toegevoegd",
+    "emptyTitle": "Nog geen sjablonen",
+    "emptyBody": "De kant-en-klare checklists, waaronder de periodieke EU-keuring, zijn allemaal verwijderd. Zet ze terug of bouw uw eigen vanaf nul.",
+    "restoreChecklists": "Checklists terugzetten",
+    "buildMyOwn": "Zelf bouwen",
+    "default": "Standaard",
+    "actionsFor": "Acties voor {name}",
+    "edit": "Bewerken",
+    "duplicate": "Dupliceren",
+    "export": "Exporteren…",
+    "delete": "Verwijderen",
+    "sections": "{count} groep(en)",
+    "checks": "{count} punt(en)",
+    "measured": "{count} gemeten",
+    "euScale": "EU-gebrekenschaal",
+    "basicScale": "Goedgekeurd / aandacht / afgekeurd",
+    "deleteTitle": "“{name}” verwijderen?",
+    "deleteBody": "Hiermee wordt het sjabloon definitief verwijderd. Al uitgevoerde inspecties houden hun eigen kopie van de checklist en worden niet geraakt.",
+    "deleted": "Sjabloon verwijderd",
+    "deleteFailed": "Sjabloon kon niet worden verwijderd",
+    "duplicated": "Sjabloon gedupliceerd",
+    "duplicateFailed": "Sjabloon kon niet worden gedupliceerd",
+    "cancel": "Annuleren",
+    "srSections": "Groepen",
+    "srChecks": "Punten",
+    "srMeasurements": "Metingen"
+  },
+  "presets": {
+    "title": "Beginnen met een sjabloon",
+    "description": "Elk sjabloon wordt als gewoon sjabloon naar uw werkplaats gekopieerd. Hernoem groepen, verplaats punten en pas elke grenswaarde aan uw land en uw apparatuur aan.",
+    "search": "Zoek op naam, land of standaard",
+    "searchLabel": "Sjablonen zoeken",
+    "inYourList": "In uw lijst",
+    "counts": "{sections} groepen · {checks} punten",
+    "noMatch": "Geen sjabloon komt overeen met “{query}”.",
+    "warning": "De wettelijke sjablonen bevatten de gangbare EU-grenswaarden. Controleer ze aan de hand van uw nationale regels voordat u een keuringsrapport afgeeft.",
+    "cancel": "Annuleren",
+    "add": "Sjabloon toevoegen",
+    "added": "Sjabloon toegevoegd. Pas het aan uw werkplaats aan.",
+    "addFailed": "Sjabloon kon niet worden toegevoegd",
+    "group": {
+      "regulatory": "Wettelijk",
+      "workshop": "Werkplaats",
+      "specialist": "Specialistisch"
+    },
+    "groupDescription": {
+      "regulatory": "Checklists voor de periodieke keuring, gebouwd op richtlijn 2014/45/EU.",
+      "workshop": "Algemene service- en verkoopchecklists die niet aan een regeling zijn gebonden.",
+      "specialist": "Checklists voor aandrijvingen en vaartuigen die een eigen procedure vragen."
+    },
+    "euScale": "EU-gebrekenschaal",
+    "basicScale": "Goedgekeurd / aandacht / afgekeurd"
+  },
+  "builder": {
+    "newTitle": "Nieuw sjabloon",
+    "editTitle": "Sjabloon bewerken",
+    "description": "Bouw de checklist die uw werkplaats echt gebruikt. Sleep om te herordenen en stel elk punt in om een beoordeling, een meting, een geschreven notitie of een vast antwoord vast te leggen.",
+    "name": "Naam",
+    "namePlaceholder": "bijv. Periodieke keuring",
+    "templateDescription": "Omschrijving",
+    "descriptionPlaceholder": "Waar deze checklist voor is en wanneer u hem gebruikt.",
+    "country": "Land",
+    "notCountrySpecific": "Niet landspecifiek",
+    "countryHelp": "Wordt op het rapport vastgelegd zodat een werkplaats die over de grens werkt haar checklists uit elkaar kan houden.",
+    "defectScale": "Gebrekenschaal",
+    "scaleEu": "Klein / groot / gevaarlijk (EU)",
+    "scaleBasic": "Goedgekeurd / aandacht / afgekeurd",
+    "scaleEuHelp": "De categorieën uit artikel 7, lid 2, van richtlijn 2014/45/EU. Een voertuig met uitsluitend kleine gebreken is nog steeds goedgekeurd.",
+    "scaleBasicHelp": "Een eenvoudige schaal met drie stappen voor servicechecklists die geen wettelijke keuring zijn.",
+    "defaultTemplate": "Standaardsjabloon",
+    "defaultHelp": "Vooraf geselecteerd wanneer een monteur een nieuwe inspectie start.",
+    "summary": "{sections} groep(en) · {checks} punt(en)",
+    "renumber": "Verwijzingen hernummeren",
+    "renumberHelp": "Nummert elke groep en elk punt op volgorde: 1, 1.1, 1.2, 2. Nieuwe regels krijgen bij toevoegen al een nummer, dus dit hebt u alleen nodig na het verplaatsen.",
+    "renumberWarning": "Deze checklist gebruikt verwijzingen naar regelgeving zoals 1.1.13. Hernummeren vervangt ze.",
+    "addSection": "Groep toevoegen",
+    "addCheck": "Punt toevoegen",
+    "ref": "Ref.",
+    "sectionName": "Groepsnaam, bijv. Reminrichting",
+    "sectionNote": "Optionele notitie boven de punten in deze groep",
+    "checkName": "Naam van het punt, bijv. Remvoeringen",
+    "reorderSection": "Groep {name} herordenen",
+    "reorderCheck": "Punt {name} herordenen",
+    "removeSection": "Groep {name} verwijderen",
+    "removeCheck": "Punt {name} verwijderen",
+    "duplicateCheck": "Punt {name} dupliceren",
+    "configure": "{name} instellen",
+    "hideSettings": "Instellingen voor {name} verbergen",
+    "howRecorded": "Hoe wordt het vastgelegd?",
+    "guidance": "Toelichting voor de monteur",
+    "guidancePlaceholder": "Wordt op het inspectieformulier onder de naam van het punt getoond.",
+    "measurement": "Meting",
+    "unit": "Eenheid",
+    "minimum": "Minimum",
+    "maximum": "Maximum",
+    "outOfRange": "Gebrek buiten het bereik",
+    "rangeHelp": "Laat een grens leeg voor een eenzijdige eis, bijvoorbeeld een minimum van 1,6 mm zonder maximum. Waarden buiten het bereik worden automatisch beoordeeld.",
+    "answers": "Antwoorden",
+    "answersHelp": "Scheid de antwoorden met komma's.",
+    "mustComplete": "Moet worden ingevuld",
+    "photoRequired": "Foto vereist wanneer een gebrek wordt vastgelegd",
+    "commonWording": "Veelgebruikte gebreksomschrijvingen",
+    "commonWordingHelp": "Eén omschrijving per regel. Deze worden hier als eerste aangeboden wanneer een monteur een gebrek vastlegt, vóór de ingebouwde teksten, zodat uw werkplaats het eens kan worden over de omschrijving.",
+    "inputType": {
+      "condition": "Gebrekbeoordeling",
+      "measurement": "Meting",
+      "text": "Vrije tekst",
+      "choice": "Keuze"
+    },
+    "inputHint": {
+      "condition": "De monteur beoordeelt het punt volgens de gebrekenschaal.",
+      "measurement": "Legt een getal met eenheid vast, automatisch beoordeeld tegen een bereik.",
+      "text": "Legt een geschreven waarneming vast, bijvoorbeeld een bandenmerk of foutcode.",
+      "choice": "De monteur kiest één antwoord uit een vaste lijst."
+    },
+    "cancel": "Annuleren",
+    "create": "Sjabloon aanmaken",
+    "saveChanges": "Wijzigingen opslaan",
+    "created": "Sjabloon aangemaakt",
+    "updated": "Sjabloon bijgewerkt",
+    "saveFailed": "Sjabloon kon niet worden opgeslagen",
+    "severityAttention": "Klein gebrek",
+    "severityFail": "Groot gebrek",
+    "severityDangerous": "Gevaarlijk gebrek",
+    "answersPlaceholder": "Volledig, Gedeeltelijk, Geen"
+  },
+  "packages": {
+    "exportTitle": "“{name}” exporteren",
+    "exportDescription": "Downloadt de hele checklist als bestand: groepen, punten, eenheden en grenswaarden. Iedereen die Torqvoice draait kan hem importeren.",
+    "includeWording": "Eigen gebreksomschrijvingen meesturen",
+    "includeWordingHelp": "De omschrijvingen die uw werkplaats aan punten heeft toegevoegd. Nuttig voor de ontvanger, maar het is vrije tekst die aan de werkbank is getypt en kan een klant, een collega of een lokale afspraak noemen. Uit, tenzij u ze hebt gelezen.",
+    "attributeTo": "Toeschrijven aan (optioneel)",
+    "attributePlaceholder": "bijv. Egeland Auto",
+    "attributeHelp": "Wordt in het bestand geschreven zodat wie het installeert ziet waar het vandaan komt. Er wordt niets uit uw account overgenomen.",
+    "download": "Downloaden",
+    "exported": "Sjabloon geëxporteerd",
+    "exportFailed": "Dit sjabloon kon niet worden geëxporteerd",
+    "importTitle": "Een checklist importeren",
+    "importDescription": "Voegt een checklist toe uit een Torqvoice-pakketbestand. Hij komt binnen als gewoon bewerkbaar sjabloon en vervangt nooit een bestaand sjabloon.",
+    "chooseFile": "Kies een pakketbestand",
+    "chooseAnother": "Kies een ander bestand",
+    "unreadable": "Dat bestand kon niet worden gelezen. Een Torqvoice-pakket is een .json-bestand dat uit een sjabloon is geëxporteerd.",
+    "from": "Van {author}",
+    "limitsWarning": "De grenswaarden in een gedeelde checklist zijn die van de auteur. Controleer ze aan de hand van uw nationale regels voordat u er iets uit afgeeft.",
+    "import": "Importeren",
+    "imported": "{count} sjabloon/sjablonen geïmporteerd",
+    "importFailed": "Dit pakket kon niet worden geïmporteerd",
+    "cancel": "Annuleren"
+  },
+  "list": {
+    "tabAll": "Alle",
+    "tabInProgress": "Loopt",
+    "tabCompleted": "Afgerond",
+    "search": "Inspecties zoeken…",
+    "new": "Nieuwe inspectie",
+    "empty": "Geen inspecties gevonden.",
+    "vehicle": "Voertuig",
+    "template": "Sjabloon",
+    "progress": "Voortgang",
+    "status": "Status",
+    "date": "Datum",
+    "statusInProgress": "Loopt",
+    "statusCompleted": "Afgerond"
+  },
+  "new": {
+    "title": "Nieuwe inspectie",
+    "vehicle": "Voertuig",
+    "searchVehicles": "Voertuigen zoeken…",
+    "loadingVehicles": "Voertuigen laden…",
+    "noVehicles": "Geen voertuigen gevonden.",
+    "template": "Sjabloon",
+    "selectTemplate": "Kies een sjabloon",
+    "manageTemplates": "Sjablonen beheren",
+    "cancel": "Annuleren",
+    "create": "Inspectie aanmaken",
+    "created": "Inspectie aangemaakt",
+    "createFailed": "Inspectie kon niet worden aangemaakt"
+  },
+  "shareDialog": {
+    "title": "Inspectie delen",
+    "description": "Deel een alleen-lezen weergave van deze inspectie met uw klant.",
+    "copyLink": "Link kopiëren",
+    "copied": "Link gekopieerd naar klembord",
+    "generated": "Deellink aangemaakt",
+    "revoked": "Deellink ingetrokken"
+  }
+}

+ 29 - 2
messages/nl/messages.json

@@ -1,7 +1,14 @@
 {
   "page": {
     "featureName": "SMS-berichten",
-    "featureDescription": "Verzend en ontvang SMS-berichten met uw klanten rechtstreeks vanuit Torqvoice."
+    "featureDescription": "Verzend en ontvang SMS-berichten met uw klanten rechtstreeks vanuit Torqvoice.",
+    "tabs": {
+      "inbox": "Postvak in",
+      "scheduled": "Gepland"
+    },
+    "smsNotConfiguredTitle": "Sms is niet ingesteld",
+    "smsNotConfiguredHint": "Koppel een sms-provider om hier berichten te versturen en ontvangen. Geplande e-mail werkt ook zonder.",
+    "goToSmsSettings": "Naar sms-instellingen"
   },
   "notConfigured": {
     "title": "SMS niet geconfigureerd",
@@ -20,7 +27,10 @@
     "deleted": "Gesprek verwijderd",
     "deleteError": "Gesprek kon niet worden verwijderd",
     "back": "Back",
-    "conversationMenu": "Conversation menu"
+    "conversationMenu": "Conversation menu",
+    "searchPlaceholder": "Gesprekken zoeken",
+    "noSearchResults": "Geen gesprekken gevonden",
+    "now": "nu"
   },
   "conversation": {
     "noPhone": "Geen telefoonnummer geregistreerd voor {name}. Voeg een telefoonnummer toe om berichten te sturen.",
@@ -44,5 +54,22 @@
     "smsSent": "SMS verzonden",
     "sentTo": "{label} is verzonden naar {name} ({phone})",
     "sendError": "SMS kon niet worden verzonden"
+  },
+  "compose": {
+    "newMessage": "Nieuw bericht",
+    "title": "Nieuw bericht",
+    "searchPlaceholder": "Klanten zoeken op naam of nummer",
+    "noMatches": "Geen klanten gevonden",
+    "noRecipients": "Geen klanten met een telefoonnummer",
+    "noRecipientsHint": "Voeg een telefoonnummer toe om te kunnen sms'en.",
+    "changeRecipient": "Iemand anders kiezen",
+    "messageLabel": "Bericht",
+    "messagePlaceholder": "Bericht aan {name}...",
+    "segments": "{chars} tekens · {segments} sms",
+    "send": "Versturen",
+    "scheduleInstead": "Liever plannen",
+    "sent": "Verzonden naar {name}",
+    "sendError": "Kan het bericht niet versturen",
+    "templates": "Sjablonen"
   }
 }

+ 2 - 3
messages/nl/navigation.json

@@ -57,6 +57,7 @@
   },
   "search": "Zoeken...",
   "shortcut": "Ctrl+K",
+  "readMore": "Meer lezen",
   "newWorkOrder": "Nieuwe werkorder",
   "quickCreate": {
     "title": "Toevoegen",
@@ -77,7 +78,6 @@
     "clients": "Klanten",
     "customers": "Klanten",
     "messages": "Berichten",
-    "smsMessages": "SMS Messages",
     "telegram": "Telegram",
     "workshop": "Werkplaats",
     "vehicles": "Voertuigen",
@@ -103,8 +103,7 @@
     "companyPlaceholder": "bijv. Jans Autogarage",
     "cancel": "Annuleren",
     "createCompany": "Bedrijf aanmaken",
-    "lightMode": "Lichte modus",
-    "darkMode": "Donkere modus",
+    "theme": "Thema",
     "signOut": "Uitloggen",
     "more": "Meer",
     "auditLog": "Activiteitenlog",

+ 31 - 1
messages/nl/pdf.json

@@ -123,7 +123,37 @@
     "notesColumn": "Notities",
     "footerText": "Voertuiginspectie — {shopName}",
     "viewPortal": "Bekijk uw portaal: {url}",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "euPass": "Geen gebrek",
+    "euAttention": "Klein gebrek",
+    "euFail": "Groot gebrek",
+    "euDangerous": "Gevaarlijk gebrek",
+    "basicPass": "Goedgekeurd",
+    "basicAttention": "Aandacht",
+    "basicFail": "Afgekeurd",
+    "basicDangerous": "Gevaarlijk",
+    "resultPass": "Goedgekeurd",
+    "resultPassMinor": "Goedgekeurd met kleine gebreken",
+    "resultFail": "Afgekeurd — grote gebreken",
+    "resultFailDangerous": "Afgekeurd — gevaarlijke gebreken",
+    "resultIncomplete": "Niet afgerond",
+    "testDetails": "Keuringsgegevens",
+    "testDate": "Keuringsdatum",
+    "testLocation": "Plaats van keuring",
+    "inspector": "Keurmeester",
+    "certificateNumber": "Certificaatnummer",
+    "vehicleCategory": "Voertuigcategorie",
+    "nextTestDue": "Volgende keuring",
+    "limit": "Grenswaarde",
+    "overallResult": "Keuringsresultaat",
+    "deficiencies": "Vastgestelde gebreken",
+    "reading": "Meetwaarde",
+    "noDeficiencies": "Er zijn geen gebreken vastgelegd.",
+    "resultDetailPass": "Er zijn geen gebreken vastgesteld.",
+    "resultDetailPassMinor": "Het voertuig is goedgekeurd. Herstel de kleine gebreken zonder onnodig uitstel.",
+    "resultDetailFail": "Het voertuig is afgekeurd. De gebreken moeten worden hersteld en het voertuig opnieuw gekeurd.",
+    "resultDetailFailDangerous": "Het voertuig mag niet op de openbare weg worden gebruikt totdat de gevaarlijke gebreken zijn hersteld.",
+    "resultDetailIncomplete": "Deze keuring loopt nog."
   },
   "serviceHistory": {
     "serviceHistoryTitle": "SERVICEGESCHIEDENIS",

Некоторые файлы не были показаны из-за большого количества измененных файлов