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

+ 13 - 0
.env.example

@@ -6,3 +6,16 @@ BETTER_AUTH_SECRET="your-secret-here"
 
 # App URL (used by both the app and Better Auth)
 NEXT_PUBLIC_APP_URL="http://localhost:3000"
+
+# Set to true only when Cloudflare proxies every request AND the origin
+# refuses traffic that did not come through it (Cloudflare IP ranges allowed
+# at the firewall or in nginx).
+#
+# Behind Cloudflare this is required, not optional: the proxy sets X-Real-IP
+# from the connection it sees, which is a Cloudflare edge address shared by
+# thousands of visitors, so leaving this off collapses everyone into a handful
+# of rate-limit buckets and real users start getting 429s.
+#
+# Without the origin lock it is worse than useless, because cf-connecting-ip is
+# then just a header anyone reaching the box directly can write for themselves.
+TRUST_CF_CONNECTING_IP=false

+ 12 - 2
messages/de/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Arbeitsplatz erstellt",
     "work_bay_update": "Arbeitsplatz aktualisiert",
     "work_bay_delete": "Arbeitsplatz gelöscht",
+    "auth_appSetupRedeemed": "Mit Einrichtungscode angemeldet",
+    "auth_technicianCodeSignIn": "Mit Einmalcode angemeldet",
+    "team_createAppSetupCode": "App-Einrichtungscode ausgestellt",
+    "team_createTechnicianAccount": "Technikerkonto angelegt",
+    "team_removeTechnicianAccess": "Techniker entfernt und Zugriff entzogen",
+    "team_setMemberTechnician": "Techniker-Status eines Mitglieds geändert",
     "settings_whatsappUpdated": "WhatsApp-Einstellungen aktualisiert",
+    "settings_whatsappDisconnected": "WhatsApp getrennt",
     "settings_whatsappNumberRegistered": "WhatsApp-Nummer registriert",
-    "settings_whatsappDisconnected": "WhatsApp getrennt"
+    "team_giveTechnicianTheApp": "Board-Techniker ein Konto gegeben",
+    "team_createDefaultRoles": "Standardrollen angelegt",
+    "settings_setCustomFieldPlacement": "Position eines benutzerdefinierten Felds geändert"
   },
   "summary": {
     "customField_create": "Benutzerdefiniertes Feld „{name}“ erstellt",
@@ -265,6 +274,7 @@
     "whatsapp_send": "WhatsApp-Nachricht an {name} gesendet",
     "work_bay_create": "Arbeitsplatz „{name}“ angelegt",
     "work_bay_update": "Arbeitsplatz „{name}“ aktualisiert",
-    "work_bay_delete": "Arbeitsplatz {id} gelöscht"
+    "work_bay_delete": "Arbeitsplatz {id} gelöscht",
+    "settings_setCustomFieldPlacement": "Hat geändert, wo ein benutzerdefiniertes Feld gedruckt wird"
   }
 }

+ 5 - 0
messages/de/common.json

@@ -95,5 +95,10 @@
     "placeholder": "z. B. Wir haben Probleme mit unserer Serverinfrastruktur und arbeiten daran.",
     "posted": "Hinweis veröffentlicht",
     "cleared": "Hinweis entfernt"
+  },
+  "pdfPreview": {
+    "title": "PDF-Vorschau",
+    "preview": "Vorschau",
+    "failed": "Die PDF-Vorschau konnte nicht erstellt werden."
   }
 }

+ 21 - 1
messages/de/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Steuerbefreit",
     "tabs": {
       "vehicles": "Fahrzeuge ({count})",
+      "invoices": "Rechnungen ({count})",
+      "quotes": "Angebote ({count})",
       "messages": "Nachrichten",
       "requests": "Anfragen ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Betriebsstunden",
       "services": "Wartungen"
     },
-    "noVehicles": "Diesem Kunden sind keine Fahrzeuge zugewiesen"
+    "documentTable": {
+      "invoiceNumber": "Rechnungsnr.",
+      "quoteNumber": "Angebotsnr.",
+      "title": "Titel",
+      "vehicle": "Fahrzeug",
+      "status": "Status",
+      "date": "Datum",
+      "total": "Gesamt",
+      "noVehicle": "Nur Teile",
+      "searchPlaceholder": "Suchen...",
+      "noMatches": "Keine Treffer für deine Suche",
+      "sort": {
+        "asc": "aufsteigend",
+        "desc": "absteigend"
+      }
+    },
+    "noVehicles": "Diesem Kunden sind keine Fahrzeuge zugewiesen",
+    "noInvoices": "Keine Rechnungen für diesen Kunden",
+    "noQuotes": "Keine Angebote für diesen Kunden"
   },
   "form": {
     "addTitle": "Neuen Kunden anlegen",

+ 27 - 0
messages/de/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "This invoice is locked because it has been sent",
+      "paid": "This invoice is locked because it has been paid"
+    },
+    "quote": {
+      "sent": "This quote is locked because it has been sent",
+      "accepted": "This quote is locked because it has been accepted"
+    }
+  },
+  "lockedBody": "Its parts, labour, prices, discount, tax, number and date can no longer be changed. Payments, status changes, sending and attachments all still work.",
+  "lockedAdminHint": "As an owner or admin you can unlock it if something genuinely needs correcting. The unlock is recorded in the audit log.",
+  "lockedMemberHint": "Ask an owner or admin to unlock it if something needs correcting.",
+  "unlock": "Unlock for editing",
+  "relock": "Lock again",
+  "unlockConfirmTitle": "Unlock this document?",
+  "unlockConfirmDescription": {
+    "invoice": "It will become editable again, and the change will be recorded in the audit log with your name. Prefer a credit note where your local rules require one.",
+    "quote": "It will become editable again, and the change will be recorded in the audit log with your name."
+  },
+  "unlocked": "Unlocked for editing",
+  "relocked": "Locked again",
+  "reopenedTitle": "This document has been unlocked for editing",
+  "reopenedBody": "It stays editable until it is locked again.",
+  "failed": "Could not change the lock"
+}

+ 5 - 0
messages/de/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram ist aktiv",
     "body": "Kundengespräche landen hier. Antworten Sie, ohne die App zu verlassen."
+  },
+  "invoice-designer": {
+    "title": "Rechnungen wurden überarbeitet",
+    "body": "Legen Sie Layout, Farben und Schriften für Rechnungen und Angebote im neuen Designer fest, unter Vorlagen.",
+    "cta": "Vorlagen öffnen"
   }
 }

+ 3 - 1
messages/de/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Fahrzeug",
     "quote": "Angebot",
     "part": "Ersatzteil",
-    "inspection": "Inspektion"
+    "inspection": "Inspektion",
+    "shopActions": "Werkstatt",
+    "person": "Person hinzufügen"
   },
   "purchaseWhiteLabel": "White-Label erwerben",
   "licenseExpired": "Ihre Lizenz ist abgelaufen. Funktionen können eingeschränkt sein.",

+ 13 - 2
messages/de/pdf.json

@@ -19,6 +19,12 @@
     "description": "Beschreibung",
     "qty": "Menge",
     "unitPrice": "Einzelpreis",
+    "items": "Positionen",
+    "pos": "Pos.",
+    "unitOfMeasure": "Einheit",
+    "invoiceNumberLabel": "Rechnungsnummer",
+    "customerNumberLabel": "Kundennummer",
+    "dateLabel": "Datum",
     "total": "Gesamt",
     "labor": "Arbeitsleistung",
     "hours": "Stunden",
@@ -64,7 +70,9 @@
     "professionalWorkshop": "Professionelle Werkstattverwaltung",
     "tel": "Tel: {phone}",
     "org": "Org: {org}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Zusätzliche Informationen",
+    "telegramConnect": "Chatten Sie mit uns auf Telegram"
   },
   "quote": {
     "title": "ANGEBOT",
@@ -100,7 +108,10 @@
     "validityFooter30": "Dieses Angebot ist 30 Tage gültig",
     "viewPortal": "Ihr Portal ansehen: {url}",
     "tel": "Tel: {phone}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Zusätzliche Informationen",
+    "quoteNumberLabel": "Angebotsnr.",
+    "validUntilLabel": "Gültig bis"
   },
   "inspection": {
     "title": "FAHRZEUGINSPEKTION",

+ 3 - 1
messages/de/quotes.json

@@ -48,7 +48,9 @@
       "details": "Details",
       "images": "Bilder",
       "documents": "Dokumente"
-    }
+    },
+    "customFieldsInvalid": "Bitte alle erforderlichen benutzerdefinierten Felder ausfüllen",
+    "customFieldsSaveFailed": "Benutzerdefinierte Felder konnten nicht gespeichert werden"
   },
   "form": {
     "newQuote": "Neues Angebot",

+ 31 - 2
messages/de/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "BEZAHLT",
     "entityLabel": "Rechnung",
     "emailSubject": "Zahlungsbestätigung",
-    "statusEmailSubject": "Aktualisierung des Servicestatus"
+    "statusEmailSubject": "Aktualisierung des Servicestatus",
+    "markCompletedTitle": "Diese Rechnung als abgeschlossen markieren?",
+    "markCompletedDescription": "Sie ist beim Kunden, gilt aber weiterhin als nicht fertig und bleibt daher auf der Auftragstafel stehen.",
+    "markCompletedConfirm": "Als abgeschlossen markieren",
+    "lockedFieldsetLabel": "Gesperrte Rechnung, Bearbeitung deaktiviert"
   },
   "payments": {
     "title": "Zahlungen",
@@ -344,7 +348,23 @@
     "setDefaults": "Standardwerte",
     "workBay": "Arbeitsplatz",
     "selectWorkBay": "Arbeitsplatz wählen …",
-    "noWorkBay": "Kein Arbeitsplatz"
+    "noWorkBay": "Kein Arbeitsplatz",
+    "technicians": "Techniker",
+    "otherTeamMembers": "Weitere Teammitglieder",
+    "makeTechnician": "Macht sie zum Techniker",
+    "addSomeoneNew": "Jemanden hinzufügen",
+    "notOnBoard": "Noch nicht auf der Tafel",
+    "putOnBoard": "Auf die Tafel",
+    "slotTaken": "{count, plural, one {Dieser Termin ist bereits belegt} other {Dieser Termin hat # Überschneidungen}}",
+    "anotherJob": "ein anderer Auftrag",
+    "clashTechnician": "der Techniker ist belegt",
+    "clashBay": "die Box ist belegt",
+    "clashBoth": "beide sind belegt",
+    "bookedAnyway": "Trotzdem gespeichert. Ändern Sie die Zeit oder wählen Sie den nächsten freien Termin.",
+    "pickNextAvailable": "Nächsten freien Termin wählen",
+    "findingSlot": "Termin wird gesucht…",
+    "slotPicked": "Auf den nächsten freien Termin gelegt",
+    "noSlotFound": "In den nächsten Wochen kein freier Termin gefunden"
   },
   "notifications": {
     "title": "Kundenbenachrichtigungen",
@@ -381,5 +401,14 @@
       "title": "Standard-Garantieeinstellungen",
       "description": "Standardgarantiebedingungen für neue Serviceeinträge festlegen"
     }
+  },
+  "concerns": {
+    "title": "Kundenanliegen",
+    "addFirst": "Kundenanliegen hinzufügen",
+    "add": "Weiteres hinzufügen",
+    "placeholder": "Beim Bremsen kommt hinten ein Geräusch",
+    "remove": "Dieses Anliegen entfernen",
+    "notAnswered": "Dazu wurde noch nichts festgestellt",
+    "answered": "{count} Feststellung(en) dazu"
   }
 }

+ 427 - 6
messages/de/settings.json

@@ -161,6 +161,9 @@
     "email": "E-Mail",
     "emailPlaceholder": "service@beispiel.de",
     "address": "Adresse",
+    "slogan": "Slogan",
+    "sloganPlaceholder": "Ihre Meisterwerkstatt für alle Marken",
+    "sloganHint": "Eine Zeile unter Ihrem Namen auf Rechnungen und Angeboten.",
     "addressPlaceholder": "Hauptstrasse 123\nEtage 1\n12345 Stadt",
     "saveCompany": "Firmendetails speichern",
     "addNewCompany": "Neue Firma hinzufugen",
@@ -380,7 +383,7 @@
     "adminLabel": "Administrator",
     "adminDescription": "Kann Mitglieder einladen/entfernen und gemeinsame Daten verwalten.",
     "memberLabel": "Mitglied",
-    "memberDescription": "Berechtigungen werden durch die zugewiesene benutzerdefinierte Rolle bestimmt. Ohne benutzerdefinierte Rolle nur Lesezugriff.",
+    "memberDescription": "Die Rechte ergeben sich aus der zugewiesenen Rolle. Ohne Rolle kann dieses Mitglied nichts tun.",
     "roleAssigned": "Rolle aktualisiert",
     "failedAssignRole": "Rolle konnte nicht aktualisiert werden",
     "removeMemberTitle": "Mitglied entfernen",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Rolle konnte nicht aktualisiert werden",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Techniker",
+    "technicianHint": "Kann Aufträge zugewiesen bekommen und die Techniker-App nutzen",
+    "technicianFailed": "Konnte nicht geändert werden",
+    "setupApp": "Für App einrichten",
+    "setupAppTitle": "Techniker-App einrichten",
+    "setupAppInstruction": "Bitten Sie {name}, dies auf dem Telefon zu tun:",
+    "setupAppOrType": "Oder lesen Sie ihm diesen Code vor:",
+    "setupAppExpiry": "Gilt einmalig und läuft in {time} ab.",
+    "setupAppExpired": "Dieser Code ist abgelaufen. Schließen und neu beginnen.",
+    "setupAppDone": "Fertig",
+    "setupAppFailed": "Einrichtungscode konnte nicht erstellt werden",
+    "setupPageTitle": "Techniker-App einrichten",
+    "setupPageBody": "Öffnen Sie Torqvoice Tech auf diesem Telefon, tippen Sie auf Einrichtungscode scannen und halten Sie es erneut auf denselben Code.",
+    "setupPageCode": "Oder geben Sie diesen Code in der App ein",
+    "setupPageOpenApp": "Torqvoice Tech öffnen",
+    "setupPageExpiry": "Dieser Code gilt einmalig und läuft zehn Minuten nach der Erstellung durch Ihre Werkstatt ab.",
+    "setupAppStep1": "Torqvoice Tech installieren",
+    "setupAppStep2": "Sie öffnen und auf „Einrichtungscode scannen“ tippen",
+    "setupAppStep3": "Das Telefon auf diesen Code halten",
+    "setupAppNotCamera": "Die normale Kamera-App des Telefons funktioniert nicht. Es muss in Torqvoice Tech gescannt werden.",
+    "addTechnician": "Techniker hinzufügen",
+    "addTechnicianHint": "Für einen Mechaniker, der am Tresen steht. Ohne E-Mail, ohne Wartezeit.",
+    "technicianName": "Name",
+    "technicianNamePlaceholder": "Vollständiger Name",
+    "technicianPhone": "Handynummer",
+    "technicianPhonePlaceholder": "Das Telefon in seiner Tasche",
+    "addTechnicianSubmit": "Anlegen",
+    "addTechnicianNote": "Ab dann meldet er sich mit dieser Nummer an. Kein Passwort zum Merken und nichts, was auf dem ersten Bildschirm der App eingetippt werden muss.",
+    "addTechnicianDone": "{name} ist angelegt. Zeigen Sie ihm den Code.",
+    "addTechnicianFailed": "Techniker konnte nicht angelegt werden",
+    "setupAppCopyLink": "Link zum Senden kopieren",
+    "setupAppCopied": "Kopiert",
+    "revokeTechnicianTitle": "Aus der App abmelden?",
+    "revokeTechnicianBody": "{name} verliert sofort den Zugriff auf dem Telefon, und jeder Code wird ungültig. Erledigte Arbeit und Stunden bleiben unverändert.",
+    "revokeTechnicianConfirm": "Abmelden",
+    "addPerson": "Hinzufügen",
+    "addPersonTitle": "Jemanden zur Werkstatt hinzufügen",
+    "addPersonWho": "Die beiden werden unterschiedlich eingerichtet. Sagen Sie uns zuerst, um wen es geht.",
+    "choiceTechnician": "Ein Mechaniker",
+    "choiceTechnicianHint": "Arbeitet an den Autos und nutzt Torqvoice auf dem Telefon. Am einfachsten, solange er neben Ihnen steht, und dauert etwa eine Minute.",
+    "choiceMember": "Jemand im Büro",
+    "choiceMemberHint": "Nimmt Autos an, bestellt Teile und schreibt Rechnungen, am Computer. Sie senden eine E-Mail und er wählt sein eigenes Passwort.",
+    "stepLabelWho": "Wer",
+    "stepLabelDetails": "Angaben",
+    "stepLabelPhone": "Sein Telefon",
+    "techDetailsTitle": "Name und Handynummer",
+    "techDetailsBlurb": "Über die Handynummer meldet er sich künftig an, nehmen Sie also das Telefon, das er wirklich dabeihat. Ein Passwort, das er sich merken oder vergessen könnte, gibt es nicht.",
+    "techHandoffTitle": "Jetzt auf sein Telefon bringen",
+    "techHandoffBlurb": "Dieser Code verbindet sein Telefon mit Ihrer Werkstatt. Er gilt einmal und nur zehn Minuten lang, machen Sie es also, solange er hier ist.",
+    "memberDetailsTitle": "Seine E-Mail-Adresse",
+    "memberDetailsBlurb": "Er bekommt eine E-Mail mit einem Link. Beim Öffnen wählt er sein eigenes Passwort und erscheint danach in der Liste oben.",
+    "roleHint": "Administratoren können Einstellungen ändern und Personen hinzufügen. Alle anderen erledigen die tägliche Arbeit.",
+    "stepBack": "Zurück",
+    "stepHandoffDone": "Er hat ihn gescannt",
+    "stepDoneTitle": "{name} ist startklar",
+    "stepDoneBody": "Er kann die App öffnen und seine Aufträge sehen. Beim nächsten Mal meldet er sich nur mit seiner Handynummer an, ohne Code.",
+    "stepInvitedTitle": "Einladung an {email} gesendet",
+    "stepInvitedBody": "Er erscheint in der Liste, sobald er die E-Mail geöffnet und angenommen hat. Der Link gilt sieben Tage.",
+    "stepDoneAnother": "Noch jemanden hinzufügen",
+    "clashTitle": "{name} hat diese Nummer bereits",
+    "clashBlurb": "Zwei Personen können sich keine Handynummer teilen, weil sie sich damit anmelden. Welcher Fall ist es?",
+    "clashSamePerson": "Das ist {name}",
+    "clashSamePersonHint": "Dieselbe Person kommt zurück oder der Name war anders geschrieben. Aufträge und Stunden bleiben erhalten, und der eben eingegebene Name ersetzt den alten.",
+    "clashTakeover": "Nein, das ist {name}",
+    "clashTakeoverHint": "Eine andere Person, die diese Nummer jetzt hat. {name} behält alles Geleistete, kann sich aber nicht mehr anmelden, und Sie können später eine neue Nummer hinterlegen.",
+    "clashDifferentNumber": "Keins davon, Nummer ändern",
+    "workshopCountry": "In welchem Land ist Ihre Werkstatt?",
+    "workshopCountryPlaceholder": "Land auswählen",
+    "workshopCountryHint": "Wird nur einmal gefragt. Danach können Handynummern kurz eingegeben werden. Sie können es später unter <link>Spracheinstellungen</link> ändern.",
+    "phonePreview": "Gespeichert als",
+    "stepScannedTitle": "{name} ist drin",
+    "countrySearch": "Länder durchsuchen",
+    "countryNoMatch": "Kein Land passt dazu",
+    "choiceStandalone": "Nur ein Name fürs Board",
+    "choiceStandaloneHint": "Ein Azubi, ein Subunternehmer, jeder, den Sie einplanen, der sich aber nie anmeldet. Kein Telefon, keine E-Mail, kein Konto. Sie können das später ergänzen.",
+    "standaloneDetailsTitle": "Name und Farbe",
+    "standaloneDetailsBlurb": "Mehr braucht es nicht. Die Person erscheint auf dem Board und auf Aufträgen und hat nichts, wo sie sich anmelden müsste.",
+    "boardColour": "Farbe auf dem Board",
+    "stepStandaloneTitle": "{name} steht auf dem Board",
+    "stepStandaloneBody": "Sie können sie sofort einplanen und Aufträgen zuweisen. Wird die App später gebraucht, ergänzen Sie hier einfach eine Handynummer.",
+    "boardOnly": "Nur auf dem Board",
+    "boardOnlyHint": "Werden eingeplant und Aufträgen zugewiesen, melden sich aber nie an. Geben Sie ihnen eine Handynummer, wenn die App gebraucht wird.",
+    "boardOnlyNoAccount": "Kein Konto",
+    "giveApp": "App geben",
+    "giveAppTitle": "{name} die App geben",
+    "giveAppBlurb": "Es fehlt nur eine Handynummer. Damit meldet sich die Person künftig an.",
+    "giveAppKeepsHistory": "Alles, was bereits auf sie gebucht ist, bleibt erhalten.",
+    "giveAppSubmit": "Konto anlegen",
+    "role": "Rolle",
+    "inviteMemberHint": "Die Person erhält eine E-Mail und wählt ihr eigenes Passwort.",
+    "removeBoardOnlyTitle": "{name} von der Tafel nehmen?",
+    "removeBoardOnlyBody": "{name} erscheint nicht mehr auf der Werkstatttafel und kann keinen Aufträgen mehr zugewiesen werden. Bereits erfasste Arbeit und gestempelte Stunden bleiben genau so, wie sie sind.",
+    "removeBoardOnlyDone": "{name} ist von der Tafel",
+    "noRole": "Keine Rolle",
+    "worksOnJobs": "Arbeitet an Aufträgen",
+    "createDefaultRoles": "Standardrollen anlegen",
+    "defaultRolesCreated": "Standardrollen angelegt",
+    "noRolesYet": "Diese Werkstatt hat noch keine Rollen, außer Admin gibt es also nichts zu vergeben. Legen Sie die Standardrollen an und schränken Sie die Rechte später ein.",
+    "noRoleDescription": "Überhaupt keine Rechte. Sie können sich anmelden, aber jeder Bildschirm weist sie ab, bis Sie ihnen unten eine Rolle geben.",
+    "cannotUseApp": "Diese Rolle kann keine Aufträge bearbeiten. Geben Sie ihr zuerst Techniker oder eine Rolle mit denselben Rechten.",
+    "revokeTechnicianDone": "{name} wurde aus der App abgemeldet",
+    "noAccessTitle": "Noch kein Zugriff",
+    "noAccessBody": "Ihr Konto gehört zu {workshop}, hat aber noch keine Rolle, deshalb gibt es hier nichts zu öffnen. Bitten Sie einen Inhaber oder Administrator Ihrer Werkstatt um eine Rolle.",
+    "setupPageInstall": "Bei Google Play laden"
   },
   "invoice": {
     "title": "Rechnungslayout",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "{count} Kunden nummeriert",
     "allCustomersNumbered": "Alle Kunden haben eine Nummer.",
     "assignCustomerNumbersConfirmTitle": "Kundennummern vergeben?",
-    "assignCustomerNumbersConfirmDescription": "Die {count} Kunden ohne Nummer erhalten fortlaufende Nummern in der Reihenfolge ihrer Erstellung, beginnend nach der höchsten vorhandenen Nummer. Kunden mit Nummer bleiben unverändert. Nummern können danach bearbeitet werden."
+    "assignCustomerNumbersConfirmDescription": "Die {count} Kunden ohne Nummer erhalten fortlaufende Nummern in der Reihenfolge ihrer Erstellung, beginnend nach der höchsten vorhandenen Nummer. Kunden mit Nummer bleiben unverändert. Nummern können danach bearbeitet werden.",
+    "layoutColorsHint": "Farben, Schriften und der Briefkopf-Stil liegen unter Vorlagen.",
+    "goToTemplates": "Vorlagen öffnen",
+    "lockTitle": "Abgeschlossene Dokumente sperren",
+    "lockDescription": "Verhindert Änderungen an einer Rechnung oder einem Angebot, sobald es abgeschlossen ist.",
+    "lockWhatItDoes": "Gesperrt werden: Teile, Arbeit, Mengen, Preise, Rabatt, Steuer, Belegnummer und Datum. Auch das Löschen des Dokuments wird verhindert.",
+    "lockWhatItAllows": "Weiterhin möglich: Zahlungen erfassen, Online-Kartenzahlung, Statusänderungen, Versand und erneuter Versand, Anhänge und interne Notizen. Eine gesperrte Rechnung kann immer bezahlt werden.",
+    "lockUnlockNote": "Inhaber und Administratoren können ein einzelnes Dokument auf dessen eigener Seite entsperren, wenn wirklich etwas korrigiert werden muss. Jede Entsperrung wird im Audit-Log festgehalten.",
+    "lockInvoicesLabel": "Rechnungen sperren",
+    "lockTriggerSent": "Sobald die Rechnung versendet ist",
+    "lockTriggerPaid": "Sobald die Rechnung vollständig bezahlt ist",
+    "lockTriggerSentHint": "Sperrt, sobald die Rechnung per E-Mail versendet oder ein Freigabelink erstellt wird. Zuvor versendete Rechnungen sind nicht betroffen.",
+    "lockTriggerPaidHint": "Sperrt, sobald der volle Betrag beglichen oder die Rechnung manuell als bezahlt markiert ist. Teilweise bezahlte Rechnungen bleiben bearbeitbar.",
+    "lockQuotesLabel": "Angebote sperren",
+    "quoteLockTriggerSent": "Sobald das Angebot versendet ist",
+    "quoteLockTriggerAccepted": "Sobald das Angebot angenommen ist",
+    "quoteLockTriggerSentHint": "Sperrt, sobald das Angebot zum Kunden geht. Nur wählen, wenn Sie Angebote nie nachverhandeln.",
+    "quoteLockTriggerAcceptedHint": "Sperrt, sobald der Kunde das Angebot angenommen hat oder es in einen Auftrag umgewandelt wurde. Versendete Angebote bleiben bearbeitbar."
   },
   "layoutEditor": {
     "helpText": "Ziehen zum Neuordnen. Verwenden Sie den Breiten-Umschalter, um Abschnitte nebeneinander zu platzieren. Aufeinanderfolgende Halbbreite-Abschnitte (L/R) werden in zwei Spalten dargestellt.",
     "addField": "Feld hinzufügen",
     "custom": "benutzerdefiniert",
     "full": "Voll",
+    "boxed": "Rahmen",
+    "plain": "Ohne",
+    "boxedHint": "Wird in einem Kasten gedruckt",
+    "plainHint": "Wird ohne Kasten gedruckt",
     "L": "L",
     "R": "R",
     "left": "links",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Volle Breite — Klicken für Halbbreite (links)",
     "sections": {
       "header": "Kopfzeile",
+      "slogan": "Slogan",
       "customer": "Kunde",
       "vehicle": "Fahrzeug",
       "service": "Service",
+      "document_title": "Belegtitel",
+      "items_table": "Positionstabelle",
       "parts_table": "Teile",
       "labor_table": "Arbeit",
       "totals": "Summen",
       "notes": "Notizen",
+      "attached_documents": "Beigefügte Dokumente",
       "diagnostic_notes": "Diagnosenotizen",
       "findings": "Beobachtungen",
+      "warranty": "Garantie",
       "bank_account": "Bankkonto",
       "footer": "Fußzeile",
       "general": "Allgemein",
@@ -493,12 +626,59 @@
       "tech_name": "Techniker",
       "logo": "Logo",
       "company_name": "Firmenname",
+      "company_slogan": "Slogan",
       "company_address": "Adresse",
       "company_phone": "Telefon",
       "company_email": "E-Mail",
       "company_org_number": "Organisationsnummer",
       "bank_account": "Bankkonto",
-      "org_number": "Organisationsnummer"
+      "footer_note": "Fußzeilen-Hinweis",
+      "org_number": "Organisationsnummer",
+      "portal_link": "Portal-Link"
+    },
+    "presetsTitle": "Mit einer Anordnung beginnen",
+    "presetsHint": "Ersetzt die Anordnung unten. Nichts wird gespeichert, bis Sie speichern.",
+    "presets": {
+      "classic": {
+        "name": "Klassisch",
+        "description": "Teile und Arbeit in getrennten Tabellen, Angaben links untereinander"
+      },
+      "letterhead": {
+        "name": "Briefkopf",
+        "description": "Kontaktdaten unten, Titel unter den Adressen"
+      },
+      "compact": {
+        "name": "Kompakt",
+        "description": "Ohne Kästen, nur das Nötigste"
+      },
+      "minimal": {
+        "name": "Minimal",
+        "description": "Reine Typografie auf Weiß: keine Kästen, keine Bänder, nur Linien und Weißraum"
+      },
+      "itemized": {
+        "name": "Positionsliste",
+        "description": "Eine nummerierte Positionsliste mit eigener Einheitenspalte"
+      },
+      "detailed": {
+        "name": "Ausführlich",
+        "description": "Titel oben, Fahrzeug für sich, beide Tabellen und alle optionalen Blöcke"
+      }
+    },
+    "style": {
+      "documentTitle": "Ganzes Blatt",
+      "documentHint": "Größe, Abstände, Akzent, Streifen",
+      "textColor": "Text",
+      "labelColor": "Überschrift",
+      "backgroundColor": "Füllung",
+      "borderColor": "Rahmen",
+      "fontSize": "Größe",
+      "rowPadding": "Zeilenhöhe",
+      "margin": "Rand",
+      "accentColor": "Akzent",
+      "stripeColor": "Streifen",
+      "stripes": "Streifen an",
+      "fontFamily": "Schrift",
+      "fontInherit": "Erben"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Vorlagen-Presets",
     "primaryColor": "Primärfarbe",
+    "colors": "Farben",
+    "textColor": "Text",
+    "textColorHint": "Die Farbe von Überschriften und Fließtext",
+    "companyTextColor": "Firmenname",
+    "companyTextColorHint": "Die Farbe des Namens im Briefkopf",
+    "frameBorderColor": "Rahmenlinie",
+    "frameBorderColorHint": "Die Linie, wo der Rahmen auf das Papier trifft",
+    "frameShadow": "Rahmenschatten",
+    "frameShadowOn": "Schatten",
+    "frameShadowOff": "Flach",
+    "backgroundColor": "Hintergrund",
+    "backgroundColorClear": "Zurücksetzen",
+    "backgroundColorHint": "Leer lassen für weißes Papier. Ein heller Ton druckt als getöntes Blatt.",
     "fontAndLayout": "Schrift & Layout",
     "fontFamily": "Schriftfamilie",
     "helveticaDefault": "Helvetica (Standard)",
@@ -525,6 +718,10 @@
     "standard": "Standard",
     "compact": "Kompakt",
     "modern": "Modern",
+    "framed": "Gerahmt",
+    "letterheadMark": "Briefkopf",
+    "letterheadLogo": "Logo",
+    "letterheadCompanyName": "Firmenname",
     "preview": "{name} Vorschau",
     "billTo": "Rechnungsempfänger",
     "preparedFor": "Erstellt für",
@@ -594,7 +791,11 @@
     "layoutDescription": "Passen Sie die Reihenfolge und Sichtbarkeit der Abschnitte in Ihren Rechnungen und Angeboten an.",
     "layoutSaved": "Layout erfolgreich gespeichert",
     "layoutDocInvoice": "Rechnung",
-    "layoutDocQuote": "Angebot"
+    "layoutDocQuote": "Angebot",
+    "goToLayout": "Layout und Abschnitte",
+    "openDesigner": "Vorlagen-Designer öffnen",
+    "designerIntro": "Wählen Sie einen Ausgangspunkt und öffnen Sie den Designer, um alles zu ändern.",
+    "designerHint": "Farben, Schriften, Abstände und alle Abschnitte liegen im Designer."
   },
   "payment": {
     "readMore": "Mehr erfahren",
@@ -739,6 +940,7 @@
       "NGN": "Nigerianischer Naira",
       "KES": "Kenia-Schilling",
       "MAD": "Marokkanischer Dirham",
+      "DZD": "Algerischer Dinar",
       "GHS": "Ghanaischer Cedi",
       "QAR": "Katar-Riyal",
       "KWD": "Kuwait-Dinar",
@@ -805,7 +1007,16 @@
     "failedSave": "Feld konnte nicht gespeichert werden",
     "failedDelete": "Konnte nicht gelöscht werden",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Nicht zugewiesen",
+    "defaultValue": "Standardwert",
+    "defaultValueHint": "Wird bei neuen Einträgen vorausgefüllt und gedruckt, solange kein Wert eingegeben wurde.",
+    "defaultValueNone": "Kein",
+    "defaultValueCheckedHint": "Standardmäßig aktiviert",
+    "placement": "Position auf dem Dokument",
+    "placementHidden": "Wird nicht gedruckt",
+    "placementHint": "In welchem Abschnitt der Rechnung oder des Angebots dieses Feld gedruckt wird. Im Designer kann es zusätzlich in weiteren Abschnitten aktiviert werden.",
+    "failedSavePlacement": "Feldposition konnte nicht gespeichert werden"
   },
   "workshop": {
     "title": "Werkstatt-Standards",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Prüfung fehlgeschlagen",
       "configurePerPart": "Mindestmenge eines Teils auf der Lagerseite festlegen →",
       "readMore": "Mehr erfahren"
+    },
+    "technicianStatus": {
+      "title": "Torqvoice Techniker-App (Android/iOS)",
+      "description": "Meldung, wenn ein Techniker einen Auftrag über sein Telefon ändert.",
+      "inApp": "Büro benachrichtigen",
+      "inAppHint": "Eine Meldung, wenn ein Auftrag abgeschlossen, auf Teile gesetzt oder wieder aufgenommen wird.",
+      "save": "Speichern",
+      "saved": "Benachrichtigungen gespeichert",
+      "saveFailed": "Einstellungen konnten nicht gespeichert werden"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Telegram-Nachrichten mit Ihren Kunden direkt aus Torqvoice senden und empfangen."
       }
     }
+  },
+  "designer": {
+    "invoice": "Rechnung",
+    "quote": "Angebot",
+    "eyebrow": "Dokument-Designer",
+    "galleryTitle": "Mit einer Vorlage beginnen",
+    "galleryHint": "Wählen Sie einen Ausgangspunkt. Im Designer lässt sich alles ändern.",
+    "yourDesigns": "Ihre Designs",
+    "templates": "Vorlagen",
+    "inUse": "In Verwendung",
+    "savedOn": "Gespeichert am {date}",
+    "deleteDesignTitle": "Design löschen",
+    "deleteDesignBody": "Das Design „{name}“ löschen? Rechnung und Angebot behalten, was angewendet ist; nur die gespeicherte Kopie verschwindet.",
+    "delete": "Löschen",
+    "deleteDesign": "Dieses Design löschen",
+    "continueCurrent": "Mit meinem aktuellen Layout fortfahren",
+    "backToSettings": "Zurück zu den Einstellungen",
+    "useInvoiceDesign": "Rechnungsdesign übernehmen",
+    "copiedToQuote": "Rechnungsdesign auf das Angebot übertragen",
+    "rulers": "Lineale",
+    "saveDesign": "Design speichern",
+    "saveDesignHint": "Eine benannte Kopie dieses Designs behalten, um sie in der Vorlagengalerie wiederzufinden",
+    "reset": "Zurücksetzen",
+    "save": "Speichern",
+    "saving": "Wird gespeichert…",
+    "saved": "Gespeichert",
+    "couldNotSave": "Speichern nicht möglich",
+    "couldNotSaveDesigns": "Ihre Designs konnten nicht gespeichert werden",
+    "designUpdated": "„{name}“ aktualisiert",
+    "designSaved": "Als „{name}“ gespeichert",
+    "defaultDesignName": "Mein {doc}-Design",
+    "documentStyling": "Dokumentgestaltung",
+    "sections": "Abschnitte",
+    "sectionEmpty": "leer",
+    "sectionEmptyHint": "Wird angezeigt, hat mit den aktuellen Daten aber nichts zu drucken.",
+    "sectionShownHint": "Auf dem Blatt sichtbar. Klicken, um ihn auszublenden.",
+    "sectionHiddenHint": "Vom Blatt ausgeblendet. Klicken, um ihn anzuzeigen.",
+    "railHint": "Ziehen Sie einen Abschnitt auf die Seite: zwischen Blöcken abgelegt ändert er die Reihenfolge, auf einer Karte sitzt er daneben, und überall sonst wird er frei platziert. Die Seite macht Platz um ihn herum.",
+    "returnToFlow": "{section} in den Fluss zurückholen",
+    "saveDialogTitle": "Dieses Design speichern",
+    "saveDialogBody": "Behält eine benannte Kopie der aktuellen Anordnung und Optik. Sie finden sie unter Ihre Designs in der Vorlagengalerie wieder.",
+    "designNamePlaceholder": "Name des Designs",
+    "nameExists": "Ein Design mit diesem Namen existiert; Speichern aktualisiert es.",
+    "updateDesign": "Design aktualisieren",
+    "cancel": "Abbrechen",
+    "insertHere": "Hier einfügen",
+    "dropLeftColumn": "Linke Spalte",
+    "dropRightColumn": "Rechte Spalte",
+    "freePosition": "Freie Position",
+    "sectionSettings": "Abschnittseinstellungen",
+    "panelStyle": "Panelstil",
+    "variant": {
+      "accent": "Akzent",
+      "panel": "Panel",
+      "outline": "Kontur",
+      "lines": "Linien",
+      "hint": "Akzent tönt die Karte in der Primärfarbe. Panel entspricht den anderen Detailkarten. Kontur zeichnet nur einen Rahmen, und Linien druckt ohne Kasten.",
+      "classic": "Klassisch",
+      "box": "Kasten",
+      "totalsHint": "Klassisch druckt reine Zeilen mit einer Linie über der Summe. Kasten rahmt sie ein. Panel und Akzent setzen sie auf eine Karte."
+    },
+    "alignment": "Ausrichtung",
+    "alignCenter": "Mitte",
+    "itemsTableHint": "Eine nummerierte Liste aller Positionen des Auftrags, erst Arbeit, dann Teile, anstelle der getrennten Teile- und Arbeitstabellen.",
+    "discardChanges": "Änderungen verwerfen",
+    "tablesExclusiveHint": "Das Blatt druckt eine Anordnung: eine nummerierte Liste oder getrennte Teile- und Arbeitstabellen. Wird die eine eingeschaltet, geht die andere aus.",
+    "innerPadding": "Innenabstand",
+    "totalsWidth": "Breite",
+    "totalsWidthHint": "Leer füllt die Zeile. Ein Wert in Punkt hängt den Kasten rechts an; in einer Spalte nimmt er deren Breite.",
+    "placement": "Platzierung",
+    "visible": "Sichtbar",
+    "columnFull": "Voll",
+    "columnLeft": "Links",
+    "columnRight": "Rechts",
+    "drawBox": "Kasten zeichnen",
+    "showHeading": "Überschrift zeigen",
+    "spacing": "Abstände",
+    "placedByHand": "Dieser Abschnitt ist von Hand platziert, Fluss-Abstände bewegen ihn also nicht.",
+    "placedByHandFramed": "Der gerahmte Briefkopf liegt auf dem Band; ziehen Sie ihn, um ihn zu bewegen.",
+    "placedByHandDrag": "Ziehen Sie ihn oder holen Sie ihn in den Fluss zurück, um Abstände zu nutzen.",
+    "marginTop": "Oben",
+    "marginBottom": "Unten",
+    "marginLeft": "Links",
+    "marginRight": "Rechts",
+    "spacingHint": "Punkte an freiem Raum, den der Abschnitt im Fluss um sich behält.",
+    "logo": "Logo",
+    "size": "Größe",
+    "logoHint": "Schalten Sie das Logo unter Felder aus, um stattdessen den Firmennamen zu drucken.",
+    "fields": "Felder",
+    "removeField": "Aus diesem Abschnitt entfernen",
+    "yourCustomFields": "Ihre eigenen Felder",
+    "appearance": "Aussehen",
+    "details": "Details",
+    "text": "Text",
+    "companyName": "Firmenname",
+    "heading": "Überschrift",
+    "fill": "Füllung",
+    "border": "Rahmen",
+    "lineWidth": "Linienbreite",
+    "borderWidth": "Rahmenbreite",
+    "outerBorder": "Äußerer Rahmen",
+    "rowBanding": "Zeilenstreifen",
+    "likeSheet": "Wie das Blatt",
+    "on": "An",
+    "off": "Aus",
+    "font": "Schrift",
+    "inherit": "Erben",
+    "auto": "auto",
+    "sectionDragHint": "Ziehen Sie diesen Abschnitt in der Liste oder auf der Seite, um ihn zu bewegen. Einmal von Hand platziert, verschieben ihn die Pfeiltasten um einen Punkt, mit Umschalt um zehn, und Escape bricht ein Ziehen ab.",
+    "document": "Dokument",
+    "documentSubtitle": "Gilt für das ganze Blatt",
+    "headerStyleTitle": "Kopfstil",
+    "headerStyle": {
+      "standard": {
+        "name": "Standard",
+        "desc": "Name und Details auf Weiß, Linie darunter"
+      },
+      "compact": {
+        "name": "Kompakt",
+        "desc": "Enger Kopf, dichte Zeilen"
+      },
+      "modern": {
+        "name": "Modern",
+        "desc": "Farbiges Banner über die volle Breite"
+      },
+      "framed": {
+        "name": "Gerahmt",
+        "desc": "Band oben, Leiste an der linken Seite"
+      }
+    },
+    "colors": "Farben",
+    "primary": "Primär",
+    "background": "Hintergrund",
+    "accent": "Akzent",
+    "frame": "Rahmen",
+    "rail": "Leiste",
+    "leftEdge": "Linke Kante",
+    "rightEdge": "Rechte Kante",
+    "frameLine": "Rahmenlinie",
+    "cornerRadius": "Eckenradius",
+    "shadow": "Schatten",
+    "shadowThin": "Dünn",
+    "shadowNormal": "Normal",
+    "shadowWide": "Breit",
+    "typography": "Typografie",
+    "baseSize": "Grundgröße",
+    "page": "Seite",
+    "margins": "Ränder",
+    "rowHeight": "Zeilenhöhe",
+    "band": "Streifen",
+    "sample": {
+      "itemLabor": "Vordere Bremsen erneuert",
+      "itemDisc": "Bremsscheibe, vorne",
+      "itemPads": "Bremsbelagsatz, Vorderachse",
+      "itemConsumables": "Verbrauchsmaterial",
+      "unitPcs": "Stk",
+      "unitSet": "Satz",
+      "unitEach": "x",
+      "findingPads": "Hintere Beläge bei 15 %",
+      "findingPadsNote": "Innerhalb von 5.000 km ersetzen",
+      "findingOilWeep": "Leichter Ölaustritt am Ventildeckel",
+      "notes": "Danke, dass Sie unsere Werkstatt gewählt haben. Melden Sie sich bei Fragen gerne.",
+      "warranty": "12 Monate Garantie auf Teile und Arbeit.",
+      "serviceTitle": "Jahresservice und Bremsen",
+      "serviceType": "Reparatur",
+      "companyName": "Ihre Werkstatt",
+      "slogan": "Qualität, auf die Sie sich verlassen können",
+      "footerNote": "Vielen Dank für Ihren Auftrag",
+      "value": "Beispiel"
+    },
+    "logoUpload": "Logo hochladen",
+    "logoReplace": "Logo ersetzen",
+    "logoUploading": "Wird hochgeladen…",
+    "logoFailed": "Das Bild konnte nicht hochgeladen werden",
+    "footerLogoHint": "Schalten Sie das Logo unter Felder ein, um es auch am Seitenfuß zu drucken.",
+    "logoReset": "Firmenlogo verwenden",
+    "logoOwn": "Wird nur auf diesem Dokument gedruckt. Das Firmenlogo bleibt unverändert.",
+    "logoInherited": "Es wird das Firmenlogo verwendet. Laden Sie hier eines hoch, um nur auf diesem Dokument ein anderes zu verwenden.",
+    "slogan": "Slogan",
+    "sloganPlaceholderHint": "Es ist kein Slogan hinterlegt, daher zeigt das Blatt einen Platzhalter, der nicht gedruckt wird.",
+    "sloganSetHint": "Ihr Slogan stammt aus Ihren Firmendaten.",
+    "sloganLink": "Firmeneinstellungen",
+    "placeholder": "Platzhalter",
+    "leaveTitle": "Ohne Speichern verlassen?",
+    "leaveBody": "Ihre Änderungen an diesem Design wurden nicht gespeichert und gehen verloren.",
+    "leaveConfirm": "Verlassen",
+    "boldField": "Fett"
+  },
+  "preview": {
+    "title": "Bremsenservice und Ölwechsel",
+    "serviceType": "Wartung",
+    "findingPads": "Hintere Bremsbeläge auf 15 % abgenutzt",
+    "findingPadsNote": "Wechsel innerhalb von 8.000 km empfohlen",
+    "findingOilLeak": "Leichter Ölaustritt an der Ventildeckeldichtung",
+    "invoiceNotes": "Vordere Bremsbeläge erneuert. Öl und Filter mit synthetischem 5W-30 gewechselt. Nächster Service bei 80.000 km empfohlen.",
+    "quoteNotes": "Wechsel der vorderen Bremsbeläge empfohlen. Öl- und Filterwechsel mit synthetischem 5W-30.",
+    "partBrakePads": "Bremsbeläge (vorne)",
+    "partOilFilter": "Ölfilter",
+    "partSyntheticOil": "Synthetiköl 5W-30",
+    "laborBrakeReplacement": "Bremsenwechsel",
+    "laborOilChange": "Ölwechsel"
   }
 }

+ 4 - 2
messages/de/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "Hoch",
     "findingSeverityNeedsWork": "Mittel",
     "findingSeverityMonitor": "Niedrig",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Weitere Angaben"
   },
   "quote": {
     "title": "Angebot",
@@ -125,7 +126,8 @@
       "converted": "Umgewandelt",
       "changes_requested": "Änderungen angefordert"
     },
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Weitere Angaben"
   },
   "inspection": {
     "title": "Fahrzeuginspektion",

+ 2 - 1
messages/de/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Noch nichts angehängt. Fotografieren Sie eine beschädigte Felge, solange die Reifen vor Ihnen liegen.",
     "captionPlaceholder": "Was ist darauf zu sehen?",
     "onInvoice": "Auf der Rechnung",
-    "invoiceHint": "Für die Rechnung markierte Dateien werden beim Abrechnen auf den Auftrag oder die Rechnung kopiert.",
+    "invoiceHint": "Für die Rechnung markierte Fotos werden beim Abrechnen auf den Auftrag oder die Rechnung kopiert. Dokumente bleiben hier beim Satz.",
+    "documentStays": "Bleibt beim Satz, wird nicht auf Rechnungen kopiert",
     "deleteTitle": "Diese Datei entfernen?",
     "deleteBody": "{name} wird vom Satz entfernt. Bereits auf eine Rechnung kopierte Dateien bleiben dort.",
     "failed": "Konnte nicht gespeichert werden",

+ 3 - 1
messages/de/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "Beantwortet welches Anliegen?",
+    "concernNone": "Nichts, wonach der Kunde gefragt hat"
   },
   "observationsPage": {
     "searchPlaceholder": "Beschreibung, Notizen oder Fahrzeug suchen...",

+ 4 - 1
messages/de/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Unabhängiger Techniker",
     "deleteTitle": "Techniker löschen",
     "deleteDescription": "\"{name}\" von der Arbeitsplatine entfernen? Ihre bestehenden Zuweisungen werden ebenfalls entfernt.",
-    "addTechnician": "Techniker hinzufügen"
+    "addTechnician": "Techniker hinzufügen",
+    "standaloneOnly": "Ein Name auf dem Board für jemanden ohne Anmeldung, etwa einen Azubi oder Subunternehmer. Einen Mechaniker mit App fügen Sie auf der Team-Seite hinzu.",
+    "linkedTo": "Meldet sich als {name} an",
+    "linkedManagedOnTeam": "Wird auf der Team-Seite verwaltet, zusammen mit dem App-Zugang."
   },
   "jobDetail": {
     "viewDetails": "Details anzeigen",

+ 14 - 4
messages/en/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Created Work Bay",
     "work_bay_update": "Updated Work Bay",
     "work_bay_delete": "Deleted Work Bay",
-    "settings_whatsappUpdated": "WhatsApp Settings Updated",
-    "settings_whatsappNumberRegistered": "WhatsApp Number Registered",
-    "settings_whatsappDisconnected": "WhatsApp Disconnected"
+    "auth_appSetupRedeemed": "Signed in with a setup code",
+    "auth_technicianCodeSignIn": "Signed in with a one-time code",
+    "team_createAppSetupCode": "Issued an app setup code",
+    "team_createTechnicianAccount": "Created a technician account",
+    "team_removeTechnicianAccess": "Removed a technician and revoked their access",
+    "team_setMemberTechnician": "Changed whether a member is a technician",
+    "settings_whatsappUpdated": "Updated WhatsApp settings",
+    "settings_whatsappDisconnected": "Disconnected WhatsApp",
+    "settings_whatsappNumberRegistered": "Registered a WhatsApp number",
+    "team_giveTechnicianTheApp": "Gave a board-only technician an account",
+    "team_createDefaultRoles": "Created the standard roles",
+    "settings_setCustomFieldPlacement": "Updated Custom Field Placement"
   },
   "summary": {
     "customField_create": "Created custom field \"{name}\"",
@@ -265,6 +274,7 @@
     "whatsapp_send": "Sent a WhatsApp message to {name}",
     "work_bay_create": "Created work bay \"{name}\"",
     "work_bay_update": "Updated work bay \"{name}\"",
-    "work_bay_delete": "Deleted work bay {id}"
+    "work_bay_delete": "Deleted work bay {id}",
+    "settings_setCustomFieldPlacement": "Changed where a custom field prints"
   }
 }

+ 5 - 0
messages/en/common.json

@@ -95,5 +95,10 @@
     "placeholder": "e.g. We are having trouble with our server infrastructure and are working on it.",
     "posted": "Notice posted",
     "cleared": "Notice cleared"
+  },
+  "pdfPreview": {
+    "title": "PDF preview",
+    "preview": "Preview",
+    "failed": "Could not generate the PDF preview."
   }
 }

+ 21 - 1
messages/en/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Tax exempt",
     "tabs": {
       "vehicles": "Vehicles ({count})",
+      "invoices": "Invoices ({count})",
+      "quotes": "Quotes ({count})",
       "messages": "Messages",
       "requests": "Requests ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Engine Hours",
       "services": "Services"
     },
-    "noVehicles": "No vehicles assigned to this customer"
+    "documentTable": {
+      "invoiceNumber": "Invoice #",
+      "quoteNumber": "Quote #",
+      "title": "Title",
+      "vehicle": "Vehicle",
+      "status": "Status",
+      "date": "Date",
+      "total": "Total",
+      "noVehicle": "Parts only",
+      "searchPlaceholder": "Search...",
+      "noMatches": "Nothing matches your search",
+      "sort": {
+        "asc": "ascending",
+        "desc": "descending"
+      }
+    },
+    "noVehicles": "No vehicles assigned to this customer",
+    "noInvoices": "No invoices for this customer",
+    "noQuotes": "No quotes for this customer"
   },
   "form": {
     "addTitle": "Add New Customer",

+ 27 - 0
messages/en/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "This invoice is locked because it has been sent",
+      "paid": "This invoice is locked because it has been paid"
+    },
+    "quote": {
+      "sent": "This quote is locked because it has been sent",
+      "accepted": "This quote is locked because it has been accepted"
+    }
+  },
+  "lockedBody": "Its parts, labour, prices, discount, tax, number and date can no longer be changed. Payments, status changes, sending and attachments all still work.",
+  "lockedAdminHint": "As an owner or admin you can unlock it if something genuinely needs correcting. The unlock is recorded in the audit log.",
+  "lockedMemberHint": "Ask an owner or admin to unlock it if something needs correcting.",
+  "unlock": "Unlock for editing",
+  "relock": "Lock again",
+  "unlockConfirmTitle": "Unlock this document?",
+  "unlockConfirmDescription": {
+    "invoice": "It will become editable again, and the change will be recorded in the audit log with your name. Prefer a credit note where your local rules require one.",
+    "quote": "It will become editable again, and the change will be recorded in the audit log with your name."
+  },
+  "unlocked": "Unlocked for editing",
+  "relocked": "Locked again",
+  "reopenedTitle": "This document has been unlocked for editing",
+  "reopenedBody": "It stays editable until it is locked again.",
+  "failed": "Could not change the lock"
+}

+ 5 - 0
messages/en/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram is on",
     "body": "Customer conversations land here. Reply without leaving the app."
+  },
+  "invoice-designer": {
+    "title": "Invoices have been overhauled",
+    "body": "Set the layout, colours and fonts for your invoices and quotes in the new designer, under Templates.",
+    "cta": "Open Templates"
   }
 }

+ 3 - 1
messages/en/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Vehicle",
     "quote": "Quote",
     "part": "Part",
-    "inspection": "Inspection"
+    "inspection": "Inspection",
+    "shopActions": "Shop actions",
+    "person": "Add a person"
   },
   "purchaseWhiteLabel": "Purchase White-Label",
   "licenseExpired": "Your license has expired. Features may be limited.",

+ 13 - 2
messages/en/pdf.json

@@ -19,6 +19,12 @@
     "description": "Description",
     "qty": "Qty",
     "unitPrice": "Unit Price",
+    "items": "Items",
+    "pos": "#",
+    "unitOfMeasure": "Unit",
+    "invoiceNumberLabel": "Invoice No.",
+    "customerNumberLabel": "Customer No.",
+    "dateLabel": "Date",
     "total": "Total",
     "labor": "Labor & Services",
     "hours": "Hours",
@@ -64,7 +70,9 @@
     "viewPortal": "View your portal: {url}",
     "professionalWorkshop": "Professional Workshop Management",
     "tel": "Tel: {phone}",
-    "org": "Org: {org}"
+    "org": "Org: {org}",
+    "customFieldsTitle": "Additional Information",
+    "telegramConnect": "Chat with us on Telegram"
   },
   "quote": {
     "title": "QUOTE",
@@ -100,7 +108,10 @@
     "validityFooterUntil": "This quote is valid until {date}",
     "validityFooter30": "This quote is valid for 30 days",
     "viewPortal": "View your portal: {url}",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFieldsTitle": "Additional Information",
+    "quoteNumberLabel": "Quote No.",
+    "validUntilLabel": "Valid Until"
   },
   "inspection": {
     "title": "VEHICLE INSPECTION",

+ 3 - 1
messages/en/quotes.json

@@ -48,7 +48,9 @@
       "details": "Details",
       "images": "Images",
       "documents": "Documents"
-    }
+    },
+    "customFieldsInvalid": "Please fill in all required custom fields",
+    "customFieldsSaveFailed": "Failed to save custom fields"
   },
   "form": {
     "newQuote": "New Quote",

+ 31 - 2
messages/en/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "PAID",
     "entityLabel": "Invoice",
     "emailSubject": "Payment Confirmation",
-    "statusEmailSubject": "Service Status Update"
+    "statusEmailSubject": "Service Status Update",
+    "markCompletedTitle": "Mark this invoice as completed?",
+    "markCompletedDescription": "It has gone to the customer but is still marked as not finished, so it will keep showing on the work board.",
+    "markCompletedConfirm": "Mark completed",
+    "lockedFieldsetLabel": "Locked invoice, editing disabled"
   },
   "payments": {
     "title": "Payments",
@@ -344,7 +348,23 @@
     "setDefaults": "Set Defaults",
     "workBay": "Work bay",
     "selectWorkBay": "Select work bay...",
-    "noWorkBay": "No work bay"
+    "noWorkBay": "No work bay",
+    "technicians": "Technicians",
+    "otherTeamMembers": "Other team members",
+    "makeTechnician": "Makes them a technician",
+    "addSomeoneNew": "Add someone new",
+    "notOnBoard": "Not on the board yet",
+    "putOnBoard": "Put on board",
+    "slotTaken": "{count, plural, one {This slot is already booked} other {This slot has # clashes}}",
+    "anotherJob": "another job",
+    "clashTechnician": "the technician is busy",
+    "clashBay": "the bay is in use",
+    "clashBoth": "both are taken",
+    "bookedAnyway": "Saved anyway. Change the time, or pick the next free slot.",
+    "pickNextAvailable": "Pick next available slot",
+    "findingSlot": "Finding a slot…",
+    "slotPicked": "Booked into the next free slot",
+    "noSlotFound": "No free slot found in the next few weeks"
   },
   "notifications": {
     "title": "Customer Notifications",
@@ -381,5 +401,14 @@
       "title": "Default Warranty Settings",
       "description": "Set default warranty terms for new service records"
     }
+  },
+  "concerns": {
+    "title": "Customer concerns",
+    "addFirst": "Add a customer concern",
+    "add": "Add another",
+    "placeholder": "There is a noise from the back when I brake",
+    "remove": "Remove this concern",
+    "notAnswered": "Nothing found against this yet",
+    "answered": "{count} finding(s) against this"
   }
 }

+ 427 - 6
messages/en/settings.json

@@ -161,6 +161,9 @@
     "email": "Email",
     "emailPlaceholder": "service@example.com",
     "address": "Address",
+    "slogan": "Slogan",
+    "sloganPlaceholder": "Independent service and repair, every make",
+    "sloganHint": "One line under your name on invoices and quotes.",
     "addressPlaceholder": "123 Main Street\nSuite 100\nCity, State 12345",
     "saveCompany": "Save Company Details",
     "addNewCompany": "Add New Company",
@@ -380,7 +383,7 @@
     "adminLabel": "Admin",
     "adminDescription": "Can invite/remove members and manage shared data.",
     "memberLabel": "Member",
-    "memberDescription": "Permissions determined by assigned custom role. No custom role means read-only access.",
+    "memberDescription": "Permissions are set by the assigned role. Without a role, this member cannot do anything.",
     "roleAssigned": "Role updated",
     "failedAssignRole": "Failed to update role",
     "removeMemberTitle": "Remove Member",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Failed to update role",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Technician",
+    "technicianHint": "Can be assigned jobs and use the technician app",
+    "technicianFailed": "Could not change that",
+    "setupApp": "Set up app",
+    "setupAppTitle": "Set up the technician app",
+    "setupAppInstruction": "Ask {name} to do this on their phone:",
+    "setupAppOrType": "Or read them this code:",
+    "setupAppExpiry": "Works once, and expires in {time}.",
+    "setupAppExpired": "This code has expired. Close and start again.",
+    "setupAppDone": "Done",
+    "setupAppFailed": "Could not create a setup code",
+    "setupPageTitle": "Set up the technician app",
+    "setupPageBody": "Open Torqvoice Tech on this phone, tap Scan setup code, and point it at the same code again.",
+    "setupPageCode": "Or type this code in the app",
+    "setupPageOpenApp": "Open Torqvoice Tech",
+    "setupPageExpiry": "This code works once and expires ten minutes after your workshop created it.",
+    "setupAppStep1": "Install Torqvoice Tech",
+    "setupAppStep2": "Open it and tap “Scan setup code”",
+    "setupAppStep3": "Point the phone at this code",
+    "setupAppNotCamera": "The phone's own camera app will not work. It has to be scanned from inside Torqvoice Tech.",
+    "addTechnician": "Add a technician",
+    "addTechnicianHint": "For a mechanic standing at the counter. No email, no waiting.",
+    "technicianName": "Name",
+    "technicianNamePlaceholder": "Their full name",
+    "technicianPhone": "Mobile number",
+    "technicianPhonePlaceholder": "The phone in their pocket",
+    "addTechnicianSubmit": "Create",
+    "addTechnicianNote": "They sign in with that number from then on. No password to remember, and nothing to type on the app’s first screen.",
+    "addTechnicianDone": "{name} is set up. Show them the code.",
+    "addTechnicianFailed": "Could not create that technician",
+    "setupAppCopyLink": "Copy link to send them",
+    "setupAppCopied": "Copied",
+    "revokeTechnicianTitle": "Sign them out of the app?",
+    "revokeTechnicianBody": "{name} loses access on their phone straight away, and any code they have stops working. Their finished work and hours stay exactly as they are.",
+    "revokeTechnicianConfirm": "Sign them out",
+    "addPerson": "Add",
+    "addPersonTitle": "Add someone to the workshop",
+    "addPersonWho": "These two are set up in different ways, so start by telling us which one this is.",
+    "choiceTechnician": "A mechanic",
+    "choiceTechnicianHint": "Works on the cars and uses Torqvoice on their phone. Easiest to do while they are standing here with you, and it takes about a minute.",
+    "choiceMember": "Someone in the office",
+    "choiceMemberHint": "Books cars in, orders parts and sends invoices, on a computer. You send them an email and they pick their own password.",
+    "stepLabelWho": "Who",
+    "stepLabelDetails": "Details",
+    "stepLabelPhone": "Their phone",
+    "techDetailsTitle": "Their name and mobile number",
+    "techDetailsBlurb": "The mobile number is how they sign in from now on, so use the phone they actually carry. There is no password for them to remember or forget.",
+    "techHandoffTitle": "Now get it onto their phone",
+    "techHandoffBlurb": "This code joins their phone to your workshop. It works once, and only for the next ten minutes, so do it while they are here.",
+    "memberDetailsTitle": "Their email address",
+    "memberDetailsBlurb": "They get an email with a link. When they open it they choose their own password, and then they appear in the list above.",
+    "roleHint": "Admins can change settings and add people. Everyone else does the day-to-day work.",
+    "stepBack": "Back",
+    "stepHandoffDone": "They have scanned it",
+    "stepDoneTitle": "{name} is ready",
+    "stepDoneBody": "They can open the app and see their jobs. Next time they sign in it is just their mobile number, no code needed.",
+    "stepInvitedTitle": "Invitation sent to {email}",
+    "stepInvitedBody": "They will show up in the list once they have opened the email and accepted. The link works for seven days.",
+    "stepDoneAnother": "Add someone else",
+    "clashTitle": "{name} already has that number",
+    "clashBlurb": "Two people cannot share a mobile number, because it is what they sign in with. Which of these is it?",
+    "clashSamePerson": "This is {name}",
+    "clashSamePersonHint": "The same person coming back, or a name spelled differently. Their jobs and hours stay with them, and the name you just typed replaces the old one.",
+    "clashTakeover": "No, this is {name}",
+    "clashTakeoverHint": "A different person who now has that number. {name} keeps everything they did here but can no longer sign in, and you can give them a new number later.",
+    "clashDifferentNumber": "Neither, let me change the number",
+    "workshopCountry": "Which country is your workshop in?",
+    "workshopCountryPlaceholder": "Choose a country",
+    "workshopCountryHint": "Asked once. After this, mobile numbers can be typed the short way. You can change it later in <link>Localisation settings</link>.",
+    "phonePreview": "Saved as",
+    "stepScannedTitle": "{name} is in",
+    "countrySearch": "Search countries",
+    "countryNoMatch": "No country matches that",
+    "choiceStandalone": "A name for the board only",
+    "choiceStandaloneHint": "An apprentice, a contractor, anyone you schedule but who never signs in. No phone, no email, no account. You can give them one later.",
+    "standaloneDetailsTitle": "Their name, and a colour",
+    "standaloneDetailsBlurb": "This is all they get, and all they need. They appear on the work board and on jobs, and there is nothing for them to sign into.",
+    "boardColour": "Colour on the board",
+    "stepStandaloneTitle": "{name} is on the board",
+    "stepStandaloneBody": "You can schedule them and put them on jobs straight away. If they ever need the app, add a mobile number to them from this list.",
+    "boardOnly": "On the board only",
+    "boardOnlyHint": "Scheduled and put on jobs, but they never sign in. Give them a mobile number when they need the app.",
+    "boardOnlyNoAccount": "No account",
+    "giveApp": "Give them the app",
+    "giveAppTitle": "Give {name} the app",
+    "giveAppBlurb": "A mobile number is all that is missing. They sign in with it from then on.",
+    "giveAppKeepsHistory": "Everything already recorded against them stays where it is.",
+    "giveAppSubmit": "Create their account",
+    "role": "Role",
+    "inviteMemberHint": "They get an email and choose their own password.",
+    "removeBoardOnlyTitle": "Take {name} off the board?",
+    "removeBoardOnlyBody": "{name} stops appearing on the work board and can no longer be put on jobs. Work already recorded against them, and the hours they clocked, stay exactly as they are.",
+    "removeBoardOnlyDone": "{name} is off the board",
+    "noRole": "No role",
+    "worksOnJobs": "Works on jobs",
+    "createDefaultRoles": "Create the standard roles",
+    "defaultRolesCreated": "Standard roles created",
+    "noRolesYet": "This workshop has no roles yet, so there is nothing to give them beyond Admin. Create the standard ones and narrow the permissions later.",
+    "noRoleDescription": "No permissions at all. They can sign in and every screen will refuse them until you give them a role below.",
+    "cannotUseApp": "Their role cannot work on jobs. Give them Technician, or a role with the same permissions, first.",
+    "revokeTechnicianDone": "{name} has been signed out of the app",
+    "noAccessTitle": "No access yet",
+    "noAccessBody": "Your account is part of {workshop}, but it has not been given a role, so there is nothing here you can open yet. Ask an owner or an admin at your workshop to give you one.",
+    "setupPageInstall": "Get it on Google Play"
   },
   "invoice": {
     "title": "Invoice & Quotes",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "Assigned numbers to {count} customers",
     "allCustomersNumbered": "All customers have a number.",
     "assignCustomerNumbersConfirmTitle": "Assign customer numbers?",
-    "assignCustomerNumbersConfirmDescription": "This will give sequential numbers to the {count} customers that have no number yet, in the order they were created, continuing after your highest existing number. Customers that already have a number are not changed. Numbers can be edited afterwards."
+    "assignCustomerNumbersConfirmDescription": "This will give sequential numbers to the {count} customers that have no number yet, in the order they were created, continuing after your highest existing number. Customers that already have a number are not changed. Numbers can be edited afterwards.",
+    "layoutColorsHint": "Colors, fonts and the header style live in Templates.",
+    "goToTemplates": "Open Templates",
+    "lockTitle": "Locking finished documents",
+    "lockDescription": "Stop an invoice or quote being changed once it is settled.",
+    "lockWhatItDoes": "What it freezes: parts, labour, quantities, prices, discount, tax, the document number and its date. Deleting the document is blocked too.",
+    "lockWhatItAllows": "What still works: recording payments, online card payments, status changes, sending and re-sending, attachments and internal notes. A locked invoice can always still be paid.",
+    "lockUnlockNote": "Owners and admins can unlock a single document from its own page when something genuinely needs correcting. Every unlock is recorded in the audit log.",
+    "lockInvoicesLabel": "Lock invoices",
+    "lockTriggerSent": "Once the invoice is sent",
+    "lockTriggerPaid": "Once the invoice is paid in full",
+    "lockTriggerSentHint": "Locks as soon as the invoice is emailed or a share link is created. Invoices sent before you turned this on are not affected.",
+    "lockTriggerPaidHint": "Locks once the full amount is settled, or the invoice is marked paid by hand. A part-paid invoice stays editable.",
+    "lockQuotesLabel": "Lock quotes",
+    "quoteLockTriggerSent": "Once the quote is sent",
+    "quoteLockTriggerAccepted": "Once the quote is accepted",
+    "quoteLockTriggerSentHint": "Locks as soon as the quote goes to the customer. Choose this only if you never revise a quote during negotiation.",
+    "quoteLockTriggerAcceptedHint": "Locks once the customer has accepted the quote, or it has been converted to a job. Sent quotes stay editable."
   },
   "layoutEditor": {
     "helpText": "Drag to reorder. Use the width toggle to place sections side-by-side. Consecutive half-width sections (L/R) will render in two columns.",
     "addField": "Add field",
     "custom": "custom",
     "full": "Full",
+    "boxed": "Box",
+    "plain": "Plain",
+    "boxedHint": "Prints inside a panel",
+    "plainHint": "Prints without a panel",
     "L": "L",
     "R": "R",
     "left": "left",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Full width — click to make half width (left)",
     "sections": {
       "header": "Header",
+      "slogan": "Slogan",
       "customer": "Customer",
       "vehicle": "Vehicle",
       "service": "Service",
+      "document_title": "Document Title",
+      "items_table": "Items Table",
       "parts_table": "Parts Table",
       "labor_table": "Labor Table",
       "totals": "Totals",
       "notes": "Notes",
+      "attached_documents": "Attached Documents",
       "diagnostic_notes": "Diagnostic Notes",
       "findings": "Observations",
+      "warranty": "Warranty",
       "bank_account": "Bank Account",
       "footer": "Footer",
       "general": "General",
@@ -493,12 +626,59 @@
       "tech_name": "Technician",
       "logo": "Logo",
       "company_name": "Company Name",
+      "company_slogan": "Slogan",
       "company_address": "Address",
       "company_phone": "Phone",
       "company_email": "Email",
       "company_org_number": "Organization Number",
       "bank_account": "Bank Account",
-      "org_number": "Organization Number"
+      "footer_note": "Footer Note",
+      "org_number": "Organization Number",
+      "portal_link": "Portal Link"
+    },
+    "presetsTitle": "Start from an arrangement",
+    "presetsHint": "Replaces the arrangement below. Nothing is saved until you save.",
+    "presets": {
+      "classic": {
+        "name": "Classic",
+        "description": "Parts and labor in separate tables, details stacked on the left"
+      },
+      "letterhead": {
+        "name": "Letterhead",
+        "description": "Contact details along the bottom, title below the addresses"
+      },
+      "compact": {
+        "name": "Compact",
+        "description": "No panels, only the essentials"
+      },
+      "minimal": {
+        "name": "Minimal",
+        "description": "Bare type on white: no boxes, no bands, just rules and whitespace"
+      },
+      "itemized": {
+        "name": "Itemized",
+        "description": "One numbered item list with a unit column"
+      },
+      "detailed": {
+        "name": "Detailed",
+        "description": "Title up top, vehicle on its own, both tables and every optional block"
+      }
+    },
+    "style": {
+      "documentTitle": "Whole sheet",
+      "documentHint": "size, spacing, accent, banding",
+      "textColor": "Text",
+      "labelColor": "Heading",
+      "backgroundColor": "Fill",
+      "borderColor": "Border",
+      "fontSize": "Size",
+      "rowPadding": "Row height",
+      "margin": "Margin",
+      "accentColor": "Accent",
+      "stripeColor": "Band",
+      "stripes": "Banding",
+      "fontFamily": "Font",
+      "fontInherit": "Inherit"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Template Presets",
     "primaryColor": "Primary Color",
+    "colors": "Colors",
+    "textColor": "Text",
+    "textColorHint": "The color of headings and body text",
+    "companyTextColor": "Company name",
+    "companyTextColorHint": "The color of the name on the letterhead",
+    "frameBorderColor": "Frame line",
+    "frameBorderColorHint": "The line where the frame meets the paper",
+    "frameShadow": "Frame shadow",
+    "frameShadowOn": "Shadow",
+    "frameShadowOff": "Flat",
+    "backgroundColor": "Background",
+    "backgroundColorClear": "Clear",
+    "backgroundColorHint": "Leave empty for white paper. A light tint prints as a tinted sheet.",
     "fontAndLayout": "Font & Layout",
     "fontFamily": "Font Family",
     "helveticaDefault": "Helvetica (Default)",
@@ -525,6 +718,10 @@
     "standard": "Standard",
     "compact": "Compact",
     "modern": "Modern",
+    "framed": "Framed",
+    "letterheadMark": "Letterhead mark",
+    "letterheadLogo": "Logo",
+    "letterheadCompanyName": "Company name",
     "preview": "{name} Preview",
     "billTo": "Bill To",
     "preparedFor": "Prepared For",
@@ -594,7 +791,11 @@
       "slate": "Slate",
       "rose": "Rose",
       "indigo": "Indigo"
-    }
+    },
+    "goToLayout": "Layout and sections",
+    "openDesigner": "Open Template Designer",
+    "designerIntro": "Pick a starting point, then open the designer to change anything.",
+    "designerHint": "Colors, fonts, spacing and every section live in the designer."
   },
   "payment": {
     "readMore": "Read More",
@@ -739,6 +940,7 @@
       "NGN": "Nigerian Naira",
       "KES": "Kenyan Shilling",
       "MAD": "Moroccan Dirham",
+      "DZD": "Algerian Dinar",
       "GHS": "Ghanaian Cedi",
       "QAR": "Qatari Riyal",
       "KWD": "Kuwaiti Dinar",
@@ -805,7 +1007,16 @@
     "failedSave": "Failed to save field",
     "failedDelete": "Failed to delete",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Unassigned",
+    "defaultValue": "Default value",
+    "defaultValueHint": "Pre-filled on new records and printed when no value has been entered.",
+    "defaultValueNone": "None",
+    "defaultValueCheckedHint": "Checked by default",
+    "placement": "Placement on document",
+    "placementHidden": "Not printed",
+    "placementHint": "Which section of the invoice or quote this field prints in. In the designer you can also switch it on in more sections.",
+    "failedSavePlacement": "Failed to save field placement"
   },
   "workshop": {
     "title": "Workshop Defaults",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Check failed",
       "configurePerPart": "Set a part's own Min Qty on the inventory page →",
       "readMore": "Read More"
+    },
+    "technicianStatus": {
+      "title": "Torqvoice Technician App (Android/iOS)",
+      "description": "Told when a technician moves a job from their phone.",
+      "inApp": "Notify the desk",
+      "inAppHint": "A notification when a job is finished, parked for parts, or picked back up.",
+      "save": "Save",
+      "saved": "Alert settings saved",
+      "saveFailed": "Could not save the settings"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Send and receive Telegram messages with your customers directly from Torqvoice."
       }
     }
+  },
+  "designer": {
+    "invoice": "Invoice",
+    "quote": "Quote",
+    "eyebrow": "Document designer",
+    "galleryTitle": "Start from a template",
+    "galleryHint": "Pick a starting point. You can change everything in the designer.",
+    "yourDesigns": "Your designs",
+    "templates": "Templates",
+    "inUse": "In use",
+    "savedOn": "Saved {date}",
+    "deleteDesignTitle": "Delete design",
+    "deleteDesignBody": "Delete the design \"{name}\"? The invoice and quote keep whatever is applied; only the saved copy goes.",
+    "delete": "Delete",
+    "deleteDesign": "Delete this design",
+    "continueCurrent": "Continue with my current layout",
+    "backToSettings": "Back to settings",
+    "useInvoiceDesign": "Use invoice design",
+    "copiedToQuote": "Invoice design copied to the quote",
+    "rulers": "Rulers",
+    "saveDesign": "Save design",
+    "saveDesignHint": "Keep a named copy of this design, to come back to from the template gallery",
+    "reset": "Reset",
+    "save": "Save",
+    "saving": "Saving…",
+    "saved": "Saved",
+    "couldNotSave": "Could not save",
+    "couldNotSaveDesigns": "Could not save your designs",
+    "designUpdated": "Updated \"{name}\"",
+    "designSaved": "Saved as \"{name}\"",
+    "defaultDesignName": "My {doc} design",
+    "documentStyling": "Document styling",
+    "sections": "Sections",
+    "sectionEmpty": "empty",
+    "sectionEmptyHint": "Shown, but there is nothing to print in it with the current data.",
+    "sectionShownHint": "Shown on the sheet. Click to hide it.",
+    "sectionHiddenHint": "Hidden from the sheet. Click to show it.",
+    "railHint": "Drag a section on the page: drop it between blocks to reorder, onto a card to sit beside it, or anywhere else to place it freely. The page makes room around it.",
+    "returnToFlow": "Return {section} to the flow",
+    "saveDialogTitle": "Save this design",
+    "saveDialogBody": "Keeps a named copy of the current arrangement and look. Find it again under Your designs in the template gallery.",
+    "designNamePlaceholder": "Design name",
+    "nameExists": "A design with this name exists; saving updates it.",
+    "updateDesign": "Update design",
+    "cancel": "Cancel",
+    "insertHere": "Insert here",
+    "dropLeftColumn": "Left column",
+    "dropRightColumn": "Right column",
+    "freePosition": "Free position",
+    "sectionSettings": "Section settings",
+    "panelStyle": "Panel style",
+    "variant": {
+      "accent": "Accent",
+      "panel": "Panel",
+      "outline": "Outline",
+      "lines": "Lines",
+      "hint": "Accent tints the card with the primary color. Panel matches the other detail cards. Outline draws only a border, and Lines prints without a box.",
+      "classic": "Classic",
+      "box": "Boxed",
+      "totalsHint": "Classic prints bare lines with a rule above the total. Boxed frames them. Panel and Accent set them on a card."
+    },
+    "alignment": "Alignment",
+    "alignCenter": "Center",
+    "itemsTableHint": "One numbered list of every line on the job, labor first and parts after, in place of the separate parts and labor tables.",
+    "discardChanges": "Discard changes",
+    "tablesExclusiveHint": "The sheet prints one arrangement: a single numbered list, or separate parts and labor tables. Switching one on switches the other off.",
+    "innerPadding": "Inner spacing",
+    "totalsWidth": "Width",
+    "totalsWidthHint": "Empty spans the row. Set points to hang the box on the right; in a column it takes the column's width.",
+    "placement": "Placement",
+    "visible": "Visible",
+    "columnFull": "Full",
+    "columnLeft": "Left",
+    "columnRight": "Right",
+    "drawBox": "Draw a box",
+    "showHeading": "Show heading",
+    "spacing": "Spacing",
+    "placedByHand": "This section is placed by hand, so flow spacing does not move it.",
+    "placedByHandFramed": "The framed letterhead sits on the band; drag it to move it.",
+    "placedByHandDrag": "Drag it, or return it to the flow, to use spacing.",
+    "marginTop": "Top",
+    "marginBottom": "Bottom",
+    "marginLeft": "Left",
+    "marginRight": "Right",
+    "spacingHint": "Points of empty room the section keeps around itself in the flow.",
+    "logo": "Logo",
+    "size": "Size",
+    "logoHint": "Turn the logo off under Fields to print the company name instead.",
+    "fields": "Fields",
+    "removeField": "Remove from this section",
+    "yourCustomFields": "Your custom fields",
+    "appearance": "Appearance",
+    "details": "Details",
+    "text": "Text",
+    "companyName": "Company name",
+    "heading": "Heading",
+    "fill": "Fill",
+    "border": "Border",
+    "lineWidth": "Line width",
+    "borderWidth": "Border width",
+    "outerBorder": "Outer border",
+    "rowBanding": "Row banding",
+    "likeSheet": "Like sheet",
+    "on": "On",
+    "off": "Off",
+    "font": "Font",
+    "inherit": "Inherit",
+    "auto": "auto",
+    "sectionDragHint": "Drag this section in the list, or on the page, to move it. Once placed by hand, the arrow keys nudge it a point at a time, ten with Shift, and Escape cancels a drag.",
+    "document": "Document",
+    "documentSubtitle": "Applies to the whole sheet",
+    "headerStyleTitle": "Header style",
+    "headerStyle": {
+      "standard": {
+        "name": "Standard",
+        "desc": "Name and details on white, rule beneath"
+      },
+      "compact": {
+        "name": "Compact",
+        "desc": "Tight header, dense rows"
+      },
+      "modern": {
+        "name": "Modern",
+        "desc": "Full-width colored banner"
+      },
+      "framed": {
+        "name": "Framed",
+        "desc": "Band across the top, rail down the left"
+      }
+    },
+    "colors": "Colors",
+    "primary": "Primary",
+    "background": "Background",
+    "accent": "Accent",
+    "frame": "Frame",
+    "rail": "Rail",
+    "leftEdge": "Left edge",
+    "rightEdge": "Right edge",
+    "frameLine": "Frame line",
+    "cornerRadius": "Corner radius",
+    "shadow": "Shadow",
+    "shadowThin": "Thin",
+    "shadowNormal": "Normal",
+    "shadowWide": "Wide",
+    "typography": "Typography",
+    "baseSize": "Base size",
+    "page": "Page",
+    "margins": "Margins",
+    "rowHeight": "Row height",
+    "band": "Band",
+    "sample": {
+      "itemLabor": "Front brakes replaced",
+      "itemDisc": "Brake disc, front",
+      "itemPads": "Brake pad set, front axle",
+      "itemConsumables": "Consumables",
+      "unitPcs": "pcs",
+      "unitSet": "set",
+      "unitEach": "x",
+      "findingPads": "Rear pads at 15%",
+      "findingPadsNote": "Replace within 5,000 km",
+      "findingOilWeep": "Small oil weep at valve cover",
+      "notes": "Thank you for choosing our workshop. Contact us if you have any questions.",
+      "warranty": "12 months warranty on parts and labour.",
+      "serviceTitle": "Annual service and brakes",
+      "serviceType": "Repair",
+      "companyName": "Your Workshop",
+      "slogan": "Quality service you can trust",
+      "footerNote": "Thank you for your business",
+      "value": "Sample"
+    },
+    "logoUpload": "Upload logo",
+    "logoReplace": "Replace logo",
+    "logoUploading": "Uploading…",
+    "logoFailed": "Could not upload that image",
+    "footerLogoHint": "Switch the logo on under Fields to print it at the foot of the page too.",
+    "logoReset": "Use the company logo",
+    "logoOwn": "Printed on this document only. The company logo is unchanged.",
+    "logoInherited": "Using the company logo. Upload one here to use a different mark on this document only.",
+    "slogan": "Slogan",
+    "sloganPlaceholderHint": "No slogan is set, so the sheet shows a stand-in that will not print.",
+    "sloganSetHint": "Your slogan comes from your company details.",
+    "sloganLink": "Company settings",
+    "placeholder": "Placeholder",
+    "leaveTitle": "Leave without saving?",
+    "leaveBody": "Your changes to this design have not been saved. They will be lost.",
+    "leaveConfirm": "Leave",
+    "boldField": "Bold"
+  },
+  "preview": {
+    "title": "Brake Service & Oil Change",
+    "serviceType": "Maintenance",
+    "findingPads": "Rear brake pads worn to 15%",
+    "findingPadsNote": "Recommend replacement within 5,000 miles",
+    "findingOilLeak": "Minor oil leak at valve cover gasket",
+    "invoiceNotes": "Front brake pads replaced. Oil and filter changed with synthetic 5W-30. Next service recommended at 50,000 miles.",
+    "quoteNotes": "Front brake pads replacement recommended. Oil and filter change with synthetic 5W-30.",
+    "partBrakePads": "Brake Pads (Front)",
+    "partOilFilter": "Oil Filter",
+    "partSyntheticOil": "Synthetic Oil 5W-30",
+    "laborBrakeReplacement": "Brake Replacement",
+    "laborOilChange": "Oil Change"
   }
 }

+ 4 - 2
messages/en/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "High",
     "findingSeverityNeedsWork": "Medium",
     "findingSeverityMonitor": "Low",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Additional information"
   },
   "quote": {
     "title": "Quote",
@@ -125,7 +126,8 @@
       "converted": "Converted",
       "changes_requested": "Changes Requested"
     },
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Additional information"
   },
   "inspection": {
     "title": "Vehicle Inspection",

+ 2 - 1
messages/en/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Nothing attached yet. Photograph a kerbed rim or damage while the tires are in front of you.",
     "captionPlaceholder": "What does this show?",
     "onInvoice": "On the invoice",
-    "invoiceHint": "Files marked for the invoice are copied onto the work order or invoice when this set is billed.",
+    "invoiceHint": "Photos marked for the invoice are copied onto the work order or invoice when this set is billed. Documents stay here with the set.",
+    "documentStays": "Stays with the set, not copied to invoices",
     "deleteTitle": "Remove this file?",
     "deleteBody": "{name} is removed from this set. Anything already copied onto an invoice stays there.",
     "failed": "Could not save that",

+ 3 - 1
messages/en/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "Answers which concern?",
+    "concernNone": "Not something the customer asked about"
   },
   "observationsPage": {
     "searchPlaceholder": "Search description, notes, or vehicle...",

+ 4 - 1
messages/en/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Standalone technician",
     "deleteTitle": "Delete Technician",
     "deleteDescription": "Remove \"{name}\" from the work board? Their existing assignments will also be removed.",
-    "addTechnician": "Add Technician"
+    "addTechnician": "Add Technician",
+    "standaloneOnly": "A name on the board for somebody who does not sign in, like an apprentice or a contractor. To add a mechanic who uses the app, add them on the Team page.",
+    "linkedTo": "Signs in as {name}",
+    "linkedManagedOnTeam": "Managed on the Team page, along with their app access."
   },
   "jobDetail": {
     "viewDetails": "View Details",

+ 12 - 2
messages/es/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Puesto de trabajo creado",
     "work_bay_update": "Puesto de trabajo actualizado",
     "work_bay_delete": "Puesto de trabajo eliminado",
+    "auth_appSetupRedeemed": "Sesión iniciada con código de configuración",
+    "auth_technicianCodeSignIn": "Sesión iniciada con código de un solo uso",
+    "team_createAppSetupCode": "Código de configuración de la aplicación emitido",
+    "team_createTechnicianAccount": "Cuenta de técnico creada",
+    "team_removeTechnicianAccess": "Técnico eliminado y acceso revocado",
+    "team_setMemberTechnician": "Cambiado si un miembro es técnico",
     "settings_whatsappUpdated": "Ajustes de WhatsApp actualizados",
+    "settings_whatsappDisconnected": "WhatsApp desconectado",
     "settings_whatsappNumberRegistered": "Número de WhatsApp registrado",
-    "settings_whatsappDisconnected": "WhatsApp desconectado"
+    "team_giveTechnicianTheApp": "Cuenta dada a un técnico solo de tablero",
+    "team_createDefaultRoles": "Roles estándar creados",
+    "settings_setCustomFieldPlacement": "Ubicación de campo personalizado actualizada"
   },
   "summary": {
     "customField_create": "Campo personalizado «{name}» creado",
@@ -265,6 +274,7 @@
     "whatsapp_send": "Envió un mensaje de WhatsApp a {name}",
     "work_bay_create": "Puesto de trabajo «{name}» creado",
     "work_bay_update": "Puesto de trabajo «{name}» actualizado",
-    "work_bay_delete": "Puesto de trabajo {id} eliminado"
+    "work_bay_delete": "Puesto de trabajo {id} eliminado",
+    "settings_setCustomFieldPlacement": "Cambió dónde se imprime un campo personalizado"
   }
 }

+ 5 - 0
messages/es/common.json

@@ -95,5 +95,10 @@
     "placeholder": "p. ej. Tenemos problemas con nuestra infraestructura de servidores y estamos trabajando en ello.",
     "posted": "Aviso publicado",
     "cleared": "Aviso retirado"
+  },
+  "pdfPreview": {
+    "title": "Vista previa del PDF",
+    "preview": "Vista previa",
+    "failed": "No se pudo generar la vista previa del PDF."
   }
 }

+ 21 - 1
messages/es/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Exento de impuestos",
     "tabs": {
       "vehicles": "Vehículos ({count})",
+      "invoices": "Facturas ({count})",
+      "quotes": "Presupuestos ({count})",
       "messages": "Mensajes",
       "requests": "Solicitudes ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Horas de Motor",
       "services": "Servicios"
     },
-    "noVehicles": "No hay vehículos asignados a este cliente"
+    "documentTable": {
+      "invoiceNumber": "N.º de factura",
+      "quoteNumber": "N.º de presupuesto",
+      "title": "Título",
+      "vehicle": "Vehículo",
+      "status": "Estado",
+      "date": "Fecha",
+      "total": "Total",
+      "noVehicle": "Solo piezas",
+      "searchPlaceholder": "Buscar...",
+      "noMatches": "No hay resultados para tu búsqueda",
+      "sort": {
+        "asc": "ascendente",
+        "desc": "descendente"
+      }
+    },
+    "noVehicles": "No hay vehículos asignados a este cliente",
+    "noInvoices": "No hay facturas para este cliente",
+    "noQuotes": "No hay presupuestos para este cliente"
   },
   "form": {
     "addTitle": "Agregar Nuevo Cliente",

+ 27 - 0
messages/es/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "This invoice is locked because it has been sent",
+      "paid": "This invoice is locked because it has been paid"
+    },
+    "quote": {
+      "sent": "This quote is locked because it has been sent",
+      "accepted": "This quote is locked because it has been accepted"
+    }
+  },
+  "lockedBody": "Its parts, labour, prices, discount, tax, number and date can no longer be changed. Payments, status changes, sending and attachments all still work.",
+  "lockedAdminHint": "As an owner or admin you can unlock it if something genuinely needs correcting. The unlock is recorded in the audit log.",
+  "lockedMemberHint": "Ask an owner or admin to unlock it if something needs correcting.",
+  "unlock": "Unlock for editing",
+  "relock": "Lock again",
+  "unlockConfirmTitle": "Unlock this document?",
+  "unlockConfirmDescription": {
+    "invoice": "It will become editable again, and the change will be recorded in the audit log with your name. Prefer a credit note where your local rules require one.",
+    "quote": "It will become editable again, and the change will be recorded in the audit log with your name."
+  },
+  "unlocked": "Unlocked for editing",
+  "relocked": "Locked again",
+  "reopenedTitle": "This document has been unlocked for editing",
+  "reopenedBody": "It stays editable until it is locked again.",
+  "failed": "Could not change the lock"
+}

+ 5 - 0
messages/es/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram está activo",
     "body": "Las conversaciones con clientes llegan aquí. Responde sin salir de la app."
+  },
+  "invoice-designer": {
+    "title": "Las facturas se han renovado",
+    "body": "Define el diseño, los colores y las tipografías de tus facturas y presupuestos en el nuevo diseñador, en Plantillas.",
+    "cta": "Abrir Plantillas"
   }
 }

+ 3 - 1
messages/es/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Vehículo",
     "quote": "Presupuesto",
     "part": "Pieza",
-    "inspection": "Inspección"
+    "inspection": "Inspección",
+    "shopActions": "Taller",
+    "person": "Añadir a una persona"
   },
   "purchaseWhiteLabel": "Adquirir marca blanca",
   "licenseExpired": "Su licencia ha expirado. Las funciones pueden estar limitadas.",

+ 13 - 2
messages/es/pdf.json

@@ -19,6 +19,12 @@
     "description": "Descripción",
     "qty": "Cant.",
     "unitPrice": "Precio unitario",
+    "items": "Artículos",
+    "pos": "N.º",
+    "unitOfMeasure": "Unidad",
+    "invoiceNumberLabel": "N.º de factura",
+    "customerNumberLabel": "N.º de cliente",
+    "dateLabel": "Fecha",
     "total": "Total",
     "labor": "Mano de obra",
     "hours": "Horas",
@@ -64,7 +70,9 @@
     "professionalWorkshop": "Gestión profesional de talleres",
     "tel": "Tel: {phone}",
     "org": "Org: {org}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Información adicional",
+    "telegramConnect": "Chatea con nosotros en Telegram"
   },
   "quote": {
     "title": "PRESUPUESTO",
@@ -100,7 +108,10 @@
     "validityFooter30": "Este presupuesto es válido por 30 días",
     "viewPortal": "Ver su portal: {url}",
     "tel": "Tel: {phone}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Información adicional",
+    "quoteNumberLabel": "N.º de presupuesto",
+    "validUntilLabel": "Válido hasta"
   },
   "inspection": {
     "title": "INSPECCIÓN DE VEHÍCULO",

+ 3 - 1
messages/es/quotes.json

@@ -48,7 +48,9 @@
       "details": "Detalles",
       "images": "Imágenes",
       "documents": "Documentos"
-    }
+    },
+    "customFieldsInvalid": "Completa todos los campos personalizados obligatorios",
+    "customFieldsSaveFailed": "No se pudieron guardar los campos personalizados"
   },
   "form": {
     "newQuote": "Nuevo presupuesto",

+ 31 - 2
messages/es/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "PAGADO",
     "entityLabel": "Factura",
     "emailSubject": "Confirmación de Pago",
-    "statusEmailSubject": "Actualización del estado del servicio"
+    "statusEmailSubject": "Actualización del estado del servicio",
+    "markCompletedTitle": "¿Marcar esta factura como completada?",
+    "markCompletedDescription": "Ya se ha enviado al cliente, pero sigue marcada como no terminada, así que continuará apareciendo en el tablero.",
+    "markCompletedConfirm": "Marcar como completada",
+    "lockedFieldsetLabel": "Factura bloqueada, edición desactivada"
   },
   "payments": {
     "title": "Pagos",
@@ -344,7 +348,23 @@
     "setDefaults": "Configurar valores",
     "workBay": "Puesto de trabajo",
     "selectWorkBay": "Seleccionar puesto…",
-    "noWorkBay": "Sin puesto"
+    "noWorkBay": "Sin puesto",
+    "technicians": "Técnicos",
+    "otherTeamMembers": "Otros miembros del equipo",
+    "makeTechnician": "Lo convierte en técnico",
+    "addSomeoneNew": "Añadir a alguien nuevo",
+    "notOnBoard": "Aún no está en el tablero",
+    "putOnBoard": "Poner en el tablero",
+    "slotTaken": "{count, plural, one {Esta franja ya está reservada} other {Esta franja tiene # conflictos}}",
+    "anotherJob": "otro trabajo",
+    "clashTechnician": "el técnico está ocupado",
+    "clashBay": "la bahía está ocupada",
+    "clashBoth": "ambos están ocupados",
+    "bookedAnyway": "Guardado igualmente. Cambia la hora o elige la siguiente franja libre.",
+    "pickNextAvailable": "Elegir la siguiente franja libre",
+    "findingSlot": "Buscando una franja…",
+    "slotPicked": "Reservado en la siguiente franja libre",
+    "noSlotFound": "No se encontró ninguna franja libre en las próximas semanas"
   },
   "notifications": {
     "title": "Notificaciones al cliente",
@@ -381,5 +401,14 @@
       "title": "Configuración de garantía predeterminada",
       "description": "Establecer términos de garantía predeterminados para nuevos registros de servicio"
     }
+  },
+  "concerns": {
+    "title": "Motivos del cliente",
+    "addFirst": "Añadir un motivo del cliente",
+    "add": "Añadir otro",
+    "placeholder": "Hace un ruido detrás cuando freno",
+    "remove": "Quitar este punto",
+    "notAnswered": "Todavía no se ha encontrado nada",
+    "answered": "{count} hallazgo(s) sobre esto"
   }
 }

+ 428 - 7
messages/es/settings.json

@@ -161,6 +161,9 @@
     "email": "Correo electrónico",
     "emailPlaceholder": "servicio@ejemplo.com",
     "address": "Dirección",
+    "slogan": "Eslogan",
+    "sloganPlaceholder": "Servicio y reparación para todas las marcas",
+    "sloganHint": "Una línea bajo tu nombre en facturas y presupuestos.",
     "addressPlaceholder": "Calle Principal 123\nPiso 1\n12345 Ciudad",
     "saveCompany": "Guardar datos de empresa",
     "addNewCompany": "Agregar nueva empresa",
@@ -380,7 +383,7 @@
     "adminLabel": "Administrador",
     "adminDescription": "Puede invitar/eliminar miembros y gestionar datos compartidos.",
     "memberLabel": "Miembro",
-    "memberDescription": "Permisos determinados por el rol personalizado asignado. Sin rol personalizado significa acceso de solo lectura.",
+    "memberDescription": "Los permisos dependen del rol asignado. Sin rol, este miembro no puede hacer nada.",
     "roleAssigned": "Rol actualizado",
     "failedAssignRole": "Error al actualizar el rol",
     "removeMemberTitle": "Eliminar miembro",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Error al actualizar el rol",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Técnico",
+    "technicianHint": "Puede recibir trabajos asignados y usar la aplicación de técnico",
+    "technicianFailed": "No se pudo cambiar",
+    "setupApp": "Configurar la aplicación",
+    "setupAppTitle": "Configurar la aplicación de técnico",
+    "setupAppInstruction": "Pida a {name} que haga esto en su teléfono:",
+    "setupAppOrType": "O léale este código:",
+    "setupAppExpiry": "Se usa una sola vez y caduca en {time}.",
+    "setupAppExpired": "Este código ha caducado. Cierre y empiece de nuevo.",
+    "setupAppDone": "Hecho",
+    "setupAppFailed": "No se pudo crear un código de configuración",
+    "setupPageTitle": "Configurar la aplicación de técnico",
+    "setupPageBody": "Abra Torqvoice Tech en este teléfono, toque Escanear código de configuración y apunte otra vez al mismo código.",
+    "setupPageCode": "O escriba este código en la aplicación",
+    "setupPageOpenApp": "Abrir Torqvoice Tech",
+    "setupPageExpiry": "Este código se usa una sola vez y caduca diez minutos después de que su taller lo creara.",
+    "setupAppStep1": "Instalar Torqvoice Tech",
+    "setupAppStep2": "Abrirla y tocar «Escanear código de configuración»",
+    "setupAppStep3": "Apuntar el teléfono a este código",
+    "setupAppNotCamera": "La cámara normal del teléfono no funciona. Hay que escanearlo desde dentro de Torqvoice Tech.",
+    "addTechnician": "Añadir un técnico",
+    "addTechnicianHint": "Para un mecánico que está en el mostrador. Sin correo y sin esperas.",
+    "technicianName": "Nombre",
+    "technicianNamePlaceholder": "Su nombre completo",
+    "technicianPhone": "Número de móvil",
+    "technicianPhonePlaceholder": "El teléfono que lleva encima",
+    "addTechnicianSubmit": "Crear",
+    "addTechnicianNote": "A partir de ahí entra con ese número. Sin contraseña que recordar y sin nada que escribir en la primera pantalla.",
+    "addTechnicianDone": "{name} está listo. Enséñele el código.",
+    "addTechnicianFailed": "No se pudo crear ese técnico",
+    "setupAppCopyLink": "Copiar el enlace para enviárselo",
+    "setupAppCopied": "Copiado",
+    "revokeTechnicianTitle": "¿Cerrarle la sesión en la aplicación?",
+    "revokeTechnicianBody": "{name} pierde el acceso en su teléfono al instante y cualquier código deja de funcionar. El trabajo hecho y las horas se quedan igual.",
+    "revokeTechnicianConfirm": "Cerrar sesión",
+    "addPerson": "Añadir",
+    "addPersonTitle": "Añadir a alguien al taller",
+    "addPersonWho": "Estos dos se configuran de forma distinta, así que empiece diciéndonos de quién se trata.",
+    "choiceTechnician": "Un mecánico",
+    "choiceTechnicianHint": "Trabaja en los coches y usa Torqvoice en el móvil. Lo más fácil es hacerlo mientras está aquí con usted, y lleva un minuto.",
+    "choiceMember": "Alguien de la oficina",
+    "choiceMemberHint": "Recibe coches, pide piezas y envía facturas, en un ordenador. Usted le envía un correo y él elige su propia contraseña.",
+    "stepLabelWho": "Quién",
+    "stepLabelDetails": "Datos",
+    "stepLabelPhone": "Su teléfono",
+    "techDetailsTitle": "Nombre y número de móvil",
+    "techDetailsBlurb": "Con ese móvil entrará a partir de ahora, así que use el teléfono que lleva de verdad. No hay contraseña que recordar ni que olvidar.",
+    "techHandoffTitle": "Ahora pásselo a su teléfono",
+    "techHandoffBlurb": "Este código conecta su teléfono con su taller. Sirve una vez y solo durante diez minutos, así que hágalo mientras está aquí.",
+    "memberDetailsTitle": "Su dirección de correo",
+    "memberDetailsBlurb": "Recibe un correo con un enlace. Al abrirlo elige su contraseña y después aparece en la lista de arriba.",
+    "roleHint": "Los administradores pueden cambiar ajustes y añadir personas. Los demás hacen el trabajo del día a día.",
+    "stepBack": "Atrás",
+    "stepHandoffDone": "Ya lo ha escaneado",
+    "stepDoneTitle": "{name} ya está listo",
+    "stepDoneBody": "Puede abrir la aplicación y ver sus trabajos. La próxima vez entra solo con su móvil, sin código.",
+    "stepInvitedTitle": "Invitación enviada a {email}",
+    "stepInvitedBody": "Aparecerá en la lista en cuanto abra el correo y acepte. El enlace vale siete días.",
+    "stepDoneAnother": "Añadir a otra persona",
+    "clashTitle": "{name} ya tiene ese número",
+    "clashBlurb": "Dos personas no pueden compartir un móvil, porque es con lo que entran. ¿Cuál de estos casos es?",
+    "clashSamePerson": "Es {name}",
+    "clashSamePersonHint": "La misma persona que vuelve, o un nombre escrito de otra forma. Sus trabajos y horas siguen con ella, y el nombre que acaba de escribir sustituye al anterior.",
+    "clashTakeover": "No, es {name}",
+    "clashTakeoverHint": "Otra persona que ahora tiene ese número. {name} conserva todo lo que hizo aquí pero ya no puede entrar, y más adelante puede darle un número nuevo.",
+    "clashDifferentNumber": "Ninguno, quiero cambiar el número",
+    "workshopCountry": "¿En qué país está su taller?",
+    "workshopCountryPlaceholder": "Elija un país",
+    "workshopCountryHint": "Se pregunta una sola vez. Después los móviles se pueden escribir en formato corto. Puede cambiarlo más adelante en <link>Ajustes de localización</link>.",
+    "phonePreview": "Se guarda como",
+    "stepScannedTitle": "{name} ya está dentro",
+    "countrySearch": "Buscar países",
+    "countryNoMatch": "Ningún país coincide",
+    "choiceStandalone": "Solo un nombre para el tablero",
+    "choiceStandaloneHint": "Un aprendiz, un externo, cualquiera a quien planifique pero que nunca entra. Sin teléfono, sin correo, sin cuenta. Puede dársela más adelante.",
+    "standaloneDetailsTitle": "Su nombre y un color",
+    "standaloneDetailsBlurb": "Es todo lo que recibe y todo lo que necesita. Aparece en el tablero y en los trabajos, y no hay nada donde iniciar sesión.",
+    "boardColour": "Color en el tablero",
+    "stepStandaloneTitle": "{name} ya está en el tablero",
+    "stepStandaloneBody": "Puede planificarlo y asignarle trabajos de inmediato. Si algún día necesita la aplicación, añádale un móvil desde esta lista.",
+    "boardOnly": "Solo en el tablero",
+    "boardOnlyHint": "Se planifican y se les asignan trabajos, pero nunca entran. Deles un móvil cuando necesiten la aplicación.",
+    "boardOnlyNoAccount": "Sin cuenta",
+    "giveApp": "Darle la aplicación",
+    "giveAppTitle": "Dar la aplicación a {name}",
+    "giveAppBlurb": "Solo falta un número de móvil. Con él entrará a partir de ahora.",
+    "giveAppKeepsHistory": "Todo lo que ya tiene registrado se queda como está.",
+    "giveAppSubmit": "Crear su cuenta",
+    "role": "Rol",
+    "inviteMemberHint": "Recibe un correo y elige su propia contraseña.",
+    "removeBoardOnlyTitle": "¿Quitar a {name} del tablero?",
+    "removeBoardOnlyBody": "{name} deja de aparecer en el tablero y ya no se le puede asignar trabajos. El trabajo ya registrado y las horas fichadas quedan exactamente igual.",
+    "removeBoardOnlyDone": "{name} está fuera del tablero",
+    "noRole": "Sin rol",
+    "worksOnJobs": "Trabaja en los coches",
+    "createDefaultRoles": "Crear los roles estándar",
+    "defaultRolesCreated": "Roles estándar creados",
+    "noRolesYet": "Este taller aún no tiene roles, así que no hay nada que darle aparte de Admin. Cree los estándar y ajuste los permisos después.",
+    "noRoleDescription": "Sin permisos. Puede iniciar sesión, pero todas las pantallas lo rechazarán hasta que le dé un rol de los de abajo.",
+    "cannotUseApp": "Su rol no puede trabajar en los trabajos. Déle primero Técnico, o un rol con los mismos permisos.",
+    "revokeTechnicianDone": "{name} ha salido de la aplicación",
+    "noAccessTitle": "Sin acceso todavía",
+    "noAccessBody": "Su cuenta pertenece a {workshop}, pero no tiene un rol asignado, así que aquí no hay nada que pueda abrir. Pida un rol a un propietario o administrador de su taller.",
+    "setupPageInstall": "Consíguelo en Google Play"
   },
   "invoice": {
     "title": "Diseño de factura",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "Números asignados a {count} clientes",
     "allCustomersNumbered": "Todos los clientes tienen número.",
     "assignCustomerNumbersConfirmTitle": "¿Asignar números de cliente?",
-    "assignCustomerNumbersConfirmDescription": "Los {count} clientes sin número recibirán números secuenciales en el orden en que se crearon, continuando después del número existente más alto. Los clientes que ya tienen número no cambian. Los números se pueden editar después."
+    "assignCustomerNumbersConfirmDescription": "Los {count} clientes sin número recibirán números secuenciales en el orden en que se crearon, continuando después del número existente más alto. Los clientes que ya tienen número no cambian. Los números se pueden editar después.",
+    "layoutColorsHint": "Los colores, las fuentes y el estilo de encabezado están en Plantillas.",
+    "goToTemplates": "Abrir Plantillas",
+    "lockTitle": "Bloqueo de documentos finalizados",
+    "lockDescription": "Evita que una factura o un presupuesto se modifique una vez cerrado.",
+    "lockWhatItDoes": "Se bloquea: piezas, mano de obra, cantidades, precios, descuento, impuestos, número de documento y fecha. También se impide eliminarlo.",
+    "lockWhatItAllows": "Sigue funcionando: registrar pagos, pago con tarjeta en línea, cambios de estado, envío y reenvío, adjuntos y notas internas. Una factura bloqueada siempre se puede pagar.",
+    "lockUnlockNote": "Los propietarios y administradores pueden desbloquear un documento concreto desde su propia página cuando algo deba corregirse. Cada desbloqueo queda en el registro de auditoría.",
+    "lockInvoicesLabel": "Bloquear facturas",
+    "lockTriggerSent": "Cuando se envía la factura",
+    "lockTriggerPaid": "Cuando la factura está pagada por completo",
+    "lockTriggerSentHint": "Se bloquea en cuanto la factura se envía por correo o se crea un enlace para compartir. Las facturas enviadas antes de activarlo no se ven afectadas.",
+    "lockTriggerPaidHint": "Se bloquea cuando se salda el importe total o la factura se marca como pagada a mano. Una factura pagada en parte sigue siendo editable.",
+    "lockQuotesLabel": "Bloquear presupuestos",
+    "quoteLockTriggerSent": "Cuando se envía el presupuesto",
+    "quoteLockTriggerAccepted": "Cuando se acepta el presupuesto",
+    "quoteLockTriggerSentHint": "Se bloquea en cuanto el presupuesto llega al cliente. Elija esta opción solo si nunca revisa un presupuesto durante la negociación.",
+    "quoteLockTriggerAcceptedHint": "Se bloquea cuando el cliente acepta el presupuesto o este se convierte en un trabajo. Los presupuestos enviados siguen siendo editables."
   },
   "layoutEditor": {
     "helpText": "Arrastra para reordenar. Usa el selector de ancho para colocar secciones lado a lado. Las secciones consecutivas de medio ancho (I/D) se mostrarán en dos columnas.",
     "addField": "Añadir campo",
     "custom": "personalizado",
     "full": "Completo",
+    "boxed": "Marco",
+    "plain": "Sin marco",
+    "boxedHint": "Se imprime dentro de un panel",
+    "plainHint": "Se imprime sin panel",
     "L": "I",
     "R": "D",
     "left": "izquierda",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Ancho completo — clic para medio ancho (izquierda)",
     "sections": {
       "header": "Encabezado",
+      "slogan": "Eslogan",
       "customer": "Cliente",
       "vehicle": "Vehículo",
       "service": "Servicio",
+      "document_title": "Título del documento",
+      "items_table": "Tabla de artículos",
       "parts_table": "Piezas",
       "labor_table": "Mano de obra",
       "totals": "Totales",
       "notes": "Notas",
+      "attached_documents": "Documentos adjuntos",
       "diagnostic_notes": "Notas de diagnóstico",
       "findings": "Observaciones",
+      "warranty": "Garantía",
       "bank_account": "Cuenta bancaria",
       "footer": "Pie de página",
       "general": "General",
@@ -491,14 +624,61 @@
       "service_title": "Título del servicio",
       "service_type": "Tipo de servicio",
       "tech_name": "Técnico",
-      "logo": "Logo",
+      "logo": "Logotipo",
       "company_name": "Nombre de empresa",
+      "company_slogan": "Eslogan",
       "company_address": "Dirección",
       "company_phone": "Teléfono",
       "company_email": "Correo electrónico",
       "company_org_number": "Número de organización",
       "bank_account": "Cuenta bancaria",
-      "org_number": "Número de organización"
+      "footer_note": "Nota de pie",
+      "org_number": "Número de organización",
+      "portal_link": "Enlace al portal"
+    },
+    "presetsTitle": "Empezar con una disposición",
+    "presetsHint": "Sustituye la disposición de abajo. No se guarda nada hasta que guardes.",
+    "presets": {
+      "classic": {
+        "name": "Clásica",
+        "description": "Piezas y mano de obra en tablas separadas, datos apilados a la izquierda"
+      },
+      "letterhead": {
+        "name": "Membrete",
+        "description": "Datos de contacto abajo, título bajo las direcciones"
+      },
+      "compact": {
+        "name": "Compacta",
+        "description": "Sin paneles, solo lo esencial"
+      },
+      "minimal": {
+        "name": "Minimalista",
+        "description": "Solo tipografía sobre blanco: sin recuadros ni bandas, solo líneas y espacio"
+      },
+      "itemized": {
+        "name": "Detallado",
+        "description": "Una lista de posiciones numerada con columna de unidad"
+      },
+      "detailed": {
+        "name": "Detallada",
+        "description": "Título arriba, vehículo aparte, ambas tablas y todos los bloques opcionales"
+      }
+    },
+    "style": {
+      "documentTitle": "Hoja completa",
+      "documentHint": "tamaño, espaciado, acento, franjas",
+      "textColor": "Texto",
+      "labelColor": "Título",
+      "backgroundColor": "Relleno",
+      "borderColor": "Borde",
+      "fontSize": "Tamaño",
+      "rowPadding": "Alto de fila",
+      "margin": "Margen",
+      "accentColor": "Acento",
+      "stripeColor": "Franja",
+      "stripes": "Franjas",
+      "fontFamily": "Fuente",
+      "fontInherit": "Heredar"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Presets de plantilla",
     "primaryColor": "Color primario",
+    "colors": "Colores",
+    "textColor": "Texto",
+    "textColorHint": "El color de los títulos y del texto",
+    "companyTextColor": "Nombre de la empresa",
+    "companyTextColorHint": "El color del nombre en el membrete",
+    "frameBorderColor": "Línea del marco",
+    "frameBorderColorHint": "La línea donde el marco toca el papel",
+    "frameShadow": "Sombra del marco",
+    "frameShadowOn": "Con sombra",
+    "frameShadowOff": "Plano",
+    "backgroundColor": "Fondo",
+    "backgroundColorClear": "Restablecer",
+    "backgroundColorHint": "Déjalo vacío para papel blanco. Un tono claro se imprime como una hoja tintada.",
     "fontAndLayout": "Fuente y diseño",
     "fontFamily": "Familia tipográfica",
     "helveticaDefault": "Helvetica (Predeterminado)",
@@ -525,6 +718,10 @@
     "standard": "Estandar",
     "compact": "Compacto",
     "modern": "Moderno",
+    "framed": "Con marco",
+    "letterheadMark": "Membrete",
+    "letterheadLogo": "Logotipo",
+    "letterheadCompanyName": "Nombre de la empresa",
     "preview": "Vista previa de {name}",
     "billTo": "Facturar a",
     "preparedFor": "Preparado para",
@@ -594,7 +791,11 @@
     "layoutDescription": "Personaliza el orden y la visibilidad de las secciones en tus facturas y presupuestos.",
     "layoutSaved": "Disposición guardada correctamente",
     "layoutDocInvoice": "Factura",
-    "layoutDocQuote": "Presupuesto"
+    "layoutDocQuote": "Presupuesto",
+    "goToLayout": "Diseño y secciones",
+    "openDesigner": "Abrir el diseñador",
+    "designerIntro": "Elige un punto de partida y abre el diseñador para cambiar lo que quieras.",
+    "designerHint": "Los colores, las fuentes, los espacios y todas las secciones están en el diseñador."
   },
   "payment": {
     "readMore": "Leer más",
@@ -739,6 +940,7 @@
       "NGN": "Naira nigeriano",
       "KES": "Chelin keniano",
       "MAD": "Dirham marroqui",
+      "DZD": "Dinar argelino",
       "GHS": "Cedi ghanes",
       "QAR": "Riyal qatari",
       "KWD": "Dinar kuwaiti",
@@ -805,7 +1007,16 @@
     "failedSave": "No se pudo guardar el campo",
     "failedDelete": "No se pudo eliminar",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Sin asignar",
+    "defaultValue": "Valor predeterminado",
+    "defaultValueHint": "Se rellena automáticamente en registros nuevos y se imprime mientras no se haya introducido un valor.",
+    "defaultValueNone": "Ninguno",
+    "defaultValueCheckedHint": "Marcado por defecto",
+    "placement": "Ubicación en el documento",
+    "placementHidden": "No se imprime",
+    "placementHint": "En qué sección de la factura o del presupuesto se imprime este campo. En el diseñador también puedes activarlo en más secciones.",
+    "failedSavePlacement": "No se pudo guardar la ubicación del campo"
   },
   "workshop": {
     "title": "Valores predeterminados del taller",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Error al comprobar",
       "configurePerPart": "Defina la cantidad mínima de una pieza en la página de inventario →",
       "readMore": "Leer más"
+    },
+    "technicianStatus": {
+      "title": "Aplicación de técnico Torqvoice (Android/iOS)",
+      "description": "Aviso cuando un técnico cambia un trabajo desde su teléfono.",
+      "inApp": "Avisar a recepción",
+      "inAppHint": "Un aviso cuando un trabajo se termina, queda a la espera de piezas o se retoma.",
+      "save": "Guardar",
+      "saved": "Ajustes de avisos guardados",
+      "saveFailed": "No se pudieron guardar los ajustes"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Envía y recibe mensajes de Telegram con tus clientes desde Torqvoice."
       }
     }
+  },
+  "designer": {
+    "invoice": "Factura",
+    "quote": "Presupuesto",
+    "eyebrow": "Diseñador de documentos",
+    "galleryTitle": "Empieza con una plantilla",
+    "galleryHint": "Elige un punto de partida. Puedes cambiarlo todo en el diseñador.",
+    "yourDesigns": "Tus diseños",
+    "templates": "Plantillas",
+    "inUse": "En uso",
+    "savedOn": "Guardado el {date}",
+    "deleteDesignTitle": "Eliminar diseño",
+    "deleteDesignBody": "¿Eliminar el diseño «{name}»? La factura y el presupuesto conservan lo aplicado; solo desaparece la copia guardada.",
+    "delete": "Eliminar",
+    "deleteDesign": "Eliminar este diseño",
+    "continueCurrent": "Continuar con mi diseño actual",
+    "backToSettings": "Volver a ajustes",
+    "useInvoiceDesign": "Usar el diseño de la factura",
+    "copiedToQuote": "Diseño de la factura copiado al presupuesto",
+    "rulers": "Reglas",
+    "saveDesign": "Guardar diseño",
+    "saveDesignHint": "Guarda una copia con nombre de este diseño para volver a ella desde la galería de plantillas",
+    "reset": "Restablecer",
+    "save": "Guardar",
+    "saving": "Guardando…",
+    "saved": "Guardado",
+    "couldNotSave": "No se pudo guardar",
+    "couldNotSaveDesigns": "No se pudieron guardar tus diseños",
+    "designUpdated": "«{name}» actualizado",
+    "designSaved": "Guardado como «{name}»",
+    "defaultDesignName": "Mi diseño de {doc}",
+    "documentStyling": "Estilo del documento",
+    "sections": "Secciones",
+    "sectionEmpty": "vacía",
+    "sectionEmptyHint": "Se muestra, pero con los datos actuales no hay nada que imprimir en ella.",
+    "sectionShownHint": "Visible en la hoja. Haz clic para ocultarla.",
+    "sectionHiddenHint": "Oculta en la hoja. Haz clic para mostrarla.",
+    "railHint": "Arrastra una sección sobre la página: suéltala entre bloques para reordenar, sobre una tarjeta para colocarla al lado, o en cualquier otro sitio para situarla libremente. La página deja espacio a su alrededor.",
+    "returnToFlow": "Devolver {section} al flujo",
+    "saveDialogTitle": "Guardar este diseño",
+    "saveDialogBody": "Guarda una copia con nombre de la disposición y el aspecto actuales. La encontrarás en Tus diseños, dentro de la galería de plantillas.",
+    "designNamePlaceholder": "Nombre del diseño",
+    "nameExists": "Ya existe un diseño con este nombre; al guardar se actualizará.",
+    "updateDesign": "Actualizar diseño",
+    "cancel": "Cancelar",
+    "insertHere": "Insertar aquí",
+    "dropLeftColumn": "Columna izquierda",
+    "dropRightColumn": "Columna derecha",
+    "freePosition": "Posición libre",
+    "sectionSettings": "Ajustes de la sección",
+    "panelStyle": "Estilo del panel",
+    "variant": {
+      "accent": "Acento",
+      "panel": "Panel",
+      "outline": "Contorno",
+      "lines": "Líneas",
+      "hint": "Acento tiñe la tarjeta con el color principal. Panel iguala a las demás tarjetas de detalle. Contorno dibuja solo un borde, y Líneas imprime sin recuadro.",
+      "classic": "Clásico",
+      "box": "Recuadro",
+      "totalsHint": "Clásico imprime líneas sueltas con una regla sobre el total. Recuadro las enmarca. Panel y Acento las colocan en una tarjeta."
+    },
+    "alignment": "Alineación",
+    "alignCenter": "Centro",
+    "itemsTableHint": "Una lista numerada de todas las líneas del trabajo, primero mano de obra y luego piezas, en lugar de las tablas separadas.",
+    "discardChanges": "Descartar cambios",
+    "tablesExclusiveHint": "La hoja imprime una disposición: una lista numerada única o tablas separadas de piezas y mano de obra. Activar una desactiva la otra.",
+    "innerPadding": "Espaciado interno",
+    "totalsWidth": "Ancho",
+    "totalsWidthHint": "Vacío ocupa toda la fila. Con un valor en puntos, el bloque cuelga a la derecha; en una columna toma el ancho de la columna.",
+    "placement": "Colocación",
+    "visible": "Visible",
+    "columnFull": "Completa",
+    "columnLeft": "Izquierda",
+    "columnRight": "Derecha",
+    "drawBox": "Dibujar un recuadro",
+    "showHeading": "Mostrar encabezado",
+    "spacing": "Espaciado",
+    "placedByHand": "Esta sección está colocada a mano, así que el espaciado del flujo no la mueve.",
+    "placedByHandFramed": "El membrete enmarcado se apoya en la banda; arrástralo para moverlo.",
+    "placedByHandDrag": "Arrástrala, o devuélvela al flujo, para usar el espaciado.",
+    "marginTop": "Arriba",
+    "marginBottom": "Abajo",
+    "marginLeft": "Izquierda",
+    "marginRight": "Derecha",
+    "spacingHint": "Puntos de espacio libre que la sección mantiene a su alrededor en el flujo.",
+    "logo": "Logotipo",
+    "size": "Tamaño",
+    "logoHint": "Desactiva el logotipo en Campos para imprimir el nombre de la empresa en su lugar.",
+    "fields": "Campos",
+    "removeField": "Quitar de esta sección",
+    "yourCustomFields": "Tus campos personalizados",
+    "appearance": "Apariencia",
+    "details": "Detalles",
+    "text": "Texto",
+    "companyName": "Nombre de la empresa",
+    "heading": "Encabezado",
+    "fill": "Relleno",
+    "border": "Borde",
+    "lineWidth": "Grosor de línea",
+    "borderWidth": "Grosor del borde",
+    "outerBorder": "Borde exterior",
+    "rowBanding": "Franjas de fila",
+    "likeSheet": "Como la hoja",
+    "on": "Sí",
+    "off": "No",
+    "font": "Fuente",
+    "inherit": "Heredar",
+    "auto": "auto",
+    "sectionDragHint": "Arrastra esta sección en la lista, o sobre la página, para moverla. Una vez colocada a mano, las flechas la desplazan un punto cada vez, diez con Mayús, y Escape cancela el arrastre.",
+    "document": "Documento",
+    "documentSubtitle": "Se aplica a toda la hoja",
+    "headerStyleTitle": "Estilo de encabezado",
+    "headerStyle": {
+      "standard": {
+        "name": "Estándar",
+        "desc": "Nombre y datos sobre blanco, con una línea debajo"
+      },
+      "compact": {
+        "name": "Compacto",
+        "desc": "Encabezado ajustado, filas densas"
+      },
+      "modern": {
+        "name": "Moderno",
+        "desc": "Banda de color a todo lo ancho"
+      },
+      "framed": {
+        "name": "Enmarcado",
+        "desc": "Banda arriba y franja por el lado izquierdo"
+      }
+    },
+    "colors": "Colores",
+    "primary": "Principal",
+    "background": "Fondo",
+    "accent": "Acento",
+    "frame": "Marco",
+    "rail": "Franja",
+    "leftEdge": "Borde izquierdo",
+    "rightEdge": "Borde derecho",
+    "frameLine": "Línea del marco",
+    "cornerRadius": "Radio de esquina",
+    "shadow": "Sombra",
+    "shadowThin": "Fina",
+    "shadowNormal": "Normal",
+    "shadowWide": "Ancha",
+    "typography": "Tipografía",
+    "baseSize": "Tamaño base",
+    "page": "Página",
+    "margins": "Márgenes",
+    "rowHeight": "Alto de fila",
+    "band": "Franja",
+    "sample": {
+      "itemLabor": "Frenos delanteros sustituidos",
+      "itemDisc": "Disco de freno, delantero",
+      "itemPads": "Juego de pastillas, eje delantero",
+      "itemConsumables": "Consumibles",
+      "unitPcs": "uds",
+      "unitSet": "juego",
+      "unitEach": "x",
+      "findingPads": "Pastillas traseras al 15 %",
+      "findingPadsNote": "Sustituir antes de 5.000 km",
+      "findingOilWeep": "Ligero rezume de aceite en la tapa de balancines",
+      "notes": "Gracias por elegir nuestro taller. Contacta con nosotros si tienes alguna duda.",
+      "warranty": "12 meses de garantía en piezas y mano de obra.",
+      "serviceTitle": "Revisión anual y frenos",
+      "serviceType": "Reparación",
+      "companyName": "Tu taller",
+      "slogan": "Calidad de servicio en la que puedes confiar",
+      "footerNote": "Gracias por confiar en nosotros",
+      "value": "Ejemplo"
+    },
+    "logoUpload": "Subir logotipo",
+    "logoReplace": "Cambiar logotipo",
+    "logoUploading": "Subiendo…",
+    "logoFailed": "No se pudo subir la imagen",
+    "footerLogoHint": "Activa el logotipo en Campos para imprimirlo también al pie de la página.",
+    "logoReset": "Usar el logotipo de la empresa",
+    "logoOwn": "Se imprime solo en este documento. El logotipo de la empresa no cambia.",
+    "logoInherited": "Se usa el logotipo de la empresa. Sube uno aquí para usar otro solo en este documento.",
+    "slogan": "Eslogan",
+    "sloganPlaceholderHint": "No hay ningún eslogan definido, así que la hoja muestra un texto de ejemplo que no se imprimirá.",
+    "sloganSetHint": "Tu eslogan proviene de los datos de tu empresa.",
+    "sloganLink": "Ajustes de empresa",
+    "placeholder": "Marcador",
+    "leaveTitle": "¿Salir sin guardar?",
+    "leaveBody": "Los cambios de este diseño no se han guardado y se perderán.",
+    "leaveConfirm": "Salir",
+    "boldField": "Negrita"
+  },
+  "preview": {
+    "title": "Servicio de frenos y cambio de aceite",
+    "serviceType": "Mantenimiento",
+    "findingPads": "Pastillas traseras desgastadas al 15 %",
+    "findingPadsNote": "Se recomienda sustituirlas antes de 8.000 km",
+    "findingOilLeak": "Ligera fuga de aceite en la junta de la tapa de balancines",
+    "invoiceNotes": "Pastillas delanteras sustituidas. Aceite y filtro cambiados con sintético 5W-30. Próxima revisión recomendada a los 80.000 km.",
+    "quoteNotes": "Se recomienda sustituir las pastillas delanteras. Cambio de aceite y filtro con sintético 5W-30.",
+    "partBrakePads": "Pastillas de freno (delanteras)",
+    "partOilFilter": "Filtro de aceite",
+    "partSyntheticOil": "Aceite sintético 5W-30",
+    "laborBrakeReplacement": "Sustitución de frenos",
+    "laborOilChange": "Cambio de aceite"
   }
 }

+ 4 - 2
messages/es/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "Alta",
     "findingSeverityNeedsWork": "Media",
     "findingSeverityMonitor": "Baja",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Información adicional"
   },
   "quote": {
     "title": "Presupuesto",
@@ -125,7 +126,8 @@
       "converted": "Convertido",
       "changes_requested": "Cambios solicitados"
     },
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Información adicional"
   },
   "inspection": {
     "title": "Inspección de vehículo",

+ 2 - 1
messages/es/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Todavía no hay nada adjunto. Fotografía una llanta rozada mientras tienes los neumáticos delante.",
     "captionPlaceholder": "¿Qué se ve aquí?",
     "onInvoice": "En la factura",
-    "invoiceHint": "Los archivos marcados para la factura se copian a la orden o a la factura al facturar el juego.",
+    "invoiceHint": "Las fotos marcadas para la factura se copian a la orden o a la factura al facturar el juego. Los documentos se quedan aquí con el juego.",
+    "documentStays": "Se queda con el juego, no se copia a las facturas",
     "deleteTitle": "¿Quitar este archivo?",
     "deleteBody": "{name} se quita del juego. Lo que ya se copió a una factura se mantiene.",
     "failed": "No se pudo guardar",

+ 3 - 1
messages/es/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "¿Responde a qué punto?",
+    "concernNone": "No es algo que preguntara el cliente"
   },
   "observationsPage": {
     "searchPlaceholder": "Buscar descripción, notas o vehículo...",

+ 4 - 1
messages/es/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Técnico independiente",
     "deleteTitle": "Eliminar Técnico",
     "deleteDescription": "¿Desea eliminar a \"{name}\" del tablero de trabajo? Sus asignaciones existentes también se eliminarán.",
-    "addTechnician": "Agregar Técnico"
+    "addTechnician": "Agregar Técnico",
+    "standaloneOnly": "Un nombre en el tablero para alguien que no inicia sesión, como un aprendiz o un externo. Para un mecánico que usa la aplicación, añádalo en la página de Equipo.",
+    "linkedTo": "Entra como {name}",
+    "linkedManagedOnTeam": "Se gestiona en la página de Equipo, junto con su acceso a la aplicación."
   },
   "jobDetail": {
     "viewDetails": "Ver Detalles",

+ 12 - 2
messages/fr/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Poste de travail créé",
     "work_bay_update": "Poste de travail mis à jour",
     "work_bay_delete": "Poste de travail supprimé",
+    "auth_appSetupRedeemed": "Connexion avec un code de configuration",
+    "auth_technicianCodeSignIn": "Connexion avec un code à usage unique",
+    "team_createAppSetupCode": "Code de configuration de l'application émis",
+    "team_createTechnicianAccount": "Compte technicien créé",
+    "team_removeTechnicianAccess": "Technicien retiré et accès révoqué",
+    "team_setMemberTechnician": "Statut de technicien d'un membre modifié",
     "settings_whatsappUpdated": "Paramètres WhatsApp mis à jour",
+    "settings_whatsappDisconnected": "WhatsApp déconnecté",
     "settings_whatsappNumberRegistered": "Numéro WhatsApp enregistré",
-    "settings_whatsappDisconnected": "WhatsApp déconnecté"
+    "team_giveTechnicianTheApp": "Compte donné à un technicien du tableau",
+    "team_createDefaultRoles": "Rôles standard créés",
+    "settings_setCustomFieldPlacement": "Emplacement de champ personnalisé mis à jour"
   },
   "summary": {
     "customField_create": "Champ personnalisé « {name} » créé",
@@ -265,6 +274,7 @@
     "whatsapp_send": "Message WhatsApp envoyé à {name}",
     "work_bay_create": "Poste de travail « {name} » créé",
     "work_bay_update": "Poste de travail « {name} » mis à jour",
-    "work_bay_delete": "Poste de travail {id} supprimé"
+    "work_bay_delete": "Poste de travail {id} supprimé",
+    "settings_setCustomFieldPlacement": "A modifié l'emplacement d'impression d'un champ personnalisé"
   }
 }

+ 5 - 0
messages/fr/common.json

@@ -95,5 +95,10 @@
     "placeholder": "ex. Nous rencontrons des difficultés avec notre infrastructure serveur et y travaillons.",
     "posted": "Message publié",
     "cleared": "Message retiré"
+  },
+  "pdfPreview": {
+    "title": "Aperçu du PDF",
+    "preview": "Aperçu",
+    "failed": "Impossible de générer l'aperçu du PDF."
   }
 }

+ 21 - 1
messages/fr/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Exonéré de taxe",
     "tabs": {
       "vehicles": "Véhicules ({count})",
+      "invoices": "Factures ({count})",
+      "quotes": "Devis ({count})",
       "messages": "Messages",
       "requests": "Demandes ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Heures Moteur",
       "services": "Services"
     },
-    "noVehicles": "Aucun véhicule associé à ce client"
+    "documentTable": {
+      "invoiceNumber": "N° de facture",
+      "quoteNumber": "N° de devis",
+      "title": "Titre",
+      "vehicle": "Véhicule",
+      "status": "Statut",
+      "date": "Date",
+      "total": "Total",
+      "noVehicle": "Pièces uniquement",
+      "searchPlaceholder": "Rechercher...",
+      "noMatches": "Aucun résultat pour votre recherche",
+      "sort": {
+        "asc": "croissant",
+        "desc": "décroissant"
+      }
+    },
+    "noVehicles": "Aucun véhicule associé à ce client",
+    "noInvoices": "Aucune facture pour ce client",
+    "noQuotes": "Aucun devis pour ce client"
   },
   "form": {
     "addTitle": "Ajouter un nouveau client",

+ 27 - 0
messages/fr/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "This invoice is locked because it has been sent",
+      "paid": "This invoice is locked because it has been paid"
+    },
+    "quote": {
+      "sent": "This quote is locked because it has been sent",
+      "accepted": "This quote is locked because it has been accepted"
+    }
+  },
+  "lockedBody": "Its parts, labour, prices, discount, tax, number and date can no longer be changed. Payments, status changes, sending and attachments all still work.",
+  "lockedAdminHint": "As an owner or admin you can unlock it if something genuinely needs correcting. The unlock is recorded in the audit log.",
+  "lockedMemberHint": "Ask an owner or admin to unlock it if something needs correcting.",
+  "unlock": "Unlock for editing",
+  "relock": "Lock again",
+  "unlockConfirmTitle": "Unlock this document?",
+  "unlockConfirmDescription": {
+    "invoice": "It will become editable again, and the change will be recorded in the audit log with your name. Prefer a credit note where your local rules require one.",
+    "quote": "It will become editable again, and the change will be recorded in the audit log with your name."
+  },
+  "unlocked": "Unlocked for editing",
+  "relocked": "Locked again",
+  "reopenedTitle": "This document has been unlocked for editing",
+  "reopenedBody": "It stays editable until it is locked again.",
+  "failed": "Could not change the lock"
+}

+ 5 - 0
messages/fr/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram est activé",
     "body": "Les conversations clients arrivent ici. Répondez sans quitter l'application."
+  },
+  "invoice-designer": {
+    "title": "Les factures ont été repensées",
+    "body": "Définissez la mise en page, les couleurs et les polices de vos factures et devis dans le nouvel éditeur, sous Modèles.",
+    "cta": "Ouvrir Modèles"
   }
 }

+ 3 - 1
messages/fr/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Véhicule",
     "quote": "Devis",
     "part": "Pièce",
-    "inspection": "Inspection"
+    "inspection": "Inspection",
+    "shopActions": "Atelier",
+    "person": "Ajouter une personne"
   },
   "purchaseWhiteLabel": "Acheter la marque blanche",
   "licenseExpired": "Votre licence a expiré. Les fonctionnalités peuvent être limitées.",

+ 13 - 2
messages/fr/pdf.json

@@ -19,6 +19,12 @@
     "description": "Description",
     "qty": "Qté",
     "unitPrice": "Prix unitaire",
+    "items": "Articles",
+    "pos": "N°",
+    "unitOfMeasure": "Unité",
+    "invoiceNumberLabel": "N° de facture",
+    "customerNumberLabel": "N° de client",
+    "dateLabel": "Date",
     "total": "Total",
     "labor": "Main-d'œuvre",
     "hours": "Heures",
@@ -64,7 +70,9 @@
     "professionalWorkshop": "Gestion professionnelle d'atelier",
     "tel": "Tél. : {phone}",
     "org": "Org. : {org}",
-    "qtyOrHours": "Unité / Heures"
+    "qtyOrHours": "Unité / Heures",
+    "customFieldsTitle": "Informations complémentaires",
+    "telegramConnect": "Discutez avec nous sur Telegram"
   },
   "quote": {
     "title": "DEVIS",
@@ -100,7 +108,10 @@
     "validityFooter30": "Ce devis est valable 30 jours",
     "viewPortal": "Consultez votre portail : {url}",
     "tel": "Tél. : {phone}",
-    "qtyOrHours": "Unité / Heures"
+    "qtyOrHours": "Unité / Heures",
+    "customFieldsTitle": "Informations complémentaires",
+    "quoteNumberLabel": "N° de devis",
+    "validUntilLabel": "Valable jusqu'au"
   },
   "inspection": {
     "title": "INSPECTION DU VÉHICULE",

+ 3 - 1
messages/fr/quotes.json

@@ -48,7 +48,9 @@
       "details": "Détails",
       "images": "Images",
       "documents": "Documents"
-    }
+    },
+    "customFieldsInvalid": "Veuillez remplir tous les champs personnalisés obligatoires",
+    "customFieldsSaveFailed": "Impossible d'enregistrer les champs personnalisés"
   },
   "form": {
     "newQuote": "Nouveau devis",

+ 31 - 2
messages/fr/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "PAYÉ",
     "entityLabel": "Facture",
     "emailSubject": "Confirmation de Paiement",
-    "statusEmailSubject": "Mise à jour du statut du service"
+    "statusEmailSubject": "Mise à jour du statut du service",
+    "markCompletedTitle": "Marquer cette facture comme terminée ?",
+    "markCompletedDescription": "Elle est partie chez le client mais reste marquée comme non terminée, elle continuera donc d'apparaître sur le tableau.",
+    "markCompletedConfirm": "Marquer comme terminée",
+    "lockedFieldsetLabel": "Facture verrouillée, modification désactivée"
   },
   "payments": {
     "title": "Paiements",
@@ -344,7 +348,23 @@
     "setDefaults": "Paramètres par défaut",
     "workBay": "Poste de travail",
     "selectWorkBay": "Choisir un poste…",
-    "noWorkBay": "Aucun poste"
+    "noWorkBay": "Aucun poste",
+    "technicians": "Techniciens",
+    "otherTeamMembers": "Autres membres de l’équipe",
+    "makeTechnician": "En fait un technicien",
+    "addSomeoneNew": "Ajouter quelqu’un",
+    "notOnBoard": "Pas encore sur le planning",
+    "putOnBoard": "Mettre au planning",
+    "slotTaken": "{count, plural, one {Ce créneau est déjà réservé} other {Ce créneau a # conflits}}",
+    "anotherJob": "un autre travail",
+    "clashTechnician": "le technicien est occupé",
+    "clashBay": "la baie est occupée",
+    "clashBoth": "les deux sont occupés",
+    "bookedAnyway": "Enregistré quand même. Changez l'heure ou choisissez le prochain créneau libre.",
+    "pickNextAvailable": "Choisir le prochain créneau libre",
+    "findingSlot": "Recherche d'un créneau…",
+    "slotPicked": "Placé sur le prochain créneau libre",
+    "noSlotFound": "Aucun créneau libre trouvé dans les prochaines semaines"
   },
   "notifications": {
     "title": "Notifications client",
@@ -381,5 +401,14 @@
       "title": "Paramètres de garantie par défaut",
       "description": "Définir les conditions de garantie par défaut pour les nouveaux dossiers de service"
     }
+  },
+  "concerns": {
+    "title": "Demandes du client",
+    "addFirst": "Ajouter une demande du client",
+    "add": "En ajouter un autre",
+    "placeholder": "Il y a un bruit à l'arrière quand je freine",
+    "remove": "Retirer ce point",
+    "notAnswered": "Rien trouvé à ce sujet pour l'instant",
+    "answered": "{count} constat(s) à ce sujet"
   }
 }

+ 427 - 6
messages/fr/settings.json

@@ -161,6 +161,9 @@
     "email": "E-mail",
     "emailPlaceholder": "service@exemple.com",
     "address": "Adresse",
+    "slogan": "Slogan",
+    "sloganPlaceholder": "Entretien et réparation toutes marques",
+    "sloganHint": "Une ligne sous votre nom sur les factures et les devis.",
     "addressPlaceholder": "123 Rue Principale\nEtage 1\n75001 Paris",
     "saveCompany": "Enregistrer les détails",
     "addNewCompany": "Ajouter une entreprise",
@@ -380,7 +383,7 @@
     "adminLabel": "Administrateur",
     "adminDescription": "Peut inviter/supprimer des membres et gérer les données partagées.",
     "memberLabel": "Membre",
-    "memberDescription": "Permissions determinees par le role personnalise assigne. Sans role personnalise, accès en lecture seule.",
+    "memberDescription": "Les droits découlent du rôle attribué. Sans rôle, ce membre ne peut rien faire.",
     "roleAssigned": "Role mis a jour",
     "failedAssignRole": "Échec de la mise a jour du role",
     "removeMemberTitle": "Retirer le membre",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Échec de la mise a jour du role",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Technicien",
+    "technicianHint": "Peut se voir attribuer des travaux et utiliser l’application technicien",
+    "technicianFailed": "Modification impossible",
+    "setupApp": "Configurer l'application",
+    "setupAppTitle": "Configurer l'application technicien",
+    "setupAppInstruction": "Demandez à {name} de faire ceci sur son téléphone :",
+    "setupAppOrType": "Ou communiquez-lui ce code :",
+    "setupAppExpiry": "Utilisable une seule fois, expire dans {time}.",
+    "setupAppExpired": "Ce code a expiré. Fermez et recommencez.",
+    "setupAppDone": "Terminé",
+    "setupAppFailed": "Impossible de créer un code de configuration",
+    "setupPageTitle": "Configurer l'application technicien",
+    "setupPageBody": "Ouvrez Torqvoice Tech sur ce téléphone, appuyez sur Scanner le code de configuration, et visez à nouveau le même code.",
+    "setupPageCode": "Ou saisissez ce code dans l'application",
+    "setupPageOpenApp": "Ouvrir Torqvoice Tech",
+    "setupPageExpiry": "Ce code est utilisable une seule fois et expire dix minutes après sa création par votre atelier.",
+    "setupAppStep1": "Installer Torqvoice Tech",
+    "setupAppStep2": "L’ouvrir et appuyer sur « Scanner le code de configuration »",
+    "setupAppStep3": "Viser ce code avec le téléphone",
+    "setupAppNotCamera": "L'appareil photo du téléphone ne fonctionnera pas. Le code doit être scanné depuis Torqvoice Tech.",
+    "addTechnician": "Ajouter un technicien",
+    "addTechnicianHint": "Pour un mécanicien présent au comptoir. Sans e-mail, sans attente.",
+    "technicianName": "Nom",
+    "technicianNamePlaceholder": "Son nom complet",
+    "technicianPhone": "Numéro de mobile",
+    "technicianPhonePlaceholder": "Le téléphone qu’il a sur lui",
+    "addTechnicianSubmit": "Créer",
+    "addTechnicianNote": "Il se connectera ensuite avec ce numéro. Aucun mot de passe à retenir et rien à saisir sur le premier écran de l'application.",
+    "addTechnicianDone": "{name} est créé. Montrez-lui le code.",
+    "addTechnicianFailed": "Impossible de créer ce technicien",
+    "setupAppCopyLink": "Copier le lien à envoyer",
+    "setupAppCopied": "Copié",
+    "revokeTechnicianTitle": "Le déconnecter de l'application ?",
+    "revokeTechnicianBody": "{name} perd immédiatement l'accès sur son téléphone et tout code cesse de fonctionner. Le travail terminé et les heures restent tels quels.",
+    "revokeTechnicianConfirm": "Le déconnecter",
+    "addPerson": "Ajouter",
+    "addPersonTitle": "Ajouter quelqu'un à l'atelier",
+    "addPersonWho": "Ces deux profils se configurent différemment, alors commencez par nous dire de qui il s'agit.",
+    "choiceTechnician": "Un mécanicien",
+    "choiceTechnicianHint": "Travaille sur les voitures et utilise Torqvoice sur son téléphone. Le plus simple pendant qu'il est là avec vous, et cela prend environ une minute.",
+    "choiceMember": "Quelqu’un au bureau",
+    "choiceMemberHint": "Réceptionne les voitures, commande les pièces et envoie les factures, sur un ordinateur. Vous envoyez un e-mail et il choisit son propre mot de passe.",
+    "stepLabelWho": "Qui",
+    "stepLabelDetails": "Détails",
+    "stepLabelPhone": "Son téléphone",
+    "techDetailsTitle": "Nom et numéro de mobile",
+    "techDetailsBlurb": "C'est avec ce numéro qu'il se connectera désormais, alors prenez le téléphone qu'il a vraiment sur lui. Il n'y a aucun mot de passe à retenir ni à oublier.",
+    "techHandoffTitle": "Maintenant, sur son téléphone",
+    "techHandoffBlurb": "Ce code relie son téléphone à votre atelier. Il ne fonctionne qu'une fois et seulement pendant dix minutes, alors faites-le tant qu'il est là.",
+    "memberDetailsTitle": "Son adresse e-mail",
+    "memberDetailsBlurb": "Il reçoit un e-mail avec un lien. En l'ouvrant, il choisit son mot de passe et apparaît ensuite dans la liste ci-dessus.",
+    "roleHint": "Les administrateurs peuvent modifier les réglages et ajouter des personnes. Les autres font le travail quotidien.",
+    "stepBack": "Retour",
+    "stepHandoffDone": "Il l'a scanné",
+    "stepDoneTitle": "{name} est prêt",
+    "stepDoneBody": "Il peut ouvrir l'application et voir ses travaux. La prochaine fois, il se connecte avec son seul numéro de mobile, sans code.",
+    "stepInvitedTitle": "Invitation envoyée à {email}",
+    "stepInvitedBody": "Il apparaîtra dans la liste dès qu'il aura ouvert l'e-mail et accepté. Le lien reste valable sept jours.",
+    "stepDoneAnother": "Ajouter quelqu’un d’autre",
+    "clashTitle": "{name} a déjà ce numéro",
+    "clashBlurb": "Deux personnes ne peuvent pas partager un numéro de mobile, puisque c'est avec lui qu'elles se connectent. Duquel s'agit-il ?",
+    "clashSamePerson": "C'est {name}",
+    "clashSamePersonHint": "La même personne qui revient, ou un nom orthographié autrement. Ses travaux et ses heures restent avec elle, et le nom que vous venez de saisir remplace l'ancien.",
+    "clashTakeover": "Non, il s’agit de {name}",
+    "clashTakeoverHint": "Une autre personne qui a désormais ce numéro. {name} conserve tout ce qu'elle a fait ici mais ne peut plus se connecter, et vous pourrez lui donner un nouveau numéro plus tard.",
+    "clashDifferentNumber": "Ni l’un ni l’autre, je corrige le numéro",
+    "workshopCountry": "Dans quel pays se trouve votre atelier ?",
+    "workshopCountryPlaceholder": "Choisissez un pays",
+    "workshopCountryHint": "Demandé une seule fois. Ensuite, les numéros de mobile peuvent être saisis en format court. Vous pourrez le modifier dans les <link>paramètres de localisation</link>.",
+    "phonePreview": "Enregistré comme",
+    "stepScannedTitle": "{name} est connecté",
+    "countrySearch": "Rechercher un pays",
+    "countryNoMatch": "Aucun pays ne correspond",
+    "choiceStandalone": "Un nom pour le tableau seulement",
+    "choiceStandaloneHint": "Un apprenti, un sous-traitant, toute personne que vous planifiez mais qui ne se connecte jamais. Ni téléphone, ni e-mail, ni compte. Vous pourrez lui en donner un plus tard.",
+    "standaloneDetailsTitle": "Son nom, et une couleur",
+    "standaloneDetailsBlurb": "C'est tout ce qu'il obtient, et tout ce qu'il lui faut. Il apparaît sur le tableau et sur les travaux, et n'a rien où se connecter.",
+    "boardColour": "Couleur sur le tableau",
+    "stepStandaloneTitle": "{name} est sur le tableau",
+    "stepStandaloneBody": "Vous pouvez le planifier et l'affecter à des travaux tout de suite. S'il lui faut un jour l'application, ajoutez-lui un numéro de mobile depuis cette liste.",
+    "boardOnly": "Sur le tableau uniquement",
+    "boardOnlyHint": "Planifiés et affectés à des travaux, mais ne se connectent jamais. Donnez-leur un numéro de mobile quand ils auront besoin de l'application.",
+    "boardOnlyNoAccount": "Aucun compte",
+    "giveApp": "Donner l'application",
+    "giveAppTitle": "Donner l'application à {name}",
+    "giveAppBlurb": "Il ne manque qu'un numéro de mobile. C'est avec lui qu'il se connectera ensuite.",
+    "giveAppKeepsHistory": "Tout ce qui lui est déjà attribué reste en place.",
+    "giveAppSubmit": "Créer son compte",
+    "role": "Rôle",
+    "inviteMemberHint": "La personne reçoit un e-mail et choisit son propre mot de passe.",
+    "removeBoardOnlyTitle": "Retirer {name} du planning ?",
+    "removeBoardOnlyBody": "{name} n’apparaît plus sur le planning et ne peut plus être affecté à des travaux. Le travail déjà enregistré et les heures pointées restent exactement tels quels.",
+    "removeBoardOnlyDone": "{name} est retiré du planning",
+    "noRole": "Aucun rôle",
+    "worksOnJobs": "Travaille sur les véhicules",
+    "createDefaultRoles": "Créer les rôles standard",
+    "defaultRolesCreated": "Rôles standard créés",
+    "noRolesYet": "Cet atelier n’a encore aucun rôle, il n’y a donc rien à leur donner en dehors d’Admin. Créez les rôles standard et affinez les permissions plus tard.",
+    "noRoleDescription": "Aucune permission. La personne peut se connecter, mais chaque écran la refusera tant que vous ne lui aurez pas donné un rôle ci-dessous.",
+    "cannotUseApp": "Son rôle ne permet pas de travailler sur les travaux. Donnez-lui d’abord Technicien, ou un rôle ayant les mêmes permissions.",
+    "revokeTechnicianDone": "{name} a été déconnecté de l’application",
+    "noAccessTitle": "Pas encore d’accès",
+    "noAccessBody": "Votre compte fait partie de {workshop}, mais aucun rôle ne lui a été attribué, donc il n’y a rien à ouvrir ici. Demandez un rôle à un propriétaire ou un administrateur de votre atelier.",
+    "setupPageInstall": "Télécharger sur Google Play"
   },
   "invoice": {
     "title": "Mise en page de facture",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "Numéros attribués à {count} clients",
     "allCustomersNumbered": "Tous les clients ont un numéro.",
     "assignCustomerNumbersConfirmTitle": "Attribuer des numéros clients ?",
-    "assignCustomerNumbersConfirmDescription": "Les {count} clients sans numéro recevront des numéros séquentiels dans leur ordre de création, à la suite du numéro existant le plus élevé. Les clients ayant déjà un numéro ne sont pas modifiés. Les numéros restent modifiables ensuite."
+    "assignCustomerNumbersConfirmDescription": "Les {count} clients sans numéro recevront des numéros séquentiels dans leur ordre de création, à la suite du numéro existant le plus élevé. Les clients ayant déjà un numéro ne sont pas modifiés. Les numéros restent modifiables ensuite.",
+    "layoutColorsHint": "Les couleurs, les polices et le style d’en-tête sont dans Modèles.",
+    "goToTemplates": "Ouvrir Modèles",
+    "lockTitle": "Verrouillage des documents finalisés",
+    "lockDescription": "Empêche la modification d'une facture ou d'un devis une fois qu'il est réglé.",
+    "lockWhatItDoes": "Ce qui est verrouillé : pièces, main-d’œuvre, quantités, prix, remise, taxe, numéro et date du document. La suppression est également bloquée.",
+    "lockWhatItAllows": "Ce qui fonctionne encore : enregistrer des paiements, le paiement en ligne, les changements de statut, l’envoi et le renvoi, les pièces jointes et les notes internes. Une facture verrouillée reste toujours payable.",
+    "lockUnlockNote": "Les propriétaires et administrateurs peuvent déverrouiller un document depuis sa propre page lorsqu’une correction est réellement nécessaire. Chaque déverrouillage est consigné dans le journal d’audit.",
+    "lockInvoicesLabel": "Verrouiller les factures",
+    "lockTriggerSent": "Une fois la facture envoyée",
+    "lockTriggerPaid": "Une fois la facture intégralement payée",
+    "lockTriggerSentHint": "Verrouille dès que la facture est envoyée par e-mail ou qu'un lien de partage est créé. Les factures envoyées avant l'activation ne sont pas concernées.",
+    "lockTriggerPaidHint": "Verrouille une fois le montant total réglé ou la facture marquée payée à la main. Une facture partiellement payée reste modifiable.",
+    "lockQuotesLabel": "Verrouiller les devis",
+    "quoteLockTriggerSent": "Une fois le devis envoyé",
+    "quoteLockTriggerAccepted": "Une fois le devis accepté",
+    "quoteLockTriggerSentHint": "Verrouille dès que le devis part chez le client. À choisir uniquement si vous ne révisez jamais un devis en cours de négociation.",
+    "quoteLockTriggerAcceptedHint": "Verrouille une fois le devis accepté par le client ou converti en intervention. Les devis envoyés restent modifiables."
   },
   "layoutEditor": {
     "helpText": "Glissez pour réorganiser. Utilisez le sélecteur de largeur pour placer les sections côte à côte. Les sections consécutives en demi-largeur (G/D) s'afficheront en deux colonnes.",
     "addField": "Ajouter un champ",
     "custom": "personnalisé",
     "full": "Plein",
+    "boxed": "Cadre",
+    "plain": "Sans",
+    "boxedHint": "Imprimé dans un cadre",
+    "plainHint": "Imprimé sans cadre",
     "L": "G",
     "R": "D",
     "left": "gauche",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Pleine largeur — cliquer pour demi-largeur (gauche)",
     "sections": {
       "header": "En-tête",
+      "slogan": "Slogan",
       "customer": "Client",
       "vehicle": "Véhicule",
       "service": "Service",
+      "document_title": "Titre du document",
+      "items_table": "Tableau des articles",
       "parts_table": "Pièces",
       "labor_table": "Main-d'œuvre",
       "totals": "Totaux",
       "notes": "Notes",
+      "attached_documents": "Documents joints",
       "diagnostic_notes": "Notes de diagnostic",
       "findings": "Observations",
+      "warranty": "Garantie",
       "bank_account": "Compte bancaire",
       "footer": "Pied de page",
       "general": "Général",
@@ -493,12 +626,59 @@
       "tech_name": "Technicien",
       "logo": "Logo",
       "company_name": "Nom de l'entreprise",
+      "company_slogan": "Slogan",
       "company_address": "Adresse",
       "company_phone": "Téléphone",
       "company_email": "E-mail",
       "company_org_number": "Numéro d'organisation",
       "bank_account": "Compte bancaire",
-      "org_number": "Numéro d'organisation"
+      "footer_note": "Note de bas de page",
+      "org_number": "Numéro d'organisation",
+      "portal_link": "Lien du portail"
+    },
+    "presetsTitle": "Partir d’une disposition",
+    "presetsHint": "Remplace la disposition ci-dessous. Rien n’est enregistré avant votre validation.",
+    "presets": {
+      "classic": {
+        "name": "Classique",
+        "description": "Pièces et main-d’œuvre en tableaux séparés, informations empilées à gauche"
+      },
+      "letterhead": {
+        "name": "En-tête",
+        "description": "Coordonnées en bas, titre sous les adresses"
+      },
+      "compact": {
+        "name": "Compacte",
+        "description": "Sans cadres, l’essentiel seulement"
+      },
+      "minimal": {
+        "name": "Minimal",
+        "description": "Typographie nue sur blanc : sans encadrés ni bandeaux, seulement des filets et de l'espace"
+      },
+      "itemized": {
+        "name": "Détaillé",
+        "description": "Une liste de postes numérotée avec une colonne d'unité"
+      },
+      "detailed": {
+        "name": "Détaillée",
+        "description": "Titre en haut, véhicule seul, les deux tableaux et tous les blocs optionnels"
+      }
+    },
+    "style": {
+      "documentTitle": "Feuille entière",
+      "documentHint": "taille, espacement, accent, bandes",
+      "textColor": "Texte",
+      "labelColor": "Titre",
+      "backgroundColor": "Fond",
+      "borderColor": "Bordure",
+      "fontSize": "Taille",
+      "rowPadding": "Hauteur de ligne",
+      "margin": "Marge",
+      "accentColor": "Accent",
+      "stripeColor": "Bande",
+      "stripes": "Bandes",
+      "fontFamily": "Police",
+      "fontInherit": "Hériter"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Presets de modèle",
     "primaryColor": "Couleur primaire",
+    "colors": "Couleurs",
+    "textColor": "Texte",
+    "textColorHint": "La couleur des titres et du corps de texte",
+    "companyTextColor": "Nom de la société",
+    "companyTextColorHint": "La couleur du nom sur l’en-tête",
+    "frameBorderColor": "Filet du cadre",
+    "frameBorderColorHint": "Le filet où le cadre rencontre le papier",
+    "frameShadow": "Ombre du cadre",
+    "frameShadowOn": "Ombre",
+    "frameShadowOff": "Plat",
+    "backgroundColor": "Arrière-plan",
+    "backgroundColorClear": "Réinitialiser",
+    "backgroundColorHint": "Laissez vide pour du papier blanc. Une teinte claire imprime une feuille teintée.",
     "fontAndLayout": "Police et mise en page",
     "fontFamily": "Famille de police",
     "helveticaDefault": "Helvetica (Par défaut)",
@@ -525,6 +718,10 @@
     "standard": "Standard",
     "compact": "Compact",
     "modern": "Moderne",
+    "framed": "Encadré",
+    "letterheadMark": "En-tête",
+    "letterheadLogo": "Logo",
+    "letterheadCompanyName": "Nom de la société",
     "preview": "Aperçu {name}",
     "billTo": "Facturer à",
     "preparedFor": "Préparé pour",
@@ -594,7 +791,11 @@
     "layoutDescription": "Personnalisez l'ordre et la visibilité des sections dans vos factures et devis.",
     "layoutSaved": "Mise en page enregistrée",
     "layoutDocInvoice": "Facture",
-    "layoutDocQuote": "Devis"
+    "layoutDocQuote": "Devis",
+    "goToLayout": "Disposition et sections",
+    "openDesigner": "Ouvrir le concepteur",
+    "designerIntro": "Choisissez un point de départ, puis ouvrez le concepteur pour tout modifier.",
+    "designerHint": "Les couleurs, les polices, les espacements et toutes les sections sont dans le concepteur."
   },
   "payment": {
     "readMore": "En savoir plus",
@@ -739,6 +940,7 @@
       "NGN": "Naira nigerian",
       "KES": "Shilling kenyan",
       "MAD": "Dirham marocain",
+      "DZD": "Dinar algérien",
       "GHS": "Cedi ghaneen",
       "QAR": "Riyal qatari",
       "KWD": "Dinar koweitien",
@@ -805,7 +1007,16 @@
     "failedSave": "Impossible d'enregistrer le champ",
     "failedDelete": "Impossible de supprimer",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Non assigné",
+    "defaultValue": "Valeur par défaut",
+    "defaultValueHint": "Préremplie sur les nouvelles fiches et imprimée tant qu'aucune valeur n'a été saisie.",
+    "defaultValueNone": "Aucune",
+    "defaultValueCheckedHint": "Cochée par défaut",
+    "placement": "Emplacement sur le document",
+    "placementHidden": "Non imprimé",
+    "placementHint": "Dans quelle section de la facture ou du devis ce champ est imprimé. Dans le designer, vous pouvez aussi l'activer dans d'autres sections.",
+    "failedSavePlacement": "Impossible d'enregistrer l'emplacement du champ"
   },
   "workshop": {
     "title": "Valeurs par défaut de l'atelier",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Échec de la vérification",
       "configurePerPart": "Définir la Qté min d'une pièce sur la page inventaire →",
       "readMore": "En savoir plus"
+    },
+    "technicianStatus": {
+      "title": "Application technicien Torqvoice (Android/iOS)",
+      "description": "Notification lorsqu'un technicien modifie un travail depuis son téléphone.",
+      "inApp": "Prévenir l'accueil",
+      "inAppHint": "Une notification lorsqu'un travail est terminé, en attente de pièces ou repris.",
+      "save": "Enregistrer",
+      "saved": "Paramètres de notification enregistrés",
+      "saveFailed": "Impossible d'enregistrer les paramètres"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Envoyez et recevez des messages Telegram avec vos clients depuis Torqvoice."
       }
     }
+  },
+  "designer": {
+    "invoice": "Facture",
+    "quote": "Devis",
+    "eyebrow": "Concepteur de documents",
+    "galleryTitle": "Partir d'un modèle",
+    "galleryHint": "Choisissez un point de départ. Vous pourrez tout modifier dans le concepteur.",
+    "yourDesigns": "Vos maquettes",
+    "templates": "Modèles",
+    "inUse": "Utilisée",
+    "savedOn": "Enregistrée le {date}",
+    "deleteDesignTitle": "Supprimer la maquette",
+    "deleteDesignBody": "Supprimer la maquette « {name} » ? La facture et le devis conservent ce qui est appliqué ; seule la copie enregistrée disparaît.",
+    "delete": "Supprimer",
+    "deleteDesign": "Supprimer cette maquette",
+    "continueCurrent": "Continuer avec ma mise en page actuelle",
+    "backToSettings": "Retour aux paramètres",
+    "useInvoiceDesign": "Reprendre la maquette de la facture",
+    "copiedToQuote": "Maquette de la facture copiée vers le devis",
+    "rulers": "Règles",
+    "saveDesign": "Enregistrer la maquette",
+    "saveDesignHint": "Conservez une copie nommée de cette maquette pour la retrouver dans la galerie de modèles",
+    "reset": "Réinitialiser",
+    "save": "Enregistrer",
+    "saving": "Enregistrement…",
+    "saved": "Enregistré",
+    "couldNotSave": "Enregistrement impossible",
+    "couldNotSaveDesigns": "Impossible d'enregistrer vos maquettes",
+    "designUpdated": "« {name} » mise à jour",
+    "designSaved": "Enregistrée sous « {name} »",
+    "defaultDesignName": "Ma maquette de {doc}",
+    "documentStyling": "Style du document",
+    "sections": "Sections",
+    "sectionEmpty": "vide",
+    "sectionEmptyHint": "Affichée, mais avec les données actuelles elle n'a rien à imprimer.",
+    "sectionShownHint": "Visible sur la feuille. Cliquez pour la masquer.",
+    "sectionHiddenHint": "Masquée sur la feuille. Cliquez pour l'afficher.",
+    "railHint": "Faites glisser une section sur la page : déposez-la entre deux blocs pour la réordonner, sur une carte pour la placer à côté, ou ailleurs pour la positionner librement. La page fait de la place autour d'elle.",
+    "returnToFlow": "Remettre {section} dans le flux",
+    "saveDialogTitle": "Enregistrer cette maquette",
+    "saveDialogBody": "Conserve une copie nommée de la disposition et de l'apparence actuelles. Vous la retrouverez sous Vos maquettes, dans la galerie de modèles.",
+    "designNamePlaceholder": "Nom de la maquette",
+    "nameExists": "Une maquette porte déjà ce nom ; l'enregistrement la mettra à jour.",
+    "updateDesign": "Mettre à jour la maquette",
+    "cancel": "Annuler",
+    "insertHere": "Insérer ici",
+    "dropLeftColumn": "Colonne de gauche",
+    "dropRightColumn": "Colonne de droite",
+    "freePosition": "Position libre",
+    "sectionSettings": "Réglages de la section",
+    "panelStyle": "Style du panneau",
+    "variant": {
+      "accent": "Accent",
+      "panel": "Panneau",
+      "outline": "Contour",
+      "lines": "Lignes",
+      "hint": "Accent teinte la carte avec la couleur principale. Panneau s'aligne sur les autres cartes de détail. Contour ne trace qu'une bordure, et Lignes imprime sans encadré.",
+      "classic": "Classique",
+      "box": "Encadré",
+      "totalsHint": "Classique imprime des lignes nues avec un filet au-dessus du total. Encadré les entoure d'un cadre. Panneau et Accent les posent sur une carte."
+    },
+    "alignment": "Alignement",
+    "alignCenter": "Centre",
+    "itemsTableHint": "Une liste numérotée de toutes les lignes du travail, main-d'œuvre d'abord puis pièces, à la place des tableaux séparés.",
+    "discardChanges": "Annuler les modifications",
+    "tablesExclusiveHint": "La feuille imprime une disposition : une liste numérotée unique, ou des tableaux séparés pour pièces et main-d'œuvre. Activer l'une désactive l'autre.",
+    "innerPadding": "Marge intérieure",
+    "totalsWidth": "Largeur",
+    "totalsWidthHint": "Vide, le bloc occupe toute la ligne. Une valeur en points l'accroche à droite ; dans une colonne, il prend la largeur de la colonne.",
+    "placement": "Placement",
+    "visible": "Visible",
+    "columnFull": "Pleine",
+    "columnLeft": "Gauche",
+    "columnRight": "Droite",
+    "drawBox": "Tracer un encadré",
+    "showHeading": "Afficher le titre",
+    "spacing": "Espacement",
+    "placedByHand": "Cette section est placée à la main : l'espacement du flux ne la déplace pas.",
+    "placedByHandFramed": "L'en-tête encadré repose sur le bandeau ; faites-le glisser pour le déplacer.",
+    "placedByHandDrag": "Faites-la glisser, ou remettez-la dans le flux, pour utiliser l'espacement.",
+    "marginTop": "Haut",
+    "marginBottom": "Bas",
+    "marginLeft": "Gauche",
+    "marginRight": "Droite",
+    "spacingHint": "Points d'espace vide que la section garde autour d'elle dans le flux.",
+    "logo": "Logo",
+    "size": "Taille",
+    "logoHint": "Désactivez le logo sous Champs pour imprimer le nom de l'entreprise à la place.",
+    "fields": "Champs",
+    "removeField": "Retirer de cette section",
+    "yourCustomFields": "Vos champs personnalisés",
+    "appearance": "Apparence",
+    "details": "Détails",
+    "text": "Texte",
+    "companyName": "Nom de l'entreprise",
+    "heading": "Titre",
+    "fill": "Remplissage",
+    "border": "Bordure",
+    "lineWidth": "Épaisseur de trait",
+    "borderWidth": "Épaisseur de bordure",
+    "outerBorder": "Bordure extérieure",
+    "rowBanding": "Alternance de lignes",
+    "likeSheet": "Comme la feuille",
+    "on": "Activé",
+    "off": "Désactivé",
+    "font": "Police",
+    "inherit": "Hériter",
+    "auto": "auto",
+    "sectionDragHint": "Faites glisser cette section dans la liste, ou sur la page, pour la déplacer. Une fois placée à la main, les flèches la décalent d'un point, de dix avec Maj, et Échap annule un déplacement.",
+    "document": "Document",
+    "documentSubtitle": "S'applique à toute la feuille",
+    "headerStyleTitle": "Style d'en-tête",
+    "headerStyle": {
+      "standard": {
+        "name": "Standard",
+        "desc": "Nom et coordonnées sur blanc, filet en dessous"
+      },
+      "compact": {
+        "name": "Compact",
+        "desc": "En-tête resserré, lignes denses"
+      },
+      "modern": {
+        "name": "Moderne",
+        "desc": "Bandeau coloré pleine largeur"
+      },
+      "framed": {
+        "name": "Encadré",
+        "desc": "Bandeau en haut, filet sur le bord gauche"
+      }
+    },
+    "colors": "Couleurs",
+    "primary": "Principale",
+    "background": "Fond",
+    "accent": "Accent",
+    "frame": "Cadre",
+    "rail": "Filet",
+    "leftEdge": "Bord gauche",
+    "rightEdge": "Bord droit",
+    "frameLine": "Trait du cadre",
+    "cornerRadius": "Rayon des angles",
+    "shadow": "Ombre",
+    "shadowThin": "Fine",
+    "shadowNormal": "Normale",
+    "shadowWide": "Large",
+    "typography": "Typographie",
+    "baseSize": "Taille de base",
+    "page": "Page",
+    "margins": "Marges",
+    "rowHeight": "Hauteur de ligne",
+    "band": "Bande",
+    "sample": {
+      "itemLabor": "Freins avant remplacés",
+      "itemDisc": "Disque de frein, avant",
+      "itemPads": "Jeu de plaquettes, essieu avant",
+      "itemConsumables": "Consommables",
+      "unitPcs": "pcs",
+      "unitSet": "jeu",
+      "unitEach": "x",
+      "findingPads": "Plaquettes arrière à 15 %",
+      "findingPadsNote": "À remplacer sous 5 000 km",
+      "findingOilWeep": "Léger suintement d'huile au cache-culbuteurs",
+      "notes": "Merci d'avoir choisi notre atelier. Contactez-nous pour toute question.",
+      "warranty": "12 mois de garantie sur les pièces et la main-d'œuvre.",
+      "serviceTitle": "Révision annuelle et freins",
+      "serviceType": "Réparation",
+      "companyName": "Votre atelier",
+      "slogan": "Un service de qualité en toute confiance",
+      "footerNote": "Merci de votre confiance",
+      "value": "Exemple"
+    },
+    "logoUpload": "Importer un logo",
+    "logoReplace": "Remplacer le logo",
+    "logoUploading": "Import en cours…",
+    "logoFailed": "Impossible d'importer cette image",
+    "footerLogoHint": "Activez le logo dans Champs pour l'imprimer aussi en bas de page.",
+    "logoReset": "Utiliser le logo de l'entreprise",
+    "logoOwn": "Imprimé sur ce document uniquement. Le logo de l'entreprise reste inchangé.",
+    "logoInherited": "Le logo de l'entreprise est utilisé. Importez-en un ici pour en utiliser un autre sur ce document seulement.",
+    "slogan": "Slogan",
+    "sloganPlaceholderHint": "Aucun slogan n'est défini, la feuille affiche donc un texte d'exemple qui ne sera pas imprimé.",
+    "sloganSetHint": "Votre slogan provient des informations de votre entreprise.",
+    "sloganLink": "Paramètres de l'entreprise",
+    "placeholder": "Exemple",
+    "leaveTitle": "Quitter sans enregistrer ?",
+    "leaveBody": "Les modifications de cette maquette ne sont pas enregistrées et seront perdues.",
+    "leaveConfirm": "Quitter",
+    "boldField": "Gras"
+  },
+  "preview": {
+    "title": "Révision des freins et vidange",
+    "serviceType": "Entretien",
+    "findingPads": "Plaquettes arrière usées à 15 %",
+    "findingPadsNote": "Remplacement recommandé sous 8 000 km",
+    "findingOilLeak": "Léger suintement d'huile au joint de cache-culbuteurs",
+    "invoiceNotes": "Plaquettes avant remplacées. Huile et filtre changés avec de la synthèse 5W-30. Prochaine révision conseillée à 80 000 km.",
+    "quoteNotes": "Remplacement des plaquettes avant recommandé. Vidange et changement de filtre avec de la synthèse 5W-30.",
+    "partBrakePads": "Plaquettes de frein (avant)",
+    "partOilFilter": "Filtre à huile",
+    "partSyntheticOil": "Huile synthétique 5W-30",
+    "laborBrakeReplacement": "Remplacement des freins",
+    "laborOilChange": "Vidange"
   }
 }

+ 4 - 2
messages/fr/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "Haute",
     "findingSeverityNeedsWork": "Moyenne",
     "findingSeverityMonitor": "Basse",
-    "tel": "Tél. : {phone}"
+    "tel": "Tél. : {phone}",
+    "customFields": "Informations complémentaires"
   },
   "quote": {
     "title": "Devis",
@@ -125,7 +126,8 @@
       "converted": "Converti",
       "changes_requested": "Modifications demandées"
     },
-    "tel": "Tél. : {phone}"
+    "tel": "Tél. : {phone}",
+    "customFields": "Informations complémentaires"
   },
   "inspection": {
     "title": "Inspection du véhicule",

+ 2 - 1
messages/fr/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Rien de joint pour l’instant. Photographiez une jante frottée pendant que les pneus sont devant vous.",
     "captionPlaceholder": "Que montre cette image ?",
     "onInvoice": "Sur la facture",
-    "invoiceHint": "Les fichiers marqués pour la facture sont copiés sur l’ordre ou la facture au moment de facturer.",
+    "invoiceHint": "Les photos marquées pour la facture sont copiées sur l’ordre ou la facture au moment de facturer. Les documents restent ici avec le jeu.",
+    "documentStays": "Reste avec le jeu, non copié sur les factures",
     "deleteTitle": "Retirer ce fichier ?",
     "deleteBody": "{name} est retiré du jeu. Ce qui a déjà été copié sur une facture y reste.",
     "failed": "Impossible d’enregistrer",

+ 3 - 1
messages/fr/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "Répond à quel point ?",
+    "concernNone": "Rien que le client ait signalé"
   },
   "observationsPage": {
     "searchPlaceholder": "Rechercher une description, des notes ou un véhicule...",

+ 4 - 1
messages/fr/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Technicien autonome",
     "deleteTitle": "Supprimer le Technicien",
     "deleteDescription": "Supprimer \"{name}\" du tableau de bord des travaux? Ses assignations existantes seront également supprimées.",
-    "addTechnician": "Ajouter un Technicien"
+    "addTechnician": "Ajouter un Technicien",
+    "standaloneOnly": "Un nom sur le tableau pour quelqu'un qui ne se connecte pas, un apprenti ou un sous-traitant. Pour un mécanicien qui utilise l'application, passez par la page Équipe.",
+    "linkedTo": "Se connecte en tant que {name}",
+    "linkedManagedOnTeam": "Géré depuis la page Équipe, avec son accès à l'application."
   },
   "jobDetail": {
     "viewDetails": "Voir les Détails",

+ 12 - 2
messages/it/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Postazione creata",
     "work_bay_update": "Postazione aggiornata",
     "work_bay_delete": "Postazione eliminata",
+    "auth_appSetupRedeemed": "Accesso con codice di configurazione",
+    "auth_technicianCodeSignIn": "Accesso con codice monouso",
+    "team_createAppSetupCode": "Codice di configurazione dell'app emesso",
+    "team_createTechnicianAccount": "Account tecnico creato",
+    "team_removeTechnicianAccess": "Tecnico rimosso e accesso revocato",
+    "team_setMemberTechnician": "Modificato se un membro è tecnico",
     "settings_whatsappUpdated": "Impostazioni WhatsApp aggiornate",
+    "settings_whatsappDisconnected": "WhatsApp disconnesso",
     "settings_whatsappNumberRegistered": "Numero WhatsApp registrato",
-    "settings_whatsappDisconnected": "WhatsApp disconnesso"
+    "team_giveTechnicianTheApp": "Account dato a un tecnico solo da lavagna",
+    "team_createDefaultRoles": "Ruoli standard creati",
+    "settings_setCustomFieldPlacement": "Posizione del campo personalizzato aggiornata"
   },
   "summary": {
     "customField_create": "Campo personalizzato «{name}» creato",
@@ -265,6 +274,7 @@
     "whatsapp_send": "Inviato un messaggio WhatsApp a {name}",
     "work_bay_create": "Postazione «{name}» creata",
     "work_bay_update": "Postazione «{name}» aggiornata",
-    "work_bay_delete": "Postazione {id} eliminata"
+    "work_bay_delete": "Postazione {id} eliminata",
+    "settings_setCustomFieldPlacement": "Ha modificato dove viene stampato un campo personalizzato"
   }
 }

+ 5 - 0
messages/it/common.json

@@ -95,5 +95,10 @@
     "placeholder": "es. Stiamo riscontrando problemi con la nostra infrastruttura server e ci stiamo lavorando.",
     "posted": "Avviso pubblicato",
     "cleared": "Avviso rimosso"
+  },
+  "pdfPreview": {
+    "title": "Anteprima PDF",
+    "preview": "Anteprima",
+    "failed": "Impossibile generare l'anteprima del PDF."
   }
 }

+ 21 - 1
messages/it/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Esente da imposta",
     "tabs": {
       "vehicles": "Veicoli ({count})",
+      "invoices": "Fatture ({count})",
+      "quotes": "Preventivi ({count})",
       "messages": "Messaggi",
       "requests": "Richieste ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Ore Motore",
       "services": "Servizi"
     },
-    "noVehicles": "Nessun veicolo assegnato a questo cliente"
+    "documentTable": {
+      "invoiceNumber": "N. fattura",
+      "quoteNumber": "N. preventivo",
+      "title": "Titolo",
+      "vehicle": "Veicolo",
+      "status": "Stato",
+      "date": "Data",
+      "total": "Totale",
+      "noVehicle": "Solo ricambi",
+      "searchPlaceholder": "Cerca...",
+      "noMatches": "Nessun risultato per la tua ricerca",
+      "sort": {
+        "asc": "crescente",
+        "desc": "decrescente"
+      }
+    },
+    "noVehicles": "Nessun veicolo assegnato a questo cliente",
+    "noInvoices": "Nessuna fattura per questo cliente",
+    "noQuotes": "Nessun preventivo per questo cliente"
   },
   "form": {
     "addTitle": "Aggiungi nuovo cliente",

+ 27 - 0
messages/it/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "This invoice is locked because it has been sent",
+      "paid": "This invoice is locked because it has been paid"
+    },
+    "quote": {
+      "sent": "This quote is locked because it has been sent",
+      "accepted": "This quote is locked because it has been accepted"
+    }
+  },
+  "lockedBody": "Its parts, labour, prices, discount, tax, number and date can no longer be changed. Payments, status changes, sending and attachments all still work.",
+  "lockedAdminHint": "As an owner or admin you can unlock it if something genuinely needs correcting. The unlock is recorded in the audit log.",
+  "lockedMemberHint": "Ask an owner or admin to unlock it if something needs correcting.",
+  "unlock": "Unlock for editing",
+  "relock": "Lock again",
+  "unlockConfirmTitle": "Unlock this document?",
+  "unlockConfirmDescription": {
+    "invoice": "It will become editable again, and the change will be recorded in the audit log with your name. Prefer a credit note where your local rules require one.",
+    "quote": "It will become editable again, and the change will be recorded in the audit log with your name."
+  },
+  "unlocked": "Unlocked for editing",
+  "relocked": "Locked again",
+  "reopenedTitle": "This document has been unlocked for editing",
+  "reopenedBody": "It stays editable until it is locked again.",
+  "failed": "Could not change the lock"
+}

+ 5 - 0
messages/it/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram è attivo",
     "body": "Le conversazioni con i clienti arrivano qui. Rispondi senza uscire dall'app."
+  },
+  "invoice-designer": {
+    "title": "Le fatture sono state rinnovate",
+    "body": "Imposta layout, colori e caratteri di fatture e preventivi nel nuovo editor, in Modelli.",
+    "cta": "Apri Modelli"
   }
 }

+ 3 - 1
messages/it/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Veicolo",
     "quote": "Preventivo",
     "part": "Ricambio",
-    "inspection": "Ispezione"
+    "inspection": "Ispezione",
+    "shopActions": "Officina",
+    "person": "Aggiungi una persona"
   },
   "purchaseWhiteLabel": "Acquista White-Label",
   "licenseExpired": "La tua licenza è scaduta. Le funzionalità potrebbero essere limitate.",

+ 13 - 2
messages/it/pdf.json

@@ -19,6 +19,12 @@
     "description": "Descrizione",
     "qty": "Qtà",
     "unitPrice": "Prezzo unitario",
+    "items": "Voci",
+    "pos": "N.",
+    "unitOfMeasure": "Unità",
+    "invoiceNumberLabel": "N. fattura",
+    "customerNumberLabel": "N. cliente",
+    "dateLabel": "Data",
     "total": "Totale",
     "labor": "Manodopera",
     "hours": "Ore",
@@ -64,7 +70,9 @@
     "professionalWorkshop": "Gestione Officina Professionale",
     "tel": "Tel: {phone}",
     "org": "Org: {org}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Informazioni aggiuntive",
+    "telegramConnect": "Scrivici su Telegram"
   },
   "quote": {
     "title": "PREVENTIVO",
@@ -100,7 +108,10 @@
     "validityFooter30": "Questo preventivo è valido per 30 giorni",
     "viewPortal": "Visualizza il tuo portale: {url}",
     "tel": "Tel: {phone}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Informazioni aggiuntive",
+    "quoteNumberLabel": "N. preventivo",
+    "validUntilLabel": "Valido fino al"
   },
   "inspection": {
     "title": "ISPEZIONE VEICOLO",

+ 3 - 1
messages/it/quotes.json

@@ -48,7 +48,9 @@
       "details": "Dettagli",
       "images": "Immagini",
       "documents": "Documenti"
-    }
+    },
+    "customFieldsInvalid": "Compila tutti i campi personalizzati obbligatori",
+    "customFieldsSaveFailed": "Impossibile salvare i campi personalizzati"
   },
   "form": {
     "newQuote": "Nuovo preventivo",

+ 31 - 2
messages/it/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "PAGATO",
     "entityLabel": "Fattura",
     "emailSubject": "Conferma Pagamento",
-    "statusEmailSubject": "Aggiornamento dello stato del servizio"
+    "statusEmailSubject": "Aggiornamento dello stato del servizio",
+    "markCompletedTitle": "Contrassegnare questa fattura come completata?",
+    "markCompletedDescription": "È stata inviata al cliente ma risulta ancora non conclusa, quindi resterà visibile sulla lavagna.",
+    "markCompletedConfirm": "Segna come completata",
+    "lockedFieldsetLabel": "Fattura bloccata, modifica disattivata"
   },
   "payments": {
     "title": "Pagamenti",
@@ -344,7 +348,23 @@
     "setDefaults": "Valori predefiniti",
     "workBay": "Postazione",
     "selectWorkBay": "Seleziona postazione…",
-    "noWorkBay": "Nessuna postazione"
+    "noWorkBay": "Nessuna postazione",
+    "technicians": "Tecnici",
+    "otherTeamMembers": "Altri membri del team",
+    "makeTechnician": "Lo rende un tecnico",
+    "addSomeoneNew": "Aggiungi qualcuno",
+    "notOnBoard": "Non ancora sulla lavagna",
+    "putOnBoard": "Metti sulla lavagna",
+    "slotTaken": "{count, plural, one {Questa fascia è già occupata} other {Questa fascia ha # conflitti}}",
+    "anotherJob": "un altro lavoro",
+    "clashTechnician": "il tecnico è occupato",
+    "clashBay": "la postazione è occupata",
+    "clashBoth": "entrambi sono occupati",
+    "bookedAnyway": "Salvato comunque. Cambia l'orario o scegli la prossima fascia libera.",
+    "pickNextAvailable": "Scegli la prossima fascia libera",
+    "findingSlot": "Ricerca di una fascia…",
+    "slotPicked": "Spostato sulla prossima fascia libera",
+    "noSlotFound": "Nessuna fascia libera trovata nelle prossime settimane"
   },
   "notifications": {
     "title": "Notifiche al cliente",
@@ -381,5 +401,14 @@
       "title": "Impostazioni garanzia predefinite",
       "description": "Imposta i termini di garanzia predefiniti per i nuovi interventi"
     }
+  },
+  "concerns": {
+    "title": "Segnalazioni del cliente",
+    "addFirst": "Aggiungi una segnalazione del cliente",
+    "add": "Aggiungine un altro",
+    "placeholder": "C'è un rumore dietro quando freno",
+    "remove": "Rimuovi questo punto",
+    "notAnswered": "Non è ancora stato trovato nulla",
+    "answered": "{count} riscontro/i su questo"
   }
 }

+ 427 - 6
messages/it/settings.json

@@ -161,6 +161,9 @@
     "email": "Email",
     "emailPlaceholder": "servizio@esempio.it",
     "address": "Indirizzo",
+    "slogan": "Slogan",
+    "sloganPlaceholder": "Assistenza e riparazione per tutte le marche",
+    "sloganHint": "Una riga sotto il nome su fatture e preventivi.",
     "addressPlaceholder": "Via Roma 123\nInterno 100\n00100 Roma",
     "saveCompany": "Salva dettagli aziendali",
     "addNewCompany": "Aggiungi nuova azienda",
@@ -380,7 +383,7 @@
     "adminLabel": "Amministratore",
     "adminDescription": "Puo invitare/rimuovere membri e gestire i dati condivisi.",
     "memberLabel": "Membro",
-    "memberDescription": "Autorizzazioni determinate dal ruolo personalizzato assegnato. Senza ruolo personalizzato, accesso in sola lettura.",
+    "memberDescription": "I permessi dipendono dal ruolo assegnato. Senza ruolo, questo membro non può fare nulla.",
     "roleAssigned": "Ruolo aggiornato",
     "failedAssignRole": "Aggiornamento ruolo non riuscito",
     "removeMemberTitle": "Rimuovi membro",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Aggiornamento ruolo non riuscito",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Tecnico",
+    "technicianHint": "Può ricevere lavori assegnati e usare l’app tecnico",
+    "technicianFailed": "Impossibile modificare",
+    "setupApp": "Configura l'app",
+    "setupAppTitle": "Configura l'app tecnico",
+    "setupAppInstruction": "Chiedi a {name} di fare questo sul telefono:",
+    "setupAppOrType": "Oppure leggigli questo codice:",
+    "setupAppExpiry": "Utilizzabile una sola volta, scade tra {time}.",
+    "setupAppExpired": "Questo codice è scaduto. Chiudi e ricomincia.",
+    "setupAppDone": "Fatto",
+    "setupAppFailed": "Impossibile creare un codice di configurazione",
+    "setupPageTitle": "Configura l'app tecnico",
+    "setupPageBody": "Apri Torqvoice Tech su questo telefono, tocca Scansiona il codice di configurazione e inquadra di nuovo lo stesso codice.",
+    "setupPageCode": "Oppure inserisci questo codice nell'app",
+    "setupPageOpenApp": "Apri Torqvoice Tech",
+    "setupPageExpiry": "Questo codice è utilizzabile una sola volta e scade dieci minuti dopo che l'officina lo ha creato.",
+    "setupAppStep1": "Installare Torqvoice Tech",
+    "setupAppStep2": "Aprirla e toccare “Scansiona il codice di configurazione”",
+    "setupAppStep3": "Inquadrare questo codice col telefono",
+    "setupAppNotCamera": "La normale fotocamera del telefono non funziona. Va scansionato dentro Torqvoice Tech.",
+    "addTechnician": "Aggiungi un tecnico",
+    "addTechnicianHint": "Per un meccanico al banco. Senza email e senza attese.",
+    "technicianName": "Nome",
+    "technicianNamePlaceholder": "Nome e cognome",
+    "technicianPhone": "Numero di cellulare",
+    "technicianPhonePlaceholder": "Il telefono che ha in tasca",
+    "addTechnicianSubmit": "Crea",
+    "addTechnicianNote": "Da lì in poi accede con quel numero. Nessuna password da ricordare e niente da digitare nella prima schermata dell'app.",
+    "addTechnicianDone": "{name} è pronto. Mostragli il codice.",
+    "addTechnicianFailed": "Impossibile creare quel tecnico",
+    "setupAppCopyLink": "Copia il link da inviargli",
+    "setupAppCopied": "Copiato",
+    "revokeTechnicianTitle": "Disconnetterlo dall'app?",
+    "revokeTechnicianBody": "{name} perde subito l’accesso sul telefono e ogni codice smette di funzionare. Il lavoro svolto e le ore restano come sono.",
+    "revokeTechnicianConfirm": "Disconnetti",
+    "addPerson": "Aggiungi",
+    "addPersonTitle": "Aggiungi qualcuno all'officina",
+    "addPersonWho": "I due si configurano in modo diverso, quindi comincia dicendoci di chi si tratta.",
+    "choiceTechnician": "Un meccanico",
+    "choiceTechnicianHint": "Lavora sulle auto e usa Torqvoice sul telefono. Più semplice mentre è qui con te, e richiede circa un minuto.",
+    "choiceMember": "Qualcuno in ufficio",
+    "choiceMemberHint": "Accetta le auto, ordina i ricambi e invia le fatture, al computer. Tu invii un’email e lui sceglie la propria password.",
+    "stepLabelWho": "Chi",
+    "stepLabelDetails": "Dati",
+    "stepLabelPhone": "Il suo telefono",
+    "techDetailsTitle": "Nome e numero di cellulare",
+    "techDetailsBlurb": "Da adesso accederà con quel numero, quindi usa il telefono che ha davvero con sé. Non c’è nessuna password da ricordare o dimenticare.",
+    "techHandoffTitle": "Ora portalo sul suo telefono",
+    "techHandoffBlurb": "Questo codice collega il suo telefono alla tua officina. Vale una volta sola e solo per dieci minuti, quindi fallo mentre è qui.",
+    "memberDetailsTitle": "Il suo indirizzo email",
+    "memberDetailsBlurb": "Riceve un’email con un link. Aprendolo sceglie la propria password e poi compare nell’elenco qui sopra.",
+    "roleHint": "Gli amministratori possono cambiare le impostazioni e aggiungere persone. Gli altri fanno il lavoro quotidiano.",
+    "stepBack": "Indietro",
+    "stepHandoffDone": "L’ha scansionato",
+    "stepDoneTitle": "{name} è pronto",
+    "stepDoneBody": "Può aprire l’app e vedere i suoi lavori. La prossima volta accede con il solo numero di cellulare, senza codice.",
+    "stepInvitedTitle": "Invito inviato a {email}",
+    "stepInvitedBody": "Comparirà nell’elenco appena aprirà l’email e accetterà. Il link vale sette giorni.",
+    "stepDoneAnother": "Aggiungi qualcun altro",
+    "clashTitle": "{name} ha già quel numero",
+    "clashBlurb": "Due persone non possono condividere un numero di cellulare, perché è con quello che accedono. Quale dei due casi è?",
+    "clashSamePerson": "È {name}",
+    "clashSamePersonHint": "La stessa persona che torna, o un nome scritto diversamente. I suoi lavori e le sue ore restano con lei, e il nome appena inserito sostituisce il vecchio.",
+    "clashTakeover": "No, è {name}",
+    "clashTakeoverHint": "Un’altra persona che ora ha quel numero. {name} conserva tutto ciò che ha fatto qui ma non può più accedere, e potrai dargli un nuovo numero più avanti.",
+    "clashDifferentNumber": "Nessuno dei due, cambio il numero",
+    "workshopCountry": "In quale paese si trova la tua officina?",
+    "workshopCountryPlaceholder": "Scegli un paese",
+    "workshopCountryHint": "Chiesto una sola volta. Dopo, i numeri di cellulare si possono scrivere in forma breve. Puoi cambiarlo più avanti in <link>Impostazioni di localizzazione</link>.",
+    "phonePreview": "Salvato come",
+    "stepScannedTitle": "{name} è dentro",
+    "countrySearch": "Cerca paesi",
+    "countryNoMatch": "Nessun paese corrisponde",
+    "choiceStandalone": "Solo un nome per la lavagna",
+    "choiceStandaloneHint": "Un apprendista, un esterno, chiunque pianifichi ma che non accede mai. Nessun telefono, nessuna email, nessun account. Potrai dargliene uno più avanti.",
+    "standaloneDetailsTitle": "Nome e colore",
+    "standaloneDetailsBlurb": "È tutto ciò che riceve e tutto ciò che serve. Compare sulla lavagna e sui lavori, e non ha nulla in cui accedere.",
+    "boardColour": "Colore sulla lavagna",
+    "stepStandaloneTitle": "{name} è sulla lavagna",
+    "stepStandaloneBody": "Puoi pianificarlo e assegnargli lavori subito. Se un giorno gli servirà l'app, aggiungi un numero di cellulare da questo elenco.",
+    "boardOnly": "Solo sulla lavagna",
+    "boardOnlyHint": "Vengono pianificati e assegnati ai lavori, ma non accedono mai. Dagli un numero di cellulare quando serviranno l'app.",
+    "boardOnlyNoAccount": "Nessun account",
+    "giveApp": "Dagli l'app",
+    "giveAppTitle": "Dai l'app a {name}",
+    "giveAppBlurb": "Manca solo un numero di cellulare. Da lì in poi accederà con quello.",
+    "giveAppKeepsHistory": "Tutto ciò che è già registrato a suo nome resta dov’è.",
+    "giveAppSubmit": "Crea il suo account",
+    "role": "Ruolo",
+    "inviteMemberHint": "Riceve un’email e sceglie la propria password.",
+    "removeBoardOnlyTitle": "Togliere {name} dalla lavagna?",
+    "removeBoardOnlyBody": "{name} non compare più sulla lavagna e non può più essere assegnato ai lavori. Il lavoro già registrato e le ore timbrate restano esattamente come sono.",
+    "removeBoardOnlyDone": "{name} è fuori dalla lavagna",
+    "noRole": "Nessun ruolo",
+    "worksOnJobs": "Lavora sui veicoli",
+    "createDefaultRoles": "Crea i ruoli standard",
+    "defaultRolesCreated": "Ruoli standard creati",
+    "noRolesYet": "Questa officina non ha ancora ruoli, quindi non c’è nulla da assegnare oltre ad Admin. Crea quelli standard e restringi i permessi dopo.",
+    "noRoleDescription": "Nessun permesso. Può accedere, ma ogni schermata lo rifiuta finché non gli assegni un ruolo qui sotto.",
+    "cannotUseApp": "Il suo ruolo non può lavorare sui lavori. Assegnagli prima Tecnico, o un ruolo con gli stessi permessi.",
+    "revokeTechnicianDone": "{name} è stato disconnesso dall’app",
+    "noAccessTitle": "Ancora nessun accesso",
+    "noAccessBody": "Il tuo account fa parte di {workshop}, ma non ha ancora un ruolo, quindi qui non c’è nulla da aprire. Chiedi un ruolo a un titolare o a un amministratore della tua officina.",
+    "setupPageInstall": "Scaricala su Google Play"
   },
   "invoice": {
     "title": "Layout fattura",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "Numeri assegnati a {count} clienti",
     "allCustomersNumbered": "Tutti i clienti hanno un numero.",
     "assignCustomerNumbersConfirmTitle": "Assegnare i numeri cliente?",
-    "assignCustomerNumbersConfirmDescription": "I {count} clienti senza numero riceveranno numeri sequenziali nell'ordine di creazione, proseguendo dal numero esistente più alto. I clienti che hanno già un numero non vengono modificati. I numeri restano modificabili."
+    "assignCustomerNumbersConfirmDescription": "I {count} clienti senza numero riceveranno numeri sequenziali nell'ordine di creazione, proseguendo dal numero esistente più alto. I clienti che hanno già un numero non vengono modificati. I numeri restano modificabili.",
+    "layoutColorsHint": "Colori, caratteri e stile dell’intestazione sono in Modelli.",
+    "goToTemplates": "Apri Modelli",
+    "lockTitle": "Blocco dei documenti conclusi",
+    "lockDescription": "Impedisce la modifica di una fattura o di un preventivo una volta chiuso.",
+    "lockWhatItDoes": "Viene bloccato: ricambi, manodopera, quantità, prezzi, sconto, imposta, numero e data del documento. Anche l’eliminazione è impedita.",
+    "lockWhatItAllows": "Continua a funzionare: registrare pagamenti, pagamento online con carta, cambi di stato, invio e reinvio, allegati e note interne. Una fattura bloccata resta sempre pagabile.",
+    "lockUnlockNote": "Titolari e amministratori possono sbloccare un singolo documento dalla sua pagina quando serve davvero una correzione. Ogni sblocco viene registrato nel log di audit.",
+    "lockInvoicesLabel": "Blocca le fatture",
+    "lockTriggerSent": "Quando la fattura è inviata",
+    "lockTriggerPaid": "Quando la fattura è saldata per intero",
+    "lockTriggerSentHint": "Si blocca appena la fattura viene inviata via email o viene creato un link di condivisione. Le fatture inviate prima dell’attivazione non sono interessate.",
+    "lockTriggerPaidHint": "Si blocca quando l’intero importo è saldato o la fattura è segnata come pagata a mano. Una fattura pagata in parte resta modificabile.",
+    "lockQuotesLabel": "Blocca i preventivi",
+    "quoteLockTriggerSent": "Quando il preventivo è inviato",
+    "quoteLockTriggerAccepted": "Quando il preventivo è accettato",
+    "quoteLockTriggerSentHint": "Si blocca appena il preventivo raggiunge il cliente. Da scegliere solo se non rivedi mai un preventivo durante la trattativa.",
+    "quoteLockTriggerAcceptedHint": "Si blocca quando il cliente accetta il preventivo o questo viene convertito in un lavoro. I preventivi inviati restano modificabili."
   },
   "layoutEditor": {
     "helpText": "Trascina per riordinare. Usa il selettore di larghezza per posizionare le sezioni affiancate. Le sezioni consecutive a mezza larghezza (S/D) verranno visualizzate in due colonne.",
     "addField": "Aggiungi campo",
     "custom": "personalizzato",
     "full": "Intero",
+    "boxed": "Riquadro",
+    "plain": "Senza",
+    "boxedHint": "Stampato dentro un riquadro",
+    "plainHint": "Stampato senza riquadro",
     "L": "S",
     "R": "D",
     "left": "sinistra",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Larghezza intera — clicca per mezza larghezza (sinistra)",
     "sections": {
       "header": "Intestazione",
+      "slogan": "Slogan",
       "customer": "Cliente",
       "vehicle": "Veicolo",
       "service": "Servizio",
+      "document_title": "Titolo del documento",
+      "items_table": "Tabella voci",
       "parts_table": "Ricambi",
       "labor_table": "Manodopera",
       "totals": "Totali",
       "notes": "Note",
+      "attached_documents": "Documenti allegati",
       "diagnostic_notes": "Note diagnostiche",
       "findings": "Osservazioni",
+      "warranty": "Garanzia",
       "bank_account": "Conto bancario",
       "footer": "Piè di pagina",
       "general": "Generale",
@@ -493,12 +626,59 @@
       "tech_name": "Tecnico",
       "logo": "Logo",
       "company_name": "Nome azienda",
+      "company_slogan": "Slogan",
       "company_address": "Indirizzo",
       "company_phone": "Telefono",
       "company_email": "E-mail",
       "company_org_number": "Numero organizzazione",
       "bank_account": "Conto bancario",
-      "org_number": "Numero organizzazione"
+      "footer_note": "Nota a piè di pagina",
+      "org_number": "Numero organizzazione",
+      "portal_link": "Link al portale"
+    },
+    "presetsTitle": "Partire da una disposizione",
+    "presetsHint": "Sostituisce la disposizione qui sotto. Nulla viene salvato finché non salvi.",
+    "presets": {
+      "classic": {
+        "name": "Classica",
+        "description": "Ricambi e manodopera in tabelle separate, dati incolonnati a sinistra"
+      },
+      "letterhead": {
+        "name": "Carta intestata",
+        "description": "Contatti in fondo, titolo sotto gli indirizzi"
+      },
+      "compact": {
+        "name": "Compatta",
+        "description": "Senza riquadri, solo l’essenziale"
+      },
+      "minimal": {
+        "name": "Minimale",
+        "description": "Solo tipografia su bianco: niente riquadri né fasce, solo filetti e spazio"
+      },
+      "itemized": {
+        "name": "Dettagliato",
+        "description": "Un unico elenco numerato di voci con la colonna unità"
+      },
+      "detailed": {
+        "name": "Dettagliata",
+        "description": "Titolo in alto, veicolo da solo, entrambe le tabelle e ogni blocco opzionale"
+      }
+    },
+    "style": {
+      "documentTitle": "Intero foglio",
+      "documentHint": "dimensione, spaziatura, accento, bande",
+      "textColor": "Testo",
+      "labelColor": "Titolo",
+      "backgroundColor": "Sfondo",
+      "borderColor": "Bordo",
+      "fontSize": "Dimensione",
+      "rowPadding": "Altezza riga",
+      "margin": "Margine",
+      "accentColor": "Accento",
+      "stripeColor": "Banda",
+      "stripes": "Bande",
+      "fontFamily": "Carattere",
+      "fontInherit": "Eredita"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Preset modello",
     "primaryColor": "Colore primario",
+    "colors": "Colori",
+    "textColor": "Testo",
+    "textColorHint": "Il colore di titoli e testo",
+    "companyTextColor": "Nome azienda",
+    "companyTextColorHint": "Il colore del nome sull’intestazione",
+    "frameBorderColor": "Filetto della cornice",
+    "frameBorderColorHint": "Il filetto dove la cornice incontra la carta",
+    "frameShadow": "Ombra della cornice",
+    "frameShadowOn": "Ombra",
+    "frameShadowOff": "Piatto",
+    "backgroundColor": "Sfondo",
+    "backgroundColorClear": "Reimposta",
+    "backgroundColorHint": "Lascia vuoto per la carta bianca. Una tinta chiara stampa un foglio colorato.",
     "fontAndLayout": "Font e Layout",
     "fontFamily": "Famiglia font",
     "helveticaDefault": "Helvetica (Predefinito)",
@@ -525,6 +718,10 @@
     "standard": "Standard",
     "compact": "Compatto",
     "modern": "Moderno",
+    "framed": "Con cornice",
+    "letterheadMark": "Intestazione",
+    "letterheadLogo": "Logo",
+    "letterheadCompanyName": "Nome azienda",
     "preview": "Anteprima {name}",
     "billTo": "Fatturare a",
     "preparedFor": "Preparato per",
@@ -594,7 +791,11 @@
     "layoutDescription": "Personalizza l'ordine e la visibilita delle sezioni nelle fatture e nei preventivi.",
     "layoutSaved": "Layout salvato con successo",
     "layoutDocInvoice": "Fattura",
-    "layoutDocQuote": "Preventivo"
+    "layoutDocQuote": "Preventivo",
+    "goToLayout": "Disposizione e sezioni",
+    "openDesigner": "Apri il designer",
+    "designerIntro": "Scegli un punto di partenza, poi apri il designer per cambiare tutto.",
+    "designerHint": "Colori, caratteri, spaziature e tutte le sezioni sono nel designer."
   },
   "payment": {
     "readMore": "Scopri di più",
@@ -739,6 +940,7 @@
       "NGN": "Naira nigeriana",
       "KES": "Scellino keniota",
       "MAD": "Dirham marocchino",
+      "DZD": "Dinaro algerino",
       "GHS": "Cedi ghanese",
       "QAR": "Riyal del Qatar",
       "KWD": "Dinaro kuwaitiano",
@@ -805,7 +1007,16 @@
     "failedSave": "Impossibile salvare il campo",
     "failedDelete": "Impossibile eliminare",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Non assegnato",
+    "defaultValue": "Valore predefinito",
+    "defaultValueHint": "Precompilato nei nuovi record e stampato finché non viene inserito un valore.",
+    "defaultValueNone": "Nessuno",
+    "defaultValueCheckedHint": "Selezionata per impostazione predefinita",
+    "placement": "Posizione sul documento",
+    "placementHidden": "Non stampato",
+    "placementHint": "In quale sezione della fattura o del preventivo viene stampato questo campo. Nel designer puoi attivarlo anche in altre sezioni.",
+    "failedSavePlacement": "Impossibile salvare la posizione del campo"
   },
   "workshop": {
     "title": "Predefiniti officina",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Controllo non riuscito",
       "configurePerPart": "Imposta la Qtà min di un ricambio nella pagina magazzino →",
       "readMore": "Scopri di più"
+    },
+    "technicianStatus": {
+      "title": "App tecnico Torqvoice (Android/iOS)",
+      "description": "Avviso quando un tecnico modifica un lavoro dal telefono.",
+      "inApp": "Avvisa l'accettazione",
+      "inAppHint": "Un avviso quando un lavoro è finito, in attesa di ricambi o ripreso.",
+      "save": "Salva",
+      "saved": "Impostazioni avvisi salvate",
+      "saveFailed": "Impossibile salvare le impostazioni"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Invia e ricevi messaggi Telegram con i tuoi clienti da Torqvoice."
       }
     }
+  },
+  "designer": {
+    "invoice": "Fattura",
+    "quote": "Preventivo",
+    "eyebrow": "Designer di documenti",
+    "galleryTitle": "Parti da un modello",
+    "galleryHint": "Scegli un punto di partenza. Nel designer puoi cambiare tutto.",
+    "yourDesigns": "I tuoi design",
+    "templates": "Modelli",
+    "inUse": "In uso",
+    "savedOn": "Salvato il {date}",
+    "deleteDesignTitle": "Elimina design",
+    "deleteDesignBody": "Eliminare il design «{name}»? La fattura e il preventivo mantengono ciò che è applicato; sparisce solo la copia salvata.",
+    "delete": "Elimina",
+    "deleteDesign": "Elimina questo design",
+    "continueCurrent": "Continua con il mio layout attuale",
+    "backToSettings": "Torna alle impostazioni",
+    "useInvoiceDesign": "Usa il design della fattura",
+    "copiedToQuote": "Design della fattura copiato nel preventivo",
+    "rulers": "Righelli",
+    "saveDesign": "Salva design",
+    "saveDesignHint": "Conserva una copia con un nome di questo design, per ritrovarla nella galleria dei modelli",
+    "reset": "Reimposta",
+    "save": "Salva",
+    "saving": "Salvataggio…",
+    "saved": "Salvato",
+    "couldNotSave": "Impossibile salvare",
+    "couldNotSaveDesigns": "Impossibile salvare i tuoi design",
+    "designUpdated": "«{name}» aggiornato",
+    "designSaved": "Salvato come «{name}»",
+    "defaultDesignName": "Il mio design di {doc}",
+    "documentStyling": "Stile del documento",
+    "sections": "Sezioni",
+    "sectionEmpty": "vuota",
+    "sectionEmptyHint": "Viene mostrata, ma con i dati attuali non ha nulla da stampare.",
+    "sectionShownHint": "Visibile sul foglio. Fai clic per nasconderla.",
+    "sectionHiddenHint": "Nascosta dal foglio. Fai clic per mostrarla.",
+    "railHint": "Trascina una sezione sulla pagina: rilasciala tra due blocchi per riordinare, su una scheda per affiancarla, oppure altrove per posizionarla liberamente. La pagina le fa spazio intorno.",
+    "returnToFlow": "Riporta {section} nel flusso",
+    "saveDialogTitle": "Salva questo design",
+    "saveDialogBody": "Conserva una copia con un nome della disposizione e dell'aspetto attuali. La ritrovi in I tuoi design, nella galleria dei modelli.",
+    "designNamePlaceholder": "Nome del design",
+    "nameExists": "Esiste già un design con questo nome; salvando lo aggiorni.",
+    "updateDesign": "Aggiorna design",
+    "cancel": "Annulla",
+    "insertHere": "Inserisci qui",
+    "dropLeftColumn": "Colonna sinistra",
+    "dropRightColumn": "Colonna destra",
+    "freePosition": "Posizione libera",
+    "sectionSettings": "Impostazioni della sezione",
+    "panelStyle": "Stile del pannello",
+    "variant": {
+      "accent": "Accento",
+      "panel": "Pannello",
+      "outline": "Contorno",
+      "lines": "Linee",
+      "hint": "Accento colora la scheda con il colore principale. Pannello la allinea alle altre schede di dettaglio. Contorno disegna solo un bordo, e Linee stampa senza riquadro.",
+      "classic": "Classico",
+      "box": "Riquadro",
+      "totalsHint": "Classico stampa righe semplici con un filetto sopra il totale. Riquadro le incornicia. Pannello e Accento le mettono su una scheda."
+    },
+    "alignment": "Allineamento",
+    "alignCenter": "Centro",
+    "itemsTableHint": "Un elenco numerato di tutte le righe del lavoro, prima la manodopera e poi i ricambi, al posto delle tabelle separate.",
+    "discardChanges": "Scarta le modifiche",
+    "tablesExclusiveHint": "Il foglio stampa una disposizione: un unico elenco numerato oppure tabelle separate per ricambi e manodopera. Attivarne una disattiva l'altra.",
+    "innerPadding": "Spaziatura interna",
+    "totalsWidth": "Larghezza",
+    "totalsWidthHint": "Vuoto occupa tutta la riga. Un valore in punti appende il blocco a destra; in una colonna prende la larghezza della colonna.",
+    "placement": "Posizione",
+    "visible": "Visibile",
+    "columnFull": "Intera",
+    "columnLeft": "Sinistra",
+    "columnRight": "Destra",
+    "drawBox": "Disegna un riquadro",
+    "showHeading": "Mostra intestazione",
+    "spacing": "Spaziatura",
+    "placedByHand": "Questa sezione è posizionata a mano, quindi la spaziatura del flusso non la sposta.",
+    "placedByHandFramed": "La carta intestata incorniciata poggia sulla fascia; trascinala per spostarla.",
+    "placedByHandDrag": "Trascinala, oppure riportala nel flusso, per usare la spaziatura.",
+    "marginTop": "Alto",
+    "marginBottom": "Basso",
+    "marginLeft": "Sinistra",
+    "marginRight": "Destra",
+    "spacingHint": "Punti di spazio vuoto che la sezione mantiene attorno a sé nel flusso.",
+    "logo": "Logo",
+    "size": "Dimensione",
+    "logoHint": "Disattiva il logo in Campi per stampare al suo posto il nome dell'azienda.",
+    "fields": "Campi",
+    "removeField": "Rimuovi da questa sezione",
+    "yourCustomFields": "I tuoi campi personalizzati",
+    "appearance": "Aspetto",
+    "details": "Dettagli",
+    "text": "Testo",
+    "companyName": "Nome azienda",
+    "heading": "Intestazione",
+    "fill": "Riempimento",
+    "border": "Bordo",
+    "lineWidth": "Spessore linea",
+    "borderWidth": "Spessore bordo",
+    "outerBorder": "Bordo esterno",
+    "rowBanding": "Righe alternate",
+    "likeSheet": "Come il foglio",
+    "on": "Sì",
+    "off": "No",
+    "font": "Carattere",
+    "inherit": "Eredita",
+    "auto": "auto",
+    "sectionDragHint": "Trascina questa sezione nell'elenco, o sulla pagina, per spostarla. Una volta posizionata a mano, le frecce la spostano di un punto per volta, dieci con Maiusc, ed Esc annulla il trascinamento.",
+    "document": "Documento",
+    "documentSubtitle": "Vale per l'intero foglio",
+    "headerStyleTitle": "Stile intestazione",
+    "headerStyle": {
+      "standard": {
+        "name": "Standard",
+        "desc": "Nome e recapiti su bianco, con un filetto sotto"
+      },
+      "compact": {
+        "name": "Compatto",
+        "desc": "Intestazione stretta, righe fitte"
+      },
+      "modern": {
+        "name": "Moderno",
+        "desc": "Fascia colorata a tutta larghezza"
+      },
+      "framed": {
+        "name": "Incorniciato",
+        "desc": "Fascia in alto e filetto sul lato sinistro"
+      }
+    },
+    "colors": "Colori",
+    "primary": "Principale",
+    "background": "Sfondo",
+    "accent": "Accento",
+    "frame": "Cornice",
+    "rail": "Filetto",
+    "leftEdge": "Bordo sinistro",
+    "rightEdge": "Bordo destro",
+    "frameLine": "Linea della cornice",
+    "cornerRadius": "Raggio degli angoli",
+    "shadow": "Ombra",
+    "shadowThin": "Sottile",
+    "shadowNormal": "Normale",
+    "shadowWide": "Ampia",
+    "typography": "Tipografia",
+    "baseSize": "Dimensione base",
+    "page": "Pagina",
+    "margins": "Margini",
+    "rowHeight": "Altezza riga",
+    "band": "Fascia",
+    "sample": {
+      "itemLabor": "Freni anteriori sostituiti",
+      "itemDisc": "Disco freno, anteriore",
+      "itemPads": "Kit pastiglie, asse anteriore",
+      "itemConsumables": "Materiali di consumo",
+      "unitPcs": "pz",
+      "unitSet": "kit",
+      "unitEach": "x",
+      "findingPads": "Pastiglie posteriori al 15%",
+      "findingPadsNote": "Sostituire entro 5.000 km",
+      "findingOilWeep": "Lieve trafilamento d'olio dal coperchio punterie",
+      "notes": "Grazie per aver scelto la nostra officina. Contattaci per qualsiasi domanda.",
+      "warranty": "12 mesi di garanzia su ricambi e manodopera.",
+      "serviceTitle": "Tagliando annuale e freni",
+      "serviceType": "Riparazione",
+      "companyName": "La tua officina",
+      "slogan": "Un servizio di qualità di cui fidarsi",
+      "footerNote": "Grazie per averci scelto",
+      "value": "Esempio"
+    },
+    "logoUpload": "Carica logo",
+    "logoReplace": "Sostituisci logo",
+    "logoUploading": "Caricamento…",
+    "logoFailed": "Impossibile caricare l'immagine",
+    "footerLogoHint": "Attiva il logo in Campi per stamparlo anche a piè di pagina.",
+    "logoReset": "Usa il logo aziendale",
+    "logoOwn": "Stampato solo su questo documento. Il logo aziendale resta invariato.",
+    "logoInherited": "Viene usato il logo aziendale. Caricane uno qui per usarne un altro solo su questo documento.",
+    "slogan": "Slogan",
+    "sloganPlaceholderHint": "Nessuno slogan impostato, quindi il foglio mostra un segnaposto che non verrà stampato.",
+    "sloganSetHint": "Lo slogan proviene dai dati della tua azienda.",
+    "sloganLink": "Impostazioni azienda",
+    "placeholder": "Segnaposto",
+    "leaveTitle": "Uscire senza salvare?",
+    "leaveBody": "Le modifiche a questo design non sono state salvate e andranno perse.",
+    "leaveConfirm": "Esci",
+    "boldField": "Grassetto"
+  },
+  "preview": {
+    "title": "Servizio freni e cambio olio",
+    "serviceType": "Manutenzione",
+    "findingPads": "Pastiglie posteriori usurate al 15%",
+    "findingPadsNote": "Se ne consiglia la sostituzione entro 8.000 km",
+    "findingOilLeak": "Lieve perdita d'olio dalla guarnizione del coperchio punterie",
+    "invoiceNotes": "Pastiglie anteriori sostituite. Olio e filtro cambiati con sintetico 5W-30. Prossimo tagliando consigliato a 80.000 km.",
+    "quoteNotes": "Si consiglia la sostituzione delle pastiglie anteriori. Cambio olio e filtro con sintetico 5W-30.",
+    "partBrakePads": "Pastiglie freno (anteriori)",
+    "partOilFilter": "Filtro olio",
+    "partSyntheticOil": "Olio sintetico 5W-30",
+    "laborBrakeReplacement": "Sostituzione freni",
+    "laborOilChange": "Cambio olio"
   }
 }

+ 4 - 2
messages/it/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "Alta",
     "findingSeverityNeedsWork": "Media",
     "findingSeverityMonitor": "Bassa",
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Informazioni aggiuntive"
   },
   "quote": {
     "title": "Preventivo",
@@ -125,7 +126,8 @@
       "converted": "Convertito",
       "changes_requested": "Modifiche Richieste"
     },
-    "tel": "Tel: {phone}"
+    "tel": "Tel: {phone}",
+    "customFields": "Informazioni aggiuntive"
   },
   "inspection": {
     "title": "Ispezione Veicolo",

+ 2 - 1
messages/it/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Ancora nulla in allegato. Fotografa un cerchio segnato mentre hai gli pneumatici davanti.",
     "captionPlaceholder": "Che cosa mostra?",
     "onInvoice": "In fattura",
-    "invoiceHint": "I file marcati per la fattura vengono copiati sull’ordine o sulla fattura quando il treno viene fatturato.",
+    "invoiceHint": "Le foto marcate per la fattura vengono copiate sull’ordine o sulla fattura quando il treno viene fatturato. I documenti restano qui con il treno.",
+    "documentStays": "Resta con il treno, non viene copiato sulle fatture",
     "deleteTitle": "Rimuovere questo file?",
     "deleteBody": "{name} viene rimosso dal treno. Ciò che è già stato copiato su una fattura resta lì.",
     "failed": "Impossibile salvare",

+ 3 - 1
messages/it/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "A quale punto risponde?",
+    "concernNone": "Non è qualcosa che ha segnalato il cliente"
   },
   "observationsPage": {
     "searchPlaceholder": "Cerca descrizione, note o veicolo...",

+ 4 - 1
messages/it/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Tecnico indipendente",
     "deleteTitle": "Elimina Tecnico",
     "deleteDescription": "Rimuovere \"{name}\" dalla lavagna di lavoro? Anche i loro incarichi esistenti verranno rimossi.",
-    "addTechnician": "Aggiungi Tecnico"
+    "addTechnician": "Aggiungi Tecnico",
+    "standaloneOnly": "Un nome sulla lavagna per chi non accede, come un apprendista o un esterno. Per un meccanico che usa l'app, aggiungilo dalla pagina Team.",
+    "linkedTo": "Accede come {name}",
+    "linkedManagedOnTeam": "Gestito dalla pagina Team, insieme all'accesso all'app."
   },
   "jobDetail": {
     "viewDetails": "Visualizza Dettagli",

+ 14 - 4
messages/lt/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Sukurta darbo vieta",
     "work_bay_update": "Atnaujinta darbo vieta",
     "work_bay_delete": "Ištrinta darbo vieta",
-    "settings_whatsappUpdated": "WhatsApp nustatymai atnaujinti",
-    "settings_whatsappNumberRegistered": "WhatsApp numeris užregistruotas",
-    "settings_whatsappDisconnected": "WhatsApp atjungtas"
+    "auth_appSetupRedeemed": "Prisijungta su nustatymo kodu",
+    "auth_technicianCodeSignIn": "Prisijungta su vienkartiniu kodu",
+    "team_createAppSetupCode": "Išduotas programėlės nustatymo kodas",
+    "team_createTechnicianAccount": "Sukurta techniko paskyra",
+    "team_removeTechnicianAccess": "Technikas pašalintas, prieiga atšaukta",
+    "team_setMemberTechnician": "Pakeista, ar narys yra technikas",
+    "settings_whatsappUpdated": "Atnaujinti „WhatsApp“ nustatymai",
+    "settings_whatsappDisconnected": "Atjungtas „WhatsApp“",
+    "settings_whatsappNumberRegistered": "Užregistruotas „WhatsApp“ numeris",
+    "team_giveTechnicianTheApp": "Lentos technikui suteikta paskyra",
+    "team_createDefaultRoles": "Sukurtos standartinės rolės",
+    "settings_setCustomFieldPlacement": "Atnaujinta pasirinktinio lauko vieta"
   },
   "summary": {
     "customField_create": "Sukurtas pasirinktinis laukas „{name}“",
@@ -265,6 +274,7 @@
     "whatsapp_send": "Klientui {name} išsiųsta „WhatsApp“ žinutė",
     "work_bay_create": "Sukurta darbo vieta „{name}“",
     "work_bay_update": "Atnaujinta darbo vieta „{name}“",
-    "work_bay_delete": "Ištrinta darbo vieta {id}"
+    "work_bay_delete": "Ištrinta darbo vieta {id}",
+    "settings_setCustomFieldPlacement": "Pakeitė, kur spausdinamas pasirinktinis laukas"
   }
 }

+ 5 - 0
messages/lt/common.json

@@ -95,5 +95,10 @@
     "placeholder": "pvz. Turime serverių infrastruktūros problemų ir jas sprendžiame.",
     "posted": "Pranešimas paskelbtas",
     "cleared": "Pranešimas pašalintas"
+  },
+  "pdfPreview": {
+    "title": "PDF peržiūra",
+    "preview": "Peržiūra",
+    "failed": "Nepavyko sugeneruoti PDF peržiūros."
   }
 }

+ 21 - 1
messages/lt/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Atleistas nuo mokesčio",
     "tabs": {
       "vehicles": "Transporto priemonės ({count})",
+      "invoices": "Sąskaitos ({count})",
+      "quotes": "Pasiūlymai ({count})",
       "messages": "Žinutės",
       "requests": "Užklausos ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Variklio valandos",
       "services": "Paslaugos"
     },
-    "noVehicles": "Šiam klientui nėra priskirtų transporto priemonių"
+    "documentTable": {
+      "invoiceNumber": "Sąskaitos nr.",
+      "quoteNumber": "Pasiūlymo nr.",
+      "title": "Pavadinimas",
+      "vehicle": "Transporto priemonė",
+      "status": "Būsena",
+      "date": "Data",
+      "total": "Iš viso",
+      "noVehicle": "Tik dalys",
+      "searchPlaceholder": "Ieškoti...",
+      "noMatches": "Pagal paiešką nieko nerasta",
+      "sort": {
+        "asc": "didėjančiai",
+        "desc": "mažėjančiai"
+      }
+    },
+    "noVehicles": "Šiam klientui nėra priskirtų transporto priemonių",
+    "noInvoices": "Šis klientas neturi sąskaitų",
+    "noQuotes": "Šis klientas neturi pasiūlymų"
   },
   "form": {
     "addTitle": "Pridėti naują klientą",

+ 27 - 0
messages/lt/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "This invoice is locked because it has been sent",
+      "paid": "This invoice is locked because it has been paid"
+    },
+    "quote": {
+      "sent": "This quote is locked because it has been sent",
+      "accepted": "This quote is locked because it has been accepted"
+    }
+  },
+  "lockedBody": "Its parts, labour, prices, discount, tax, number and date can no longer be changed. Payments, status changes, sending and attachments all still work.",
+  "lockedAdminHint": "As an owner or admin you can unlock it if something genuinely needs correcting. The unlock is recorded in the audit log.",
+  "lockedMemberHint": "Ask an owner or admin to unlock it if something needs correcting.",
+  "unlock": "Unlock for editing",
+  "relock": "Lock again",
+  "unlockConfirmTitle": "Unlock this document?",
+  "unlockConfirmDescription": {
+    "invoice": "It will become editable again, and the change will be recorded in the audit log with your name. Prefer a credit note where your local rules require one.",
+    "quote": "It will become editable again, and the change will be recorded in the audit log with your name."
+  },
+  "unlocked": "Unlocked for editing",
+  "relocked": "Locked again",
+  "reopenedTitle": "This document has been unlocked for editing",
+  "reopenedBody": "It stays editable until it is locked again.",
+  "failed": "Could not change the lock"
+}

+ 5 - 0
messages/lt/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram įjungtas",
     "body": "Pokalbiai su klientais atsiduria čia. Atsakykite neišeidami iš programos."
+  },
+  "invoice-designer": {
+    "title": "Sąskaitos buvo atnaujintos",
+    "body": "Nustatykite sąskaitų ir pasiūlymų išdėstymą, spalvas ir šriftus naujame redaktoriuje, skiltyje Šablonai.",
+    "cta": "Atidaryti šablonus"
   }
 }

+ 3 - 1
messages/lt/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Transporto priemonė",
     "quote": "Pasiūlymas",
     "part": "Dalis",
-    "inspection": "Apžiūra"
+    "inspection": "Apžiūra",
+    "shopActions": "Servisas",
+    "person": "Pridėti žmogų"
   },
   "purchaseWhiteLabel": "Įsigyti \"White-Label\"",
   "licenseExpired": "Jūsų licencija pasibaigė. Funkcijos gali būti ribotos.",

+ 13 - 2
messages/lt/pdf.json

@@ -19,6 +19,12 @@
     "description": "Aprašymas",
     "qty": "Kiekis",
     "unitPrice": "Vnt. kaina",
+    "items": "Pozicijos",
+    "pos": "Nr.",
+    "unitOfMeasure": "Mato vnt.",
+    "invoiceNumberLabel": "Sąskaitos Nr.",
+    "customerNumberLabel": "Kliento Nr.",
+    "dateLabel": "Data",
     "total": "Suma",
     "labor": "Darbai ir paslaugos",
     "hours": "Valandos",
@@ -64,7 +70,9 @@
     "viewPortal": "Peržiūrėkite savo portalą: {url}",
     "professionalWorkshop": "Profesionalus dirbtuvių valdymas",
     "tel": "Tel.: {phone}",
-    "org": "Įm. kodas: {org}"
+    "org": "Įm. kodas: {org}",
+    "customFieldsTitle": "Papildoma informacija",
+    "telegramConnect": "Susisiekite su mumis per Telegram"
   },
   "quote": {
     "title": "PASIŪLYMAS",
@@ -100,7 +108,10 @@
     "validityFooterUntil": "Šis pasiūlymas galioja iki {date}",
     "validityFooter30": "Šis pasiūlymas galioja 30 dienų",
     "viewPortal": "Peržiūrėkite savo portalą: {url}",
-    "tel": "Tel.: {phone}"
+    "tel": "Tel.: {phone}",
+    "customFieldsTitle": "Papildoma informacija",
+    "quoteNumberLabel": "Pasiūlymo nr.",
+    "validUntilLabel": "Galioja iki"
   },
   "inspection": {
     "title": "TRANSPORTO PRIEMONĖS APŽIŪRA",

+ 3 - 1
messages/lt/quotes.json

@@ -48,7 +48,9 @@
       "details": "Informacija",
       "images": "Vaizdai",
       "documents": "Dokumentai"
-    }
+    },
+    "customFieldsInvalid": "Užpildykite visus privalomus pasirinktinius laukus",
+    "customFieldsSaveFailed": "Nepavyko išsaugoti pasirinktinių laukų"
   },
   "form": {
     "newQuote": "Naujas pasiūlymas",

+ 31 - 2
messages/lt/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "APMOKĖTA",
     "entityLabel": "Sąskaita",
     "emailSubject": "Mokėjimo patvirtinimas",
-    "statusEmailSubject": "Paslaugos būsenos atnaujinimas"
+    "statusEmailSubject": "Paslaugos būsenos atnaujinimas",
+    "markCompletedTitle": "Pažymėti šią sąskaitą kaip užbaigtą?",
+    "markCompletedDescription": "Ji jau išsiųsta klientui, bet vis dar pažymėta kaip nebaigta, todėl liks matoma darbų lentoje.",
+    "markCompletedConfirm": "Žymėti užbaigta",
+    "lockedFieldsetLabel": "Užrakinta sąskaita, redagavimas išjungtas"
   },
   "payments": {
     "title": "Mokėjimai",
@@ -344,7 +348,23 @@
     "setDefaults": "Nustatyti numatytuosius",
     "workBay": "Darbo vieta",
     "selectWorkBay": "Pasirinkite darbo vietą…",
-    "noWorkBay": "Be darbo vietos"
+    "noWorkBay": "Be darbo vietos",
+    "technicians": "Technikai",
+    "otherTeamMembers": "Kiti komandos nariai",
+    "makeTechnician": "Padarys jį techniku",
+    "addSomeoneNew": "Pridėti naują žmogų",
+    "notOnBoard": "Dar nėra lentoje",
+    "putOnBoard": "Įtraukti į lentą",
+    "slotTaken": "{count, plural, one {Šis laikas jau užimtas} other {Šiam laikui yra # sutapimų}}",
+    "anotherJob": "kitas darbas",
+    "clashTechnician": "technikas užimtas",
+    "clashBay": "postas užimtas",
+    "clashBoth": "abu užimti",
+    "bookedAnyway": "Vis tiek išsaugota. Pakeiskite laiką arba pasirinkite artimiausią laisvą.",
+    "pickNextAvailable": "Rinktis artimiausią laisvą laiką",
+    "findingSlot": "Ieškoma laiko…",
+    "slotPicked": "Priskirta artimiausiam laisvam laikui",
+    "noSlotFound": "Artimiausiomis savaitėmis laisvo laiko nerasta"
   },
   "notifications": {
     "title": "Kliento pranešimai",
@@ -381,5 +401,14 @@
       "title": "Numatytieji garantijos nustatymai",
       "description": "Nustatyti numatytas garantijos sąlygas naujiems aptarnavimo įrašams"
     }
+  },
+  "concerns": {
+    "title": "Kliento pranešimai",
+    "addFirst": "Pridėti kliento pranešimą",
+    "add": "Pridėti dar vieną",
+    "placeholder": "Stabdant gale girdisi garsas",
+    "remove": "Pašalinti šį punktą",
+    "notAnswered": "Kol kas nieko nenustatyta",
+    "answered": "Nustatymų: {count}"
   }
 }

+ 427 - 6
messages/lt/settings.json

@@ -161,6 +161,9 @@
     "email": "El. paštas",
     "emailPlaceholder": "servisas@example.com",
     "address": "Adresas",
+    "slogan": "Šūkis",
+    "sloganPlaceholder": "Visų markių aptarnavimas ir remontas",
+    "sloganHint": "Viena eilutė po pavadinimu sąskaitose ir pasiūlymuose.",
     "addressPlaceholder": "Gatvės g. 1\nKab. 100\nMiestas, LT-12345",
     "saveCompany": "Išsaugoti įmonės informaciją",
     "addNewCompany": "Pridėti naują įmonę",
@@ -380,7 +383,7 @@
     "adminLabel": "Administratorius",
     "adminDescription": "Gali kviesti/šalinti narius ir valdyti bendrinamus duomenis.",
     "memberLabel": "Narys",
-    "memberDescription": "Leidimai nustatomi pagal priskirtą pasirinktinę rolę. Be pasirinktinės rolės — tik skaitymo prieiga.",
+    "memberDescription": "Teisės priklauso nuo priskirto vaidmens. Be vaidmens šis narys nieko negali daryti.",
     "roleAssigned": "Rolė atnaujinta",
     "failedAssignRole": "Nepavyko atnaujinti rolės",
     "removeMemberTitle": "Pašalinti narį",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Nepavyko atnaujinti rolės",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Technikas",
+    "technicianHint": "Gali gauti priskirtus darbus ir naudotis techniko programa",
+    "technicianFailed": "Nepavyko pakeisti",
+    "setupApp": "Nustatyti programėlę",
+    "setupAppTitle": "Nustatyti techniko programėlę",
+    "setupAppInstruction": "Paprašykite {name} tai atlikti telefone:",
+    "setupAppOrType": "Arba padiktuokite šį kodą:",
+    "setupAppExpiry": "Galioja vieną kartą, baigia galioti po {time}.",
+    "setupAppExpired": "Šis kodas nebegalioja. Uždarykite ir pradėkite iš naujo.",
+    "setupAppDone": "Atlikta",
+    "setupAppFailed": "Nepavyko sukurti nustatymo kodo",
+    "setupPageTitle": "Nustatyti techniko programėlę",
+    "setupPageBody": "Atidarykite „Torqvoice Tech“ šiame telefone, bakstelėkite „Nuskaityti nustatymo kodą“ ir vėl nukreipkite į tą patį kodą.",
+    "setupPageCode": "Arba įveskite šį kodą programėlėje",
+    "setupPageOpenApp": "Atidaryti „Torqvoice Tech“",
+    "setupPageExpiry": "Šis kodas galioja vieną kartą ir baigia galioti praėjus dešimčiai minučių nuo serviso sukūrimo.",
+    "setupAppStep1": "Įdiegti „Torqvoice Tech“",
+    "setupAppStep2": "Ją atidaryti ir bakstelėti „Nuskaityti nustatymo kodą“",
+    "setupAppStep3": "Nukreipti telefoną į šį kodą",
+    "setupAppNotCamera": "Įprasta telefono kamera neveiks. Nuskaityti reikia „Torqvoice Tech“ programėlėje.",
+    "addTechnician": "Pridėti techniką",
+    "addTechnicianHint": "Mechanikui, stovinčiam prie registratūros. Be el. pašto ir be laukimo.",
+    "technicianName": "Vardas",
+    "technicianNamePlaceholder": "Pilnas vardas",
+    "technicianPhone": "Mobiliojo numeris",
+    "technicianPhonePlaceholder": "Telefonas, kurį jie turi",
+    "addTechnicianSubmit": "Sukurti",
+    "addTechnicianNote": "Nuo tada jis prisijungia su tuo numeriu. Nereikia atsiminti slaptažodžio ir nieko rašyti pirmame programėlės ekrane.",
+    "addTechnicianDone": "{name} paruoštas. Parodykite jam kodą.",
+    "addTechnicianFailed": "Nepavyko sukurti techniko",
+    "setupAppCopyLink": "Kopijuoti nuorodą siuntimui",
+    "setupAppCopied": "Nukopijuota",
+    "revokeTechnicianTitle": "Atjungti jį nuo programėlės?",
+    "revokeTechnicianBody": "{name} iškart praranda prieigą telefone, o visi kodai nustoja veikti. Atliktas darbas ir valandos lieka kaip buvę.",
+    "revokeTechnicianConfirm": "Atjungti",
+    "addPerson": "Pridėti",
+    "addPersonTitle": "Pridėti žmogų į servisą",
+    "addPersonWho": "Šie du nustatomi skirtingai, tad pirmiausia pasakykite, kas tai.",
+    "choiceTechnician": "Mechanikas",
+    "choiceTechnicianHint": "Dirba su automobiliais ir naudoja „Torqvoice“ telefone. Lengviausia, kol jis stovi šalia, užtrunka apie minutę.",
+    "choiceMember": "Kažkas biure",
+    "choiceMemberHint": "Priima automobilius, užsako dalis ir siunčia sąskaitas kompiuteriu. Jūs išsiunčiate el. laišką, o jis pats pasirenka slaptažodį.",
+    "stepLabelWho": "Kas",
+    "stepLabelDetails": "Duomenys",
+    "stepLabelPhone": "Jo telefonas",
+    "techDetailsTitle": "Vardas ir mobiliojo numeris",
+    "techDetailsBlurb": "Nuo šiol jis jungsis su šiuo numeriu, tad nurodykite telefoną, kurį jis tikrai nešiojasi. Slaptažodžio, kurį reikėtų atsiminti, nėra.",
+    "techHandoffTitle": "Dabar perkelkite į jo telefoną",
+    "techHandoffBlurb": "Šis kodas prijungia jo telefoną prie jūsų serviso. Galioja vieną kartą ir tik dešimt minučių, tad padarykite tai, kol jis čia.",
+    "memberDetailsTitle": "Jo el. pašto adresas",
+    "memberDetailsBlurb": "Jis gaus laišką su nuoroda. Ją atidaręs pasirinks savo slaptažodį ir tada atsiras sąraše viršuje.",
+    "roleHint": "Administratoriai gali keisti nustatymus ir pridėti žmonių. Visi kiti dirba kasdienį darbą.",
+    "stepBack": "Atgal",
+    "stepHandoffDone": "Jis nuskaitė",
+    "stepDoneTitle": "{name} paruoštas",
+    "stepDoneBody": "Jis gali atidaryti programėlę ir matyti savo darbus. Kitą kartą prisijungs tik su mobiliojo numeriu, be kodo.",
+    "stepInvitedTitle": "Kvietimas išsiųstas į {email}",
+    "stepInvitedBody": "Jis atsiras sąraše, kai atidarys laišką ir priims kvietimą. Nuoroda galioja septynias dienas.",
+    "stepDoneAnother": "Pridėti dar vieną",
+    "clashTitle": "{name} jau turi šį numerį",
+    "clashBlurb": "Du žmonės negali dalytis vienu numeriu, nes su juo jie prisijungia. Kuris variantas?",
+    "clashSamePerson": "Tai {name}",
+    "clashSamePersonHint": "Tas pats žmogus grįžta arba vardas parašytas kitaip. Jo darbai ir valandos lieka su juo, o ką tik įvestas vardas pakeis senąjį.",
+    "clashTakeover": "Ne, tai {name}",
+    "clashTakeoverHint": "Kitas žmogus, kuris dabar turi šį numerį. {name} išlaiko viską, ką čia atliko, bet nebegali prisijungti, o naują numerį galėsite suteikti vėliau.",
+    "clashDifferentNumber": "Nei vienas, pakeisiu numerį",
+    "workshopCountry": "Kurioje šalyje yra jūsų servisas?",
+    "workshopCountryPlaceholder": "Pasirinkite šalį",
+    "workshopCountryHint": "Klausiama vieną kartą. Vėliau numerius galima rašyti trumpai. Tai galėsite pakeisti <link>Lokalizacijos nustatymuose</link>.",
+    "phonePreview": "Išsaugoma kaip",
+    "stepScannedTitle": "{name} prisijungė",
+    "countrySearch": "Ieškoti šalies",
+    "countryNoMatch": "Nėra atitinkančios šalies",
+    "choiceStandalone": "Tik vardas lentoje",
+    "choiceStandaloneHint": "Praktikantas, rangovas, bet kas, ką planuojate, bet kas niekada neprisijungia. Be telefono, be el. pašto, be paskyros. Ją galėsite suteikti vėliau.",
+    "standaloneDetailsTitle": "Vardas ir spalva",
+    "standaloneDetailsBlurb": "Tai viskas, ką jis gauna, ir viskas, ko reikia. Jis matomas lentoje ir darbuose, o prisijungti niekur nereikia.",
+    "boardColour": "Spalva lentoje",
+    "stepStandaloneTitle": "{name} yra lentoje",
+    "stepStandaloneBody": "Jį galite iškart planuoti ir skirti darbams. Jei kada prireiks programėlės, iš šio sąrašo pridėkite mobiliojo numerį.",
+    "boardOnly": "Tik lentoje",
+    "boardOnlyHint": "Juos planuojate ir skiriate darbams, bet jie niekada neprisijungia. Suteikite mobiliojo numerį, kai prireiks programėlės.",
+    "boardOnlyNoAccount": "Nėra paskyros",
+    "giveApp": "Suteikti programėlę",
+    "giveAppTitle": "Suteikti {name} programėlę",
+    "giveAppBlurb": "Trūksta tik mobiliojo numerio. Nuo tada su juo jis ir prisijungs.",
+    "giveAppKeepsHistory": "Viskas, kas jam jau užfiksuota, lieka savo vietoje.",
+    "giveAppSubmit": "Sukurti paskyrą",
+    "role": "Vaidmuo",
+    "inviteMemberHint": "Jis gaus laišką ir pats pasirinks slaptažodį.",
+    "removeBoardOnlyTitle": "Pašalinti {name} iš lentos?",
+    "removeBoardOnlyBody": "{name} nebesirodo darbų lentoje ir jo nebegalima priskirti darbams. Jau užfiksuotas darbas ir pažymėtos valandos lieka lygiai tokie patys.",
+    "removeBoardOnlyDone": "{name} pašalintas iš lentos",
+    "noRole": "Nėra rolės",
+    "worksOnJobs": "Dirba su automobiliais",
+    "createDefaultRoles": "Sukurti standartines roles",
+    "defaultRolesCreated": "Standartinės rolės sukurtos",
+    "noRolesYet": "Šios dirbtuvės dar neturi rolių, todėl, be administratoriaus, nėra ko suteikti. Sukurkite standartines ir teises patikslinkite vėliau.",
+    "noRoleDescription": "Jokių teisių. Gali prisijungti, bet kiekvienas ekranas jį atmes, kol nesuteiksite rolės žemiau.",
+    "cannotUseApp": "Jo rolė neleidžia dirbti su užsakymais. Pirma suteikite meistro rolę arba rolę su tomis pačiomis teisėmis.",
+    "revokeTechnicianDone": "{name} atjungtas nuo programėlės",
+    "noAccessTitle": "Prieigos kol kas nėra",
+    "noAccessBody": "Jūsų paskyra priklauso {workshop}, bet jai dar nesuteikta rolė, todėl čia nėra ką atidaryti. Paprašykite dirbtuvių savininko arba administratoriaus suteikti jums rolę.",
+    "setupPageInstall": "Atsisiųsti iš „Google Play“"
   },
   "invoice": {
     "title": "Sąskaitos ir pasiūlymai",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "Numeriai priskirti {count} klientams",
     "allCustomersNumbered": "Visi klientai turi numerį.",
     "assignCustomerNumbersConfirmTitle": "Priskirti klientų numerius?",
-    "assignCustomerNumbersConfirmDescription": "{count} klientams be numerio bus priskirti eilės numeriai sukūrimo tvarka, tęsiant nuo didžiausio esamo numerio. Klientai, jau turintys numerį, nekeičiami. Numerius galima redaguoti vėliau."
+    "assignCustomerNumbersConfirmDescription": "{count} klientams be numerio bus priskirti eilės numeriai sukūrimo tvarka, tęsiant nuo didžiausio esamo numerio. Klientai, jau turintys numerį, nekeičiami. Numerius galima redaguoti vėliau.",
+    "layoutColorsHint": "Spalvos, šriftai ir antraštės stilius yra skiltyje Šablonai.",
+    "goToTemplates": "Atverti šablonus",
+    "lockTitle": "Užbaigtų dokumentų užrakinimas",
+    "lockDescription": "Neleidžia keisti sąskaitos ar pasiūlymo, kai jis jau užbaigtas.",
+    "lockWhatItDoes": "Užrakinama: dalys, darbas, kiekiai, kainos, nuolaida, mokestis, dokumento numeris ir data. Dokumento ištrynimas taip pat blokuojamas.",
+    "lockWhatItAllows": "Toliau veikia: mokėjimų registravimas, mokėjimas kortele internetu, būsenos keitimas, siuntimas ir pakartotinis siuntimas, priedai ir vidinės pastabos. Užrakintą sąskaitą visada galima apmokėti.",
+    "lockUnlockNote": "Savininkai ir administratoriai gali atrakinti atskirą dokumentą jo paties puslapyje, kai kažką tikrai reikia pataisyti. Kiekvienas atrakinimas įrašomas į audito žurnalą.",
+    "lockInvoicesLabel": "Užrakinti sąskaitas",
+    "lockTriggerSent": "Kai sąskaita išsiųsta",
+    "lockTriggerPaid": "Kai sąskaita visiškai apmokėta",
+    "lockTriggerSentHint": "Užrakina, kai tik sąskaita išsiunčiama el. paštu arba sukuriama bendrinimo nuoroda. Anksčiau išsiųstoms sąskaitoms tai negalioja.",
+    "lockTriggerPaidHint": "Užrakina, kai padengiama visa suma arba sąskaita rankiniu būdu pažymima apmokėta. Iš dalies apmokėtą sąskaitą galima redaguoti.",
+    "lockQuotesLabel": "Užrakinti pasiūlymus",
+    "quoteLockTriggerSent": "Kai pasiūlymas išsiųstas",
+    "quoteLockTriggerAccepted": "Kai pasiūlymas priimtas",
+    "quoteLockTriggerSentHint": "Užrakina, kai tik pasiūlymas išsiunčiamas klientui. Rinkitės tik jei niekada nekeičiate pasiūlymo derybų metu.",
+    "quoteLockTriggerAcceptedHint": "Užrakina, kai klientas priima pasiūlymą arba jis paverčiamas darbu. Išsiųstus pasiūlymus galima redaguoti."
   },
   "layoutEditor": {
     "helpText": "Vilkite, kad pertvarkytumėte. Naudokite pločio perjungiklį, kad išdėstytumėte sekcijas greta. Iš eilės einančios pusės pločio sekcijos (K/D) bus vaizduojamos dviejuose stulpeliuose.",
     "addField": "Pridėti lauką",
     "custom": "pasirinktinis",
     "full": "Pilnas",
+    "boxed": "Rėmelis",
+    "plain": "Be rėmelio",
+    "boxedHint": "Spausdinama rėmelyje",
+    "plainHint": "Spausdinama be rėmelio",
     "L": "K",
     "R": "D",
     "left": "kairė",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Pilnas plotis — spustelėkite, kad padarytumėte pusės pločio (kairė)",
     "sections": {
       "header": "Antraštė",
+      "slogan": "Šūkis",
       "customer": "Klientas",
       "vehicle": "Transporto priemonė",
       "service": "Paslauga",
+      "document_title": "Dokumento antraštė",
+      "items_table": "Pozicijų lentelė",
       "parts_table": "Dalių lentelė",
       "labor_table": "Darbų lentelė",
       "totals": "Sumos",
       "notes": "Pastabos",
+      "attached_documents": "Pridėti dokumentai",
       "diagnostic_notes": "Diagnostikos pastabos",
       "findings": "Pastebėjimai",
+      "warranty": "Garantija",
       "bank_account": "Banko sąskaita",
       "footer": "Poraštė",
       "general": "Bendra",
@@ -493,12 +626,59 @@
       "tech_name": "Technikas",
       "logo": "Logotipas",
       "company_name": "Įmonės pavadinimas",
+      "company_slogan": "Šūkis",
       "company_address": "Adresas",
       "company_phone": "Telefonas",
       "company_email": "El. paštas",
       "company_org_number": "Įmonės kodas",
       "bank_account": "Banko sąskaita",
-      "org_number": "Įmonės kodas"
+      "footer_note": "Poraštės pastaba",
+      "org_number": "Įmonės kodas",
+      "portal_link": "Portalo nuoroda"
+    },
+    "presetsTitle": "Pradėti nuo išdėstymo",
+    "presetsHint": "Pakeičia žemiau esantį išdėstymą. Niekas neįrašoma, kol neišsaugote.",
+    "presets": {
+      "classic": {
+        "name": "Klasikinis",
+        "description": "Dalys ir darbas atskirose lentelėse, duomenys kairėje"
+      },
+      "letterhead": {
+        "name": "Firminis blankas",
+        "description": "Kontaktai apačioje, antraštė po adresais"
+      },
+      "compact": {
+        "name": "Kompaktiškas",
+        "description": "Be rėmelių, tik būtiniausia"
+      },
+      "minimal": {
+        "name": "Minimalus",
+        "description": "Tik tekstas baltame fone: be rėmelių ir juostų, tik linijos ir erdvė"
+      },
+      "itemized": {
+        "name": "Detalizuotas",
+        "description": "Vienas numeruotas eilučių sąrašas su mato vieneto stulpeliu"
+      },
+      "detailed": {
+        "name": "Išsamus",
+        "description": "Antraštė viršuje, transporto priemonė atskirai, abi lentelės ir visi blokai"
+      }
+    },
+    "style": {
+      "documentTitle": "Visas lapas",
+      "documentHint": "dydis, tarpai, akcentas, juostos",
+      "textColor": "Tekstas",
+      "labelColor": "Antraštė",
+      "backgroundColor": "Užpildas",
+      "borderColor": "Rėmelis",
+      "fontSize": "Dydis",
+      "rowPadding": "Eilutės aukštis",
+      "margin": "Paraštė",
+      "accentColor": "Akcentas",
+      "stripeColor": "Juosta",
+      "stripes": "Juostos",
+      "fontFamily": "Šriftas",
+      "fontInherit": "Paveldėti"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Šablonų presetai",
     "primaryColor": "Pagrindinė spalva",
+    "colors": "Spalvos",
+    "textColor": "Tekstas",
+    "textColorHint": "Antraščių ir teksto spalva",
+    "companyTextColor": "Įmonės pavadinimas",
+    "companyTextColorHint": "Pavadinimo spalva firminiame blanke",
+    "frameBorderColor": "Rėmelio linija",
+    "frameBorderColorHint": "Linija ten, kur rėmelis liečia popierių",
+    "frameShadow": "Rėmelio šešėlis",
+    "frameShadowOn": "Su šešėliu",
+    "frameShadowOff": "Plokščias",
+    "backgroundColor": "Fonas",
+    "backgroundColorClear": "Išvalyti",
+    "backgroundColorHint": "Palikite tuščią baltam popieriui. Šviesus atspalvis spausdinamas kaip tonuotas lapas.",
     "fontAndLayout": "Šriftas ir išdėstymas",
     "fontFamily": "Šrifto šeima",
     "helveticaDefault": "Helvetica (numatytasis)",
@@ -525,6 +718,10 @@
     "standard": "Standartinis",
     "compact": "Kompaktiškas",
     "modern": "Modernus",
+    "framed": "Rėmelis",
+    "letterheadMark": "Firminis ženklas",
+    "letterheadLogo": "Logotipas",
+    "letterheadCompanyName": "Įmonės pavadinimas",
     "preview": "{name} peržiūra",
     "billTo": "Gavėjas",
     "preparedFor": "Paruošta",
@@ -594,7 +791,11 @@
       "slate": "Šiferinė",
       "rose": "Rožinė",
       "indigo": "Indigo"
-    }
+    },
+    "goToLayout": "Išdėstymas ir skiltys",
+    "openDesigner": "Atverti dizainerį",
+    "designerIntro": "Pasirinkite pradžios tašką ir atverkite dizainerį, kad pakeistumėte viską.",
+    "designerHint": "Spalvos, šriftai, tarpai ir visos skiltys yra dizaineryje."
   },
   "payment": {
     "readMore": "Skaityti daugiau",
@@ -739,6 +940,7 @@
       "NGN": "Nigerijos naira",
       "KES": "Kenijos šilingas",
       "MAD": "Maroko dirhamas",
+      "DZD": "Alžyro dinaras",
       "GHS": "Ganos sedis",
       "QAR": "Kataro rialas",
       "KWD": "Kuveito dinaras",
@@ -805,7 +1007,16 @@
     "failedSave": "Nepavyko išsaugoti lauko",
     "failedDelete": "Nepavyko ištrinti",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Nepriskirta",
+    "defaultValue": "Numatytoji reikšmė",
+    "defaultValueHint": "Automatiškai užpildoma naujuose įrašuose ir spausdinama, kol neįvesta reikšmė.",
+    "defaultValueNone": "Nėra",
+    "defaultValueCheckedHint": "Pažymėta pagal numatytuosius nustatymus",
+    "placement": "Vieta dokumente",
+    "placementHidden": "Nespausdinama",
+    "placementHint": "Kurioje sąskaitos arba pasiūlymo dalyje spausdinamas šis laukas. Dizaineryje jį galima įjungti ir kitose dalyse.",
+    "failedSavePlacement": "Nepavyko išsaugoti lauko vietos"
   },
   "workshop": {
     "title": "Dirbtuvių numatytosios reikšmės",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Patikra nepavyko",
       "configurePerPart": "Nustatykite dalies min. kiekį sandėlio puslapyje →",
       "readMore": "Skaityti daugiau"
+    },
+    "technicianStatus": {
+      "title": "Torqvoice techniko programėlė (Android/iOS)",
+      "description": "Pranešimas, kai technikas pakeičia darbą telefone.",
+      "inApp": "Pranešti registratūrai",
+      "inAppHint": "Pranešimas, kai darbas baigtas, laukia dalių arba vėl pradėtas.",
+      "save": "Išsaugoti",
+      "saved": "Pranešimų nustatymai išsaugoti",
+      "saveFailed": "Nepavyko išsaugoti nustatymų"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Siųskite ir gaukite „Telegram“ žinutes su klientais tiesiai iš „Torqvoice“."
       }
     }
+  },
+  "designer": {
+    "invoice": "Sąskaita",
+    "quote": "Pasiūlymas",
+    "eyebrow": "Dokumentų kūrimo įrankis",
+    "galleryTitle": "Pradėkite nuo šablono",
+    "galleryHint": "Pasirinkite atspirties tašką. Kūrimo įrankyje galėsite pakeisti viską.",
+    "yourDesigns": "Jūsų dizainai",
+    "templates": "Šablonai",
+    "inUse": "Naudojamas",
+    "savedOn": "Išsaugota {date}",
+    "deleteDesignTitle": "Ištrinti dizainą",
+    "deleteDesignBody": "Ištrinti dizainą „{name}“? Sąskaita ir pasiūlymas išlaikys tai, kas pritaikyta; dings tik išsaugota kopija.",
+    "delete": "Ištrinti",
+    "deleteDesign": "Ištrinti šį dizainą",
+    "continueCurrent": "Tęsti su dabartiniu išdėstymu",
+    "backToSettings": "Grįžti į nustatymus",
+    "useInvoiceDesign": "Naudoti sąskaitos dizainą",
+    "copiedToQuote": "Sąskaitos dizainas nukopijuotas į pasiūlymą",
+    "rulers": "Liniuotės",
+    "saveDesign": "Išsaugoti dizainą",
+    "saveDesignHint": "Išsaugokite pavadintą šio dizaino kopiją, kad grįžtumėte prie jos iš šablonų galerijos",
+    "reset": "Atstatyti",
+    "save": "Išsaugoti",
+    "saving": "Išsaugoma…",
+    "saved": "Išsaugota",
+    "couldNotSave": "Nepavyko išsaugoti",
+    "couldNotSaveDesigns": "Nepavyko išsaugoti jūsų dizainų",
+    "designUpdated": "Atnaujinta „{name}“",
+    "designSaved": "Išsaugota kaip „{name}“",
+    "defaultDesignName": "Mano {doc} dizainas",
+    "documentStyling": "Dokumento stilius",
+    "sections": "Sekcijos",
+    "sectionEmpty": "tuščia",
+    "sectionEmptyHint": "Rodoma, bet su dabartiniais duomenimis joje nėra ko spausdinti.",
+    "sectionShownHint": "Matoma lape. Spustelėkite, kad paslėptumėte.",
+    "sectionHiddenHint": "Paslėpta lape. Spustelėkite, kad parodytumėte.",
+    "railHint": "Vilkite sekciją ant puslapio: paleiskite tarp blokų, kad pakeistumėte eiliškumą, ant kortelės, kad atsidurtų šalia jos, arba bet kur kitur, kad padėtumėte laisvai. Puslapis paliks vietos aplink ją.",
+    "returnToFlow": "Grąžinti {section} į srautą",
+    "saveDialogTitle": "Išsaugoti šį dizainą",
+    "saveDialogBody": "Išsaugo pavadintą dabartinio išdėstymo ir išvaizdos kopiją. Rasite ją skiltyje Jūsų dizainai, šablonų galerijoje.",
+    "designNamePlaceholder": "Dizaino pavadinimas",
+    "nameExists": "Dizainas tokiu pavadinimu jau yra; išsaugojus jis bus atnaujintas.",
+    "updateDesign": "Atnaujinti dizainą",
+    "cancel": "Atšaukti",
+    "insertHere": "Įterpti čia",
+    "dropLeftColumn": "Kairysis stulpelis",
+    "dropRightColumn": "Dešinysis stulpelis",
+    "freePosition": "Laisva vieta",
+    "sectionSettings": "Sekcijos nustatymai",
+    "panelStyle": "Skydelio stilius",
+    "variant": {
+      "accent": "Akcentas",
+      "panel": "Skydelis",
+      "outline": "Kontūras",
+      "lines": "Linijos",
+      "hint": "Akcentas nuspalvina kortelę pagrindine spalva. Skydelis suvienodina ją su kitomis detalių kortelėmis. Kontūras piešia tik rėmelį, o Linijos spausdina be rėmelio.",
+      "classic": "Klasikinis",
+      "box": "Rėmelis",
+      "totalsHint": "Klasikinis spausdina paprastas eilutes su linija virš sumos. Rėmelis jas įrėmina. Skydelis ir Akcentas deda jas ant kortelės."
+    },
+    "alignment": "Lygiavimas",
+    "alignCenter": "Centre",
+    "itemsTableHint": "Vienas numeruotas visų darbo eilučių sąrašas, pirmiausia darbai, paskui dalys, vietoj atskirų lentelių.",
+    "discardChanges": "Atmesti pakeitimus",
+    "tablesExclusiveHint": "Lape spausdinamas vienas išdėstymas: vienas numeruotas sąrašas arba atskiros dalių ir darbų lentelės. Įjungus vieną, kitas išsijungia.",
+    "innerPadding": "Vidinis tarpas",
+    "totalsWidth": "Plotis",
+    "totalsWidthHint": "Tuščias užima visą eilutę. Nurodžius taškus, blokas kabinamas dešinėje; stulpelyje jis užima stulpelio plotį.",
+    "placement": "Išdėstymas",
+    "visible": "Matoma",
+    "columnFull": "Visas plotis",
+    "columnLeft": "Kairė",
+    "columnRight": "Dešinė",
+    "drawBox": "Piešti rėmelį",
+    "showHeading": "Rodyti antraštę",
+    "spacing": "Tarpai",
+    "placedByHand": "Ši sekcija padėta ranka, todėl srauto tarpai jos nepajudina.",
+    "placedByHandFramed": "Įrėmintas firminis blankas guli ant juostos; vilkite jį, kad pastumtumėte.",
+    "placedByHandDrag": "Vilkite ją arba grąžinkite į srautą, kad galėtumėte naudoti tarpus.",
+    "marginTop": "Viršus",
+    "marginBottom": "Apačia",
+    "marginLeft": "Kairė",
+    "marginRight": "Dešinė",
+    "spacingHint": "Tuščios vietos punktai, kuriuos sekcija išlaiko aplink save sraute.",
+    "logo": "Logotipas",
+    "size": "Dydis",
+    "logoHint": "Išjunkite logotipą skiltyje Laukai, kad vietoj jo būtų spausdinamas įmonės pavadinimas.",
+    "fields": "Laukai",
+    "removeField": "Pašalinti iš šios sekcijos",
+    "yourCustomFields": "Jūsų pasirinktiniai laukai",
+    "appearance": "Išvaizda",
+    "details": "Detalės",
+    "text": "Tekstas",
+    "companyName": "Įmonės pavadinimas",
+    "heading": "Antraštė",
+    "fill": "Užpildas",
+    "border": "Rėmelis",
+    "lineWidth": "Linijos storis",
+    "borderWidth": "Rėmelio storis",
+    "outerBorder": "Išorinis rėmelis",
+    "rowBanding": "Eilučių juostos",
+    "likeSheet": "Kaip lape",
+    "on": "Įjungta",
+    "off": "Išjungta",
+    "font": "Šriftas",
+    "inherit": "Paveldėti",
+    "auto": "auto",
+    "sectionDragHint": "Vilkite šią sekciją sąraše arba ant puslapio, kad ją perkeltumėte. Padėjus ranka, rodyklių klavišai pastumia ją vienu punktu, su Shift dešimčia, o Escape atšaukia vilkimą.",
+    "document": "Dokumentas",
+    "documentSubtitle": "Taikoma visam lapui",
+    "headerStyleTitle": "Antraštės stilius",
+    "headerStyle": {
+      "standard": {
+        "name": "Standartinis",
+        "desc": "Pavadinimas ir duomenys ant balto, brūkšnys apačioje"
+      },
+      "compact": {
+        "name": "Kompaktiškas",
+        "desc": "Siaura antraštė, tankios eilutės"
+      },
+      "modern": {
+        "name": "Modernus",
+        "desc": "Spalvota juosta per visą plotį"
+      },
+      "framed": {
+        "name": "Įrėmintas",
+        "desc": "Juosta viršuje, juostelė kairiajame krašte"
+      }
+    },
+    "colors": "Spalvos",
+    "primary": "Pagrindinė",
+    "background": "Fonas",
+    "accent": "Akcentas",
+    "frame": "Rėmelis",
+    "rail": "Juostelė",
+    "leftEdge": "Kairysis kraštas",
+    "rightEdge": "Dešinysis kraštas",
+    "frameLine": "Rėmelio linija",
+    "cornerRadius": "Kampų apvalinimas",
+    "shadow": "Šešėlis",
+    "shadowThin": "Plonas",
+    "shadowNormal": "Įprastas",
+    "shadowWide": "Platus",
+    "typography": "Tipografija",
+    "baseSize": "Bazinis dydis",
+    "page": "Puslapis",
+    "margins": "Paraštės",
+    "rowHeight": "Eilutės aukštis",
+    "band": "Juosta",
+    "sample": {
+      "itemLabor": "Pakeisti priekiniai stabdžiai",
+      "itemDisc": "Stabdžių diskas, priekinis",
+      "itemPads": "Kaladėlių komplektas, priekinė ašis",
+      "itemConsumables": "Eksploatacinės medžiagos",
+      "unitPcs": "vnt.",
+      "unitSet": "kompl.",
+      "unitEach": "x",
+      "findingPads": "Galinės kaladėlės 15 %",
+      "findingPadsNote": "Pakeisti per 5 000 km",
+      "findingOilWeep": "Nedidelis alyvos sunkimasis ties vožtuvų dangteliu",
+      "notes": "Ačiū, kad pasirinkote mūsų servisą. Kilus klausimų, susisiekite su mumis.",
+      "warranty": "12 mėnesių garantija dalims ir darbui.",
+      "serviceTitle": "Metinė apžiūra ir stabdžiai",
+      "serviceType": "Remontas",
+      "companyName": "Jūsų servisas",
+      "slogan": "Kokybiškas aptarnavimas, kuriuo galite pasitikėti",
+      "footerNote": "Ačiū, kad renkatės mus",
+      "value": "Pavyzdys"
+    },
+    "logoUpload": "Įkelti logotipą",
+    "logoReplace": "Pakeisti logotipą",
+    "logoUploading": "Įkeliama…",
+    "logoFailed": "Nepavyko įkelti vaizdo",
+    "footerLogoHint": "Įjunkite logotipą skiltyje Laukai, kad jis būtų spausdinamas ir puslapio apačioje.",
+    "logoReset": "Naudoti įmonės logotipą",
+    "logoOwn": "Spausdinamas tik šiame dokumente. Įmonės logotipas nekeičiamas.",
+    "logoInherited": "Naudojamas įmonės logotipas. Įkelkite kitą čia, kad jis būtų naudojamas tik šiame dokumente.",
+    "slogan": "Šūkis",
+    "sloganPlaceholderHint": "Šūkis nenustatytas, todėl lape rodomas pavyzdinis tekstas, kuris nebus spausdinamas.",
+    "sloganSetHint": "Jūsų šūkis imamas iš įmonės duomenų.",
+    "sloganLink": "Įmonės nustatymai",
+    "placeholder": "Vietaženklis",
+    "leaveTitle": "Išeiti neišsaugojus?",
+    "leaveBody": "Šio dizaino pakeitimai neišsaugoti ir bus prarasti.",
+    "leaveConfirm": "Išeiti",
+    "boldField": "Paryškinta"
+  },
+  "preview": {
+    "title": "Stabdžių aptarnavimas ir tepalų keitimas",
+    "serviceType": "Techninė priežiūra",
+    "findingPads": "Galinės stabdžių kaladėlės nusidėvėjusios iki 15 %",
+    "findingPadsNote": "Rekomenduojama pakeisti per 8 000 km",
+    "findingOilLeak": "Nedidelis alyvos sunkimasis ties vožtuvų dangtelio tarpine",
+    "invoiceNotes": "Pakeistos priekinės stabdžių kaladėlės. Alyva ir filtras pakeisti sintetine 5W-30. Kitą apžiūrą rekomenduojame ties 80 000 km.",
+    "quoteNotes": "Rekomenduojame pakeisti priekines stabdžių kaladėles. Alyvos ir filtro keitimas sintetine 5W-30.",
+    "partBrakePads": "Stabdžių kaladėlės (priekinės)",
+    "partOilFilter": "Alyvos filtras",
+    "partSyntheticOil": "Sintetinė alyva 5W-30",
+    "laborBrakeReplacement": "Stabdžių keitimas",
+    "laborOilChange": "Alyvos keitimas"
   }
 }

+ 4 - 2
messages/lt/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "Aukšta",
     "findingSeverityNeedsWork": "Vidutinė",
     "findingSeverityMonitor": "Žema",
-    "tel": "Tel.: {phone}"
+    "tel": "Tel.: {phone}",
+    "customFields": "Papildoma informacija"
   },
   "quote": {
     "title": "Pasiūlymas",
@@ -125,7 +126,8 @@
       "converted": "Konvertuotas",
       "changes_requested": "Prašomi pakeitimai"
     },
-    "tel": "Tel.: {phone}"
+    "tel": "Tel.: {phone}",
+    "customFields": "Papildoma informacija"
   },
   "inspection": {
     "title": "Transporto priemonės apžiūra",

+ 2 - 1
messages/lt/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Kol kas nieko nepridėta. Nufotografuokite subraižytą ratlankį, kol padangos prieš jus.",
     "captionPlaceholder": "Kas čia matyti?",
     "onInvoice": "Sąskaitoje",
-    "invoiceHint": "Sąskaitai pažymėti failai nukopijuojami į darbo užsakymą ar sąskaitą apmokestinant komplektą.",
+    "invoiceHint": "Sąskaitai pažymėtos nuotraukos nukopijuojamos į darbo užsakymą ar sąskaitą apmokestinant komplektą. Dokumentai lieka čia, prie komplekto.",
+    "documentStays": "Lieka prie komplekto, į sąskaitas nekopijuojamas",
     "deleteTitle": "Pašalinti šį failą?",
     "deleteBody": "{name} pašalinamas iš komplekto. Tai, kas jau nukopijuota į sąskaitą, lieka.",
     "failed": "Nepavyko išsaugoti",

+ 3 - 1
messages/lt/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "Kurį punktą atsako?",
+    "concernNone": "Klientas apie tai neklausė"
   },
   "observationsPage": {
     "searchPlaceholder": "Ieškoti pagal aprašymą, pastabas arba transporto priemonę...",

+ 4 - 1
messages/lt/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Atskiras technikas",
     "deleteTitle": "Ištrinti techniką",
     "deleteDescription": "Pašalinti \"{name}\" iš darbų lentos? Esami priskyrimai taip pat bus pašalinti.",
-    "addTechnician": "Pridėti techniką"
+    "addTechnician": "Pridėti techniką",
+    "standaloneOnly": "Vardas lentoje tam, kuris neprisijungia: praktikantui ar rangovui. Mechaniką, kuris naudoja programėlę, pridėkite Komandos puslapyje.",
+    "linkedTo": "Prisijungia kaip {name}",
+    "linkedManagedOnTeam": "Valdoma Komandos puslapyje kartu su prieiga prie programėlės."
   },
   "jobDetail": {
     "viewDetails": "Peržiūrėti informaciją",

+ 14 - 4
messages/nb/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Opprettet arbeidsplass",
     "work_bay_update": "Oppdaterte arbeidsplass",
     "work_bay_delete": "Slettet arbeidsplass",
-    "settings_whatsappUpdated": "WhatsApp-innstillinger oppdatert",
-    "settings_whatsappNumberRegistered": "WhatsApp-nummer registrert",
-    "settings_whatsappDisconnected": "WhatsApp koblet fra"
+    "auth_appSetupRedeemed": "Logget inn med oppsettskode",
+    "auth_technicianCodeSignIn": "Logget inn med engangskode",
+    "team_createAppSetupCode": "Utstedte en oppsettskode for appen",
+    "team_createTechnicianAccount": "Opprettet en teknikerkonto",
+    "team_removeTechnicianAccess": "Fjernet en tekniker og trakk tilbake tilgangen",
+    "team_setMemberTechnician": "Endret om et medlem er tekniker",
+    "settings_whatsappUpdated": "Oppdaterte WhatsApp-innstillinger",
+    "settings_whatsappDisconnected": "Koblet fra WhatsApp",
+    "settings_whatsappNumberRegistered": "Registrerte et WhatsApp-nummer",
+    "team_giveTechnicianTheApp": "Ga en tavle-tekniker en konto",
+    "team_createDefaultRoles": "Opprettet standardrollene",
+    "settings_setCustomFieldPlacement": "Oppdaterte plassering av egendefinert felt"
   },
   "summary": {
     "customField_create": "Opprettet egendefinert felt «{name}»",
@@ -265,6 +274,7 @@
     "whatsapp_send": "Sendte en WhatsApp-melding til {name}",
     "work_bay_create": "Opprettet arbeidsplass «{name}»",
     "work_bay_update": "Oppdaterte arbeidsplass «{name}»",
-    "work_bay_delete": "Slettet arbeidsplass {id}"
+    "work_bay_delete": "Slettet arbeidsplass {id}",
+    "settings_setCustomFieldPlacement": "Endret hvor et egendefinert felt skrives ut"
   }
 }

+ 5 - 0
messages/nb/common.json

@@ -95,5 +95,10 @@
     "placeholder": "f.eks. Vi har problemer med serverinfrastrukturen vår og jobber med saken.",
     "posted": "Meldingen er publisert",
     "cleared": "Meldingen er fjernet"
+  },
+  "pdfPreview": {
+    "title": "PDF-forhåndsvisning",
+    "preview": "Forhåndsvisning",
+    "failed": "Kunne ikke generere PDF-forhåndsvisningen."
   }
 }

+ 21 - 1
messages/nb/customers.json

@@ -35,6 +35,8 @@
     "taxExemptBadge": "Avgiftsfritatt",
     "tabs": {
       "vehicles": "Kjøretøy ({count})",
+      "invoices": "Fakturaer ({count})",
+      "quotes": "Tilbud ({count})",
       "messages": "Meldinger",
       "requests": "Forespørsler ({count})",
       "sms": "SMS",
@@ -48,7 +50,25 @@
       "mileageMarine": "Motortimer",
       "services": "Tjenester"
     },
-    "noVehicles": "Ingen kjøretøy tilknyttet denne kunden"
+    "documentTable": {
+      "invoiceNumber": "Fakturanr.",
+      "quoteNumber": "Tilbudsnr.",
+      "title": "Tittel",
+      "vehicle": "Kjøretøy",
+      "status": "Status",
+      "date": "Dato",
+      "total": "Totalt",
+      "noVehicle": "Kun deler",
+      "searchPlaceholder": "Søk...",
+      "noMatches": "Ingen treff på søket ditt",
+      "sort": {
+        "asc": "stigende",
+        "desc": "synkende"
+      }
+    },
+    "noVehicles": "Ingen kjøretøy tilknyttet denne kunden",
+    "noInvoices": "Ingen fakturaer for denne kunden",
+    "noQuotes": "Ingen tilbud for denne kunden"
   },
   "form": {
     "addTitle": "Legg til ny kunde",

+ 27 - 0
messages/nb/documentLock.json

@@ -0,0 +1,27 @@
+{
+  "lockedTitle": {
+    "invoice": {
+      "sent": "Denne fakturaen er låst fordi den er sendt",
+      "paid": "Denne fakturaen er låst fordi den er betalt"
+    },
+    "quote": {
+      "sent": "Dette tilbudet er låst fordi det er sendt",
+      "accepted": "Dette tilbudet er låst fordi det er akseptert"
+    }
+  },
+  "lockedBody": "Deler, arbeid, priser, rabatt, avgift, nummer og dato kan ikke lenger endres. Betalinger, statusendringer, sending og vedlegg virker fortsatt.",
+  "lockedAdminHint": "Som eier eller administrator kan du låse opp dokumentet hvis noe virkelig må rettes. Opplåsingen loggføres.",
+  "lockedMemberHint": "Be en eier eller administrator låse opp dokumentet hvis noe må rettes.",
+  "unlock": "Lås opp for redigering",
+  "relock": "Lås igjen",
+  "unlockConfirmTitle": "Låse opp dette dokumentet?",
+  "unlockConfirmDescription": {
+    "invoice": "Dokumentet kan redigeres igjen, og endringen loggføres med navnet ditt. Bruk heller kreditnota der regelverket krever det.",
+    "quote": "Dokumentet kan redigeres igjen, og endringen loggføres med navnet ditt."
+  },
+  "unlocked": "Låst opp for redigering",
+  "relocked": "Låst igjen",
+  "reopenedTitle": "Dette dokumentet er låst opp for redigering",
+  "reopenedBody": "Det kan redigeres til det låses igjen.",
+  "failed": "Kunne ikke endre låsen"
+}

+ 5 - 0
messages/nb/featureHints.json

@@ -6,5 +6,10 @@
   "telegram": {
     "title": "Telegram er på",
     "body": "Kundesamtaler havner her. Svar uten å forlate appen."
+  },
+  "invoice-designer": {
+    "title": "Fakturaene er bygget om",
+    "body": "Bestem oppsett, farger og skrifter på fakturaer og tilbud i den nye designeren, under Maler.",
+    "cta": "Åpne Maler"
   }
 }

+ 3 - 1
messages/nb/navigation.json

@@ -72,7 +72,9 @@
     "vehicle": "Kjøretøy",
     "quote": "Tilbud",
     "part": "Del",
-    "inspection": "Inspeksjon"
+    "inspection": "Inspeksjon",
+    "shopActions": "Verkstedet",
+    "person": "Legg til en person"
   },
   "purchaseWhiteLabel": "Kjøp White-Label",
   "licenseExpired": "Lisensen din har utløpt. Funksjoner kan være begrenset.",

+ 13 - 2
messages/nb/pdf.json

@@ -19,6 +19,12 @@
     "description": "Beskrivelse",
     "qty": "Ant.",
     "unitPrice": "Enhetspris",
+    "items": "Poster",
+    "pos": "Nr.",
+    "unitOfMeasure": "Enhet",
+    "invoiceNumberLabel": "Fakturanr.",
+    "customerNumberLabel": "Kundenr.",
+    "dateLabel": "Dato",
     "total": "Totalt",
     "labor": "Arbeid",
     "hours": "Timer",
@@ -64,7 +70,9 @@
     "professionalWorkshop": "Profesjonell verkstedadministrasjon",
     "tel": "Tlf: {phone}",
     "org": "Org: {org}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Tilleggsinformasjon",
+    "telegramConnect": "Chat med oss på Telegram"
   },
   "quote": {
     "title": "TILBUD",
@@ -100,7 +108,10 @@
     "validityFooter30": "Dette tilbudet er gyldig i 30 dager",
     "viewPortal": "Se portalen din: {url}",
     "tel": "Tlf: {phone}",
-    "qtyOrHours": "Unit / Hours"
+    "qtyOrHours": "Unit / Hours",
+    "customFieldsTitle": "Tilleggsinformasjon",
+    "quoteNumberLabel": "Tilbudsnr.",
+    "validUntilLabel": "Gyldig til"
   },
   "inspection": {
     "title": "KJØRETØYKONTROLL",

+ 3 - 1
messages/nb/quotes.json

@@ -48,7 +48,9 @@
       "details": "Detaljer",
       "images": "Bilder",
       "documents": "Dokumenter"
-    }
+    },
+    "customFieldsInvalid": "Fyll ut alle obligatoriske egendefinerte felt",
+    "customFieldsSaveFailed": "Kunne ikke lagre egendefinerte felt"
   },
   "form": {
     "newQuote": "Nytt tilbud",

+ 31 - 2
messages/nb/service.json

@@ -185,7 +185,11 @@
     "paidBadge": "BETALT",
     "entityLabel": "Faktura",
     "emailSubject": "Betalingsbekreftelse",
-    "statusEmailSubject": "Oppdatering av servicestatus"
+    "statusEmailSubject": "Oppdatering av servicestatus",
+    "markCompletedTitle": "Merke denne fakturaen som fullført?",
+    "markCompletedDescription": "Den er sendt til kunden, men står fortsatt som ikke ferdig, så den blir liggende på tavla.",
+    "markCompletedConfirm": "Merk som fullført",
+    "lockedFieldsetLabel": "Låst faktura, redigering er deaktivert"
   },
   "payments": {
     "title": "Betalinger",
@@ -344,7 +348,23 @@
     "setDefaults": "Standardinnstillinger",
     "workBay": "Arbeidsplass",
     "selectWorkBay": "Velg arbeidsplass …",
-    "noWorkBay": "Ingen arbeidsplass"
+    "noWorkBay": "Ingen arbeidsplass",
+    "technicians": "Teknikere",
+    "otherTeamMembers": "Andre i teamet",
+    "makeTechnician": "Gjør dem til tekniker",
+    "addSomeoneNew": "Legg til noen ny",
+    "notOnBoard": "Ikke på tavlen ennå",
+    "putOnBoard": "Sett på tavlen",
+    "slotTaken": "{count, plural, one {Denne tiden er allerede booket} other {Denne tiden har # kollisjoner}}",
+    "anotherJob": "en annen jobb",
+    "clashTechnician": "teknikeren er opptatt",
+    "clashBay": "plassen er i bruk",
+    "clashBoth": "begge er opptatt",
+    "bookedAnyway": "Lagret likevel. Endre tiden, eller velg neste ledige tid.",
+    "pickNextAvailable": "Velg neste ledige tid",
+    "findingSlot": "Finner en tid…",
+    "slotPicked": "Booket inn på neste ledige tid",
+    "noSlotFound": "Fant ingen ledig tid de neste ukene"
   },
   "notifications": {
     "title": "Kundevarsler",
@@ -381,5 +401,14 @@
       "title": "Standard garantiinnstillinger",
       "description": "Angi standard garantivilkår for nye serviceoppføringer"
     }
+  },
+  "concerns": {
+    "title": "Kundens beskrivelse",
+    "addFirst": "Legg til kundens beskrivelse",
+    "add": "Legg til en til",
+    "placeholder": "Det kommer en lyd bakfra når jeg bremser",
+    "remove": "Fjern dette punktet",
+    "notAnswered": "Ingenting funnet på dette ennå",
+    "answered": "{count} funn på dette"
   }
 }

+ 427 - 6
messages/nb/settings.json

@@ -161,6 +161,9 @@
     "email": "E-post",
     "emailPlaceholder": "service@eksempel.no",
     "address": "Adresse",
+    "slogan": "Slagord",
+    "sloganPlaceholder": "Service og reparasjon for alle merker",
+    "sloganHint": "Én linje under navnet på fakturaer og tilbud.",
     "addressPlaceholder": "Hovedgaten 123\n0001 Oslo",
     "saveCompany": "Lagre bedriftsdetaljer",
     "addNewCompany": "Legg til ny bedrift",
@@ -380,7 +383,7 @@
     "adminLabel": "Administrator",
     "adminDescription": "Kan invitere/fjerne medlemmer og administrere delte data.",
     "memberLabel": "Medlem",
-    "memberDescription": "Tillatelser bestemt av tildelt egendefinert rolle. Ingen egendefinert rolle betyr kun lesetilgang.",
+    "memberDescription": "Rettigheter følger av tildelt rolle. Uten rolle kan dette medlemmet ikke gjøre noe.",
     "roleAssigned": "Rolle oppdatert",
     "failedAssignRole": "Kunne ikke oppdatere rolle",
     "removeMemberTitle": "Fjern medlem",
@@ -392,7 +395,111 @@
     "failedUpdateRole": "Kunne ikke oppdatere rolle",
     "removeMember": "Remove member",
     "cancelInvite": "Cancel invitation",
-    "editRole": "Edit role"
+    "editRole": "Edit role",
+    "technician": "Tekniker",
+    "technicianHint": "Kan tildeles jobber og bruke teknikerappen",
+    "technicianFailed": "Kunne ikke endres",
+    "setupApp": "Sett opp app",
+    "setupAppTitle": "Sett opp teknikerappen",
+    "setupAppInstruction": "Be {name} gjøre dette på telefonen:",
+    "setupAppOrType": "Eller les opp denne koden:",
+    "setupAppExpiry": "Virker én gang og utløper om {time}.",
+    "setupAppExpired": "Denne koden er utløpt. Lukk og start på nytt.",
+    "setupAppDone": "Ferdig",
+    "setupAppFailed": "Kunne ikke lage en oppsettskode",
+    "setupPageTitle": "Sett opp teknikerappen",
+    "setupPageBody": "Åpne Torqvoice Tech på denne telefonen, trykk Skann oppsettskode, og rett den mot den samme koden igjen.",
+    "setupPageCode": "Eller skriv inn denne koden i appen",
+    "setupPageOpenApp": "Åpne Torqvoice Tech",
+    "setupPageExpiry": "Denne koden virker én gang og utløper ti minutter etter at verkstedet laget den.",
+    "setupAppStep1": "Installer Torqvoice Tech",
+    "setupAppStep2": "Åpne den og trykke «Skann oppsettskode»",
+    "setupAppStep3": "Rette telefonen mot denne koden",
+    "setupAppNotCamera": "Telefonens vanlige kameraapp virker ikke. Det må skannes inne i Torqvoice Tech.",
+    "addTechnician": "Legg til en tekniker",
+    "addTechnicianHint": "For en mekaniker som står i skranken. Ingen e-post, ingen venting.",
+    "technicianName": "Navn",
+    "technicianNamePlaceholder": "Fullt navn",
+    "technicianPhone": "Mobilnummer",
+    "technicianPhonePlaceholder": "Telefonen i lomma",
+    "addTechnicianSubmit": "Opprett",
+    "addTechnicianNote": "Fra da av logger han inn med det nummeret. Ingen passord å huske, og ingenting å skrive på appens første skjerm.",
+    "addTechnicianDone": "{name} er opprettet. Vis ham koden.",
+    "addTechnicianFailed": "Kunne ikke opprette teknikeren",
+    "setupAppCopyLink": "Kopier lenke å sende",
+    "setupAppCopied": "Kopiert",
+    "revokeTechnicianTitle": "Logge ham ut av appen?",
+    "revokeTechnicianBody": "{name} mister tilgangen på telefonen umiddelbart, og alle koder slutter å virke. Utført arbeid og timer blir stående som de er.",
+    "revokeTechnicianConfirm": "Logg ut",
+    "addPerson": "Legg til",
+    "addPersonTitle": "Legg noen til i verkstedet",
+    "addPersonWho": "De to settes opp på hver sin måte, så si først hvem dette er.",
+    "choiceTechnician": "En mekaniker",
+    "choiceTechnicianHint": "Jobber på bilene og bruker Torqvoice på telefonen. Enklest mens han står her hos deg, og tar omtrent ett minutt.",
+    "choiceMember": "Noen på kontoret",
+    "choiceMemberHint": "Tar imot biler, bestiller deler og sender fakturaer, på datamaskin. Du sender en e-post, og han velger sitt eget passord.",
+    "stepLabelWho": "Hvem",
+    "stepLabelDetails": "Detaljer",
+    "stepLabelPhone": "Telefonen hans",
+    "techDetailsTitle": "Navn og mobilnummer",
+    "techDetailsBlurb": "Mobilnummeret er det han logger inn med fra nå av, så bruk telefonen han faktisk har med seg. Det finnes ikke noe passord å huske eller glemme.",
+    "techHandoffTitle": "Få det over på telefonen hans",
+    "techHandoffBlurb": "Denne koden kobler telefonen hans til verkstedet ditt. Den virker én gang og bare de neste ti minuttene, så gjør det mens han er her.",
+    "memberDetailsTitle": "E-postadressen hans",
+    "memberDetailsBlurb": "Han får en e-post med en lenke. Når han åpner den, velger han sitt eget passord og dukker deretter opp i listen over.",
+    "roleHint": "Administratorer kan endre innstillinger og legge til folk. Alle andre gjør det daglige arbeidet.",
+    "stepBack": "Tilbake",
+    "stepHandoffDone": "Han har skannet den",
+    "stepDoneTitle": "{name} er klar",
+    "stepDoneBody": "Han kan åpne appen og se jobbene sine. Neste gang logger han inn med bare mobilnummeret, uten kode.",
+    "stepInvitedTitle": "Invitasjon sendt til {email}",
+    "stepInvitedBody": "Han dukker opp i listen så snart han har åpnet e-posten og takket ja. Lenken virker i sju dager.",
+    "stepDoneAnother": "Legg til en til",
+    "clashTitle": "{name} har allerede det nummeret",
+    "clashBlurb": "To personer kan ikke dele et mobilnummer, siden det er det de logger inn med. Hvilket av disse er det?",
+    "clashSamePerson": "Dette er {name}",
+    "clashSamePersonHint": "Samme person som kommer tilbake, eller et navn stavet annerledes. Jobbene og timene følger dem, og navnet du nettopp skrev erstatter det gamle.",
+    "clashTakeover": "Nei, dette er {name}",
+    "clashTakeoverHint": "En annen person som nå har det nummeret. {name} beholder alt de har gjort her, men kan ikke lenger logge inn, og du kan gi dem et nytt nummer senere.",
+    "clashDifferentNumber": "Ingen av delene, la meg endre nummeret",
+    "workshopCountry": "Hvilket land ligger verkstedet i?",
+    "workshopCountryPlaceholder": "Velg land",
+    "workshopCountryHint": "Spørres bare én gang. Etter dette kan mobilnumre skrives kort. Du kan endre det senere under <link>Språkinnstillinger</link>.",
+    "phonePreview": "Lagres som",
+    "stepScannedTitle": "{name} er inne",
+    "countrySearch": "Søk etter land",
+    "countryNoMatch": "Ingen land passer",
+    "choiceStandalone": "Bare et navn på tavlen",
+    "choiceStandaloneHint": "En lærling, en innleid, alle du planlegger inn men som aldri logger inn. Ingen telefon, ingen e-post, ingen konto. Du kan gi dem det senere.",
+    "standaloneDetailsTitle": "Navn og farge",
+    "standaloneDetailsBlurb": "Dette er alt de får, og alt de trenger. De vises på tavlen og på jobber, og har ingenting å logge inn på.",
+    "boardColour": "Farge på tavlen",
+    "stepStandaloneTitle": "{name} er på tavlen",
+    "stepStandaloneBody": "Du kan planlegge dem og sette dem på jobber med en gang. Trenger de appen senere, legger du til et mobilnummer herfra.",
+    "boardOnly": "Bare på tavlen",
+    "boardOnlyHint": "Planlegges og settes på jobber, men logger aldri inn. Gi dem et mobilnummer når de trenger appen.",
+    "boardOnlyNoAccount": "Ingen konto",
+    "giveApp": "Gi dem appen",
+    "giveAppTitle": "Gi {name} appen",
+    "giveAppBlurb": "Det eneste som mangler er et mobilnummer. Med det logger de inn fra nå av.",
+    "giveAppKeepsHistory": "Alt som allerede er ført på dem blir stående.",
+    "giveAppSubmit": "Opprett kontoen",
+    "role": "Rolle",
+    "inviteMemberHint": "Personen får en e-post og velger sitt eget passord.",
+    "removeBoardOnlyTitle": "Ta {name} av tavlen?",
+    "removeBoardOnlyBody": "{name} vises ikke lenger på arbeidstavlen og kan ikke settes på jobber. Arbeid som allerede er registrert på dem, og timene de har stemplet, blir stående nøyaktig som de er.",
+    "removeBoardOnlyDone": "{name} er tatt av tavlen",
+    "noRole": "Ingen rolle",
+    "worksOnJobs": "Jobber på biler",
+    "createDefaultRoles": "Opprett standardrollene",
+    "defaultRolesCreated": "Standardroller opprettet",
+    "noRolesYet": "Dette verkstedet har ingen roller ennå, så det finnes ingenting å gi dem utover Admin. Opprett standardrollene og juster tillatelsene senere.",
+    "noRoleDescription": "Ingen tillatelser i det hele tatt. De kan logge inn, men hver skjerm avviser dem til du gir dem en rolle nedenfor.",
+    "cannotUseApp": "Rollen deres kan ikke jobbe på jobber. Gi dem Tekniker, eller en rolle med de samme tillatelsene, først.",
+    "revokeTechnicianDone": "{name} er logget ut av appen",
+    "noAccessTitle": "Ingen tilgang ennå",
+    "noAccessBody": "Kontoen din tilhører {workshop}, men den har ikke fått en rolle ennå, så det er ingenting her du kan åpne. Be en eier eller administrator på verkstedet om å gi deg en.",
+    "setupPageInstall": "Last ned fra Google Play"
   },
   "invoice": {
     "title": "Faktura og tilbud",
@@ -448,13 +555,34 @@
     "customerNumbersAssigned": "Tildelte numre til {count} kunder",
     "allCustomersNumbered": "Alle kunder har et nummer.",
     "assignCustomerNumbersConfirmTitle": "Tildele kundenumre?",
-    "assignCustomerNumbersConfirmDescription": "De {count} kundene uten nummer får fortløpende numre i opprettelsesrekkefølge, fortsettende etter det høyeste eksisterende nummeret. Kunder som allerede har nummer endres ikke. Numrene kan redigeres etterpå."
+    "assignCustomerNumbersConfirmDescription": "De {count} kundene uten nummer får fortløpende numre i opprettelsesrekkefølge, fortsettende etter det høyeste eksisterende nummeret. Kunder som allerede har nummer endres ikke. Numrene kan redigeres etterpå.",
+    "layoutColorsHint": "Farger, skrifter og brevhodestilen ligger under Maler.",
+    "goToTemplates": "Åpne Maler",
+    "lockTitle": "Låsing av ferdige dokumenter",
+    "lockDescription": "Hindre at en faktura eller et tilbud endres etter at det er gjort opp.",
+    "lockWhatItDoes": "Dette låses: deler, arbeid, antall, priser, rabatt, avgift, dokumentnummer og dato. Sletting av dokumentet blokkeres også.",
+    "lockWhatItAllows": "Dette virker fortsatt: registrere betalinger, kortbetaling på nett, statusendringer, sending og ny sending, vedlegg og interne notater. En låst faktura kan alltid betales.",
+    "lockUnlockNote": "Eiere og administratorer kan låse opp ett enkelt dokument fra dokumentets egen side når noe virkelig må rettes. Hver opplåsing loggføres.",
+    "lockInvoicesLabel": "Lås fakturaer",
+    "lockTriggerSent": "Når fakturaen er sendt",
+    "lockTriggerPaid": "Når fakturaen er betalt i sin helhet",
+    "lockTriggerSentHint": "Låses så snart fakturaen sendes på e-post eller det opprettes en delingslenke. Fakturaer sendt før du slo dette på berøres ikke.",
+    "lockTriggerPaidHint": "Låses når hele beløpet er gjort opp, eller fakturaen merkes betalt manuelt. Delvis betalte fakturaer kan fortsatt endres.",
+    "lockQuotesLabel": "Lås tilbud",
+    "quoteLockTriggerSent": "Når tilbudet er sendt",
+    "quoteLockTriggerAccepted": "Når tilbudet er akseptert",
+    "quoteLockTriggerSentHint": "Låses så snart tilbudet går til kunden. Velg dette bare hvis du aldri endrer et tilbud underveis i forhandlingen.",
+    "quoteLockTriggerAcceptedHint": "Låses når kunden har akseptert tilbudet, eller det er gjort om til en jobb. Sendte tilbud kan fortsatt endres."
   },
   "layoutEditor": {
     "helpText": "Dra for å sortere. Bruk bredde-veksler for å plassere seksjoner side om side. Påfølgende halvbredde-seksjoner (V/H) vises i to kolonner.",
     "addField": "Legg til felt",
     "custom": "egendefinert",
     "full": "Full",
+    "boxed": "Ramme",
+    "plain": "Uten",
+    "boxedHint": "Skrives ut i en ramme",
+    "plainHint": "Skrives ut uten ramme",
     "L": "V",
     "R": "H",
     "left": "venstre",
@@ -463,15 +591,20 @@
     "fullWidthHint": "Full bredde — klikk for halvbredde (venstre)",
     "sections": {
       "header": "Topptekst",
+      "slogan": "Slagord",
       "customer": "Kunde",
       "vehicle": "Kjøretøy",
       "service": "Tjeneste",
+      "document_title": "Dokumenttittel",
+      "items_table": "Posttabell",
       "parts_table": "Deler",
       "labor_table": "Arbeid",
       "totals": "Totaler",
       "notes": "Notater",
+      "attached_documents": "Vedlagte dokumenter",
       "diagnostic_notes": "Diagnostiske notater",
       "findings": "Observasjoner",
+      "warranty": "Garanti",
       "bank_account": "Bankkonto",
       "footer": "Bunntekst",
       "general": "Generelt",
@@ -493,12 +626,59 @@
       "tech_name": "Tekniker",
       "logo": "Logo",
       "company_name": "Firmanavn",
+      "company_slogan": "Slagord",
       "company_address": "Adresse",
       "company_phone": "Telefon",
       "company_email": "E-post",
       "company_org_number": "Organisasjonsnummer",
       "bank_account": "Bankkonto",
-      "org_number": "Organisasjonsnummer"
+      "footer_note": "Bunntekstnotat",
+      "org_number": "Organisasjonsnummer",
+      "portal_link": "Portallenke"
+    },
+    "presetsTitle": "Start fra et oppsett",
+    "presetsHint": "Erstatter oppsettet under. Ingenting lagres før du lagrer.",
+    "presets": {
+      "classic": {
+        "name": "Klassisk",
+        "description": "Deler og arbeid i hver sin tabell, opplysninger stablet til venstre"
+      },
+      "letterhead": {
+        "name": "Brevhode",
+        "description": "Kontaktinfo nederst, tittel under adressene"
+      },
+      "compact": {
+        "name": "Kompakt",
+        "description": "Uten rammer, bare det nødvendige"
+      },
+      "minimal": {
+        "name": "Minimal",
+        "description": "Ren typografi på hvitt: ingen bokser, ingen bånd, bare streker og luft"
+      },
+      "itemized": {
+        "name": "Spesifisert",
+        "description": "Én nummerert liste med egen kolonne for enhet"
+      },
+      "detailed": {
+        "name": "Detaljert",
+        "description": "Tittel øverst, kjøretøyet for seg, begge tabeller og alle valgfrie blokker"
+      }
+    },
+    "style": {
+      "documentTitle": "Hele arket",
+      "documentHint": "størrelse, avstand, aksent, striper",
+      "textColor": "Tekst",
+      "labelColor": "Overskrift",
+      "backgroundColor": "Fyll",
+      "borderColor": "Ramme",
+      "fontSize": "Størrelse",
+      "rowPadding": "Radhøyde",
+      "margin": "Marg",
+      "accentColor": "Aksent",
+      "stripeColor": "Stripe",
+      "stripes": "Striper",
+      "fontFamily": "Skrift",
+      "fontInherit": "Arv"
     }
   },
   "templates": {
@@ -515,6 +695,19 @@
     },
     "presets": "Malforhåndsvisninger",
     "primaryColor": "Primærfarge",
+    "colors": "Farger",
+    "textColor": "Tekst",
+    "textColorHint": "Fargen på overskrifter og brødtekst",
+    "companyTextColor": "Firmanavn",
+    "companyTextColorHint": "Fargen på navnet i brevhodet",
+    "frameBorderColor": "Rammelinje",
+    "frameBorderColorHint": "Linjen der rammen møter papiret",
+    "frameShadow": "Rammeskygge",
+    "frameShadowOn": "Skygge",
+    "frameShadowOff": "Flat",
+    "backgroundColor": "Bakgrunn",
+    "backgroundColorClear": "Nullstill",
+    "backgroundColorHint": "La stå tomt for hvitt papir. En lys tone skrives ut som et tonet ark.",
     "fontAndLayout": "Skrift og layout",
     "fontFamily": "Skriftfamilie",
     "helveticaDefault": "Helvetica (Standard)",
@@ -525,6 +718,10 @@
     "standard": "Standard",
     "compact": "Kompakt",
     "modern": "Moderne",
+    "framed": "Innrammet",
+    "letterheadMark": "Brevhode",
+    "letterheadLogo": "Logo",
+    "letterheadCompanyName": "Firmanavn",
     "preview": "{name} forhåndsvisning",
     "billTo": "Faktureres til",
     "preparedFor": "Utarbeidet for",
@@ -594,7 +791,11 @@
       "slate": "Skifer",
       "rose": "Rosa",
       "indigo": "Indigo"
-    }
+    },
+    "goToLayout": "Oppsett og seksjoner",
+    "openDesigner": "Åpne designeren",
+    "designerIntro": "Velg et utgangspunkt, og åpne designeren for å endre alt.",
+    "designerHint": "Farger, skrifter, avstander og alle seksjoner ligger i designeren."
   },
   "payment": {
     "readMore": "Les mer",
@@ -739,6 +940,7 @@
       "NGN": "Nigerianske naira",
       "KES": "Kenyansk shilling",
       "MAD": "Marokkansk dirham",
+      "DZD": "Algerisk dinar",
       "GHS": "Ghanesisk cedi",
       "QAR": "Qatarske riyal",
       "KWD": "Kuwaitiske dinar",
@@ -805,7 +1007,16 @@
     "failedSave": "Kunne ikke lagre felt",
     "failedDelete": "Kunne ikke slette",
     "edit": "Edit",
-    "delete": "Delete"
+    "delete": "Delete",
+    "unassigned": "Ikke plassert",
+    "defaultValue": "Standardverdi",
+    "defaultValueHint": "Fylles ut automatisk på nye oppføringer og skrives ut så lenge ingen verdi er angitt.",
+    "defaultValueNone": "Ingen",
+    "defaultValueCheckedHint": "Avkrysset som standard",
+    "placement": "Plassering på dokumentet",
+    "placementHidden": "Skrives ikke ut",
+    "placementHint": "Hvilken del av fakturaen eller tilbudet dette feltet skrives ut i. I designeren kan du også slå det på i flere seksjoner.",
+    "failedSavePlacement": "Kunne ikke lagre feltplasseringen"
   },
   "workshop": {
     "title": "Verkstedstandarder",
@@ -1449,6 +1660,15 @@
       "checkFailed": "Sjekken mislyktes",
       "configurePerPart": "Sett delens min. antall på lagersiden →",
       "readMore": "Les mer"
+    },
+    "technicianStatus": {
+      "title": "Torqvoice teknikerapp (Android/iOS)",
+      "description": "Varsel når en tekniker endrer en jobb fra telefonen.",
+      "inApp": "Varsle kontoret",
+      "inAppHint": "Et varsel når en jobb er ferdig, venter på deler eller tas opp igjen.",
+      "save": "Lagre",
+      "saved": "Varselinnstillinger lagret",
+      "saveFailed": "Kunne ikke lagre innstillingene"
     }
   },
   "support": {
@@ -1521,5 +1741,206 @@
         "description": "Send og motta Telegram-meldinger med kundene dine rett fra Torqvoice."
       }
     }
+  },
+  "designer": {
+    "invoice": "Faktura",
+    "quote": "Tilbud",
+    "eyebrow": "Dokumentdesigner",
+    "galleryTitle": "Start fra en mal",
+    "galleryHint": "Velg et utgangspunkt. Du kan endre alt i designeren.",
+    "yourDesigns": "Dine design",
+    "templates": "Maler",
+    "inUse": "I bruk",
+    "savedOn": "Lagret {date}",
+    "deleteDesignTitle": "Slett design",
+    "deleteDesignBody": "Slette designet «{name}»? Fakturaen og tilbudet beholder det som er tatt i bruk; bare den lagrede kopien forsvinner.",
+    "delete": "Slett",
+    "deleteDesign": "Slett dette designet",
+    "continueCurrent": "Fortsett med oppsettet mitt",
+    "backToSettings": "Tilbake til innstillinger",
+    "useInvoiceDesign": "Bruk fakturadesignet",
+    "copiedToQuote": "Fakturadesignet er kopiert til tilbudet",
+    "rulers": "Linjaler",
+    "saveDesign": "Lagre design",
+    "saveDesignHint": "Ta vare på en navngitt kopi av dette designet, slik at du finner det igjen i malgalleriet",
+    "reset": "Nullstill",
+    "save": "Lagre",
+    "saving": "Lagrer…",
+    "saved": "Lagret",
+    "couldNotSave": "Kunne ikke lagre",
+    "couldNotSaveDesigns": "Kunne ikke lagre designene dine",
+    "designUpdated": "Oppdaterte «{name}»",
+    "designSaved": "Lagret som «{name}»",
+    "defaultDesignName": "Mitt {doc}design",
+    "documentStyling": "Dokumentstil",
+    "sections": "Seksjoner",
+    "sectionEmpty": "tom",
+    "sectionEmptyHint": "Vises, men det er ingenting å skrive ut i den med dagens data.",
+    "sectionShownHint": "Vises på arket. Klikk for å skjule den.",
+    "sectionHiddenHint": "Skjult fra arket. Klikk for å vise den.",
+    "railHint": "Dra en seksjon på siden: slipp den mellom blokker for å endre rekkefølge, på et kort for å ligge ved siden av det, eller hvor som helst ellers for å plassere den fritt. Siden gir plass rundt den.",
+    "returnToFlow": "Sett {section} tilbake i flyten",
+    "saveDialogTitle": "Lagre dette designet",
+    "saveDialogBody": "Tar vare på en navngitt kopi av dagens oppsett og utseende. Du finner den igjen under Dine design i malgalleriet.",
+    "designNamePlaceholder": "Navn på design",
+    "nameExists": "Et design med dette navnet finnes; lagring oppdaterer det.",
+    "updateDesign": "Oppdater design",
+    "cancel": "Avbryt",
+    "insertHere": "Sett inn her",
+    "dropLeftColumn": "Venstre kolonne",
+    "dropRightColumn": "Høyre kolonne",
+    "freePosition": "Fri plassering",
+    "sectionSettings": "Seksjonsinnstillinger",
+    "panelStyle": "Panelstil",
+    "variant": {
+      "accent": "Aksent",
+      "panel": "Panel",
+      "outline": "Kontur",
+      "lines": "Linjer",
+      "hint": "Aksent toner kortet med primærfargen. Panel matcher de andre detaljkortene. Kontur tegner bare en ramme, og Linjer skriver ut uten boks.",
+      "classic": "Klassisk",
+      "box": "Ramme",
+      "totalsHint": "Klassisk skriver ut rene linjer med en strek over totalen. Ramme setter en ramme rundt dem. Panel og Aksent setter dem på et kort."
+    },
+    "alignment": "Justering",
+    "alignCenter": "Midt",
+    "itemsTableHint": "Én nummerert liste over alle linjene i jobben, arbeid først og deler etterpå, i stedet for de separate tabellene.",
+    "discardChanges": "Forkast endringer",
+    "tablesExclusiveHint": "Arket skriver ut én ordning: én nummerert liste, eller separate tabeller for deler og arbeid. Slår du på den ene, slås den andre av.",
+    "innerPadding": "Innvendig avstand",
+    "totalsWidth": "Bredde",
+    "totalsWidthHint": "Tom fyller hele raden. En verdi i punkter henger boksen til høyre; i en kolonne tar den kolonnens bredde.",
+    "placement": "Plassering",
+    "visible": "Synlig",
+    "columnFull": "Full",
+    "columnLeft": "Venstre",
+    "columnRight": "Høyre",
+    "drawBox": "Tegn en boks",
+    "showHeading": "Vis overskrift",
+    "spacing": "Avstand",
+    "placedByHand": "Denne seksjonen er plassert for hånd, så avstand i flyten flytter den ikke.",
+    "placedByHandFramed": "Den innrammede brevhodet ligger på båndet; dra det for å flytte det.",
+    "placedByHandDrag": "Dra den, eller sett den tilbake i flyten, for å bruke avstand.",
+    "marginTop": "Topp",
+    "marginBottom": "Bunn",
+    "marginLeft": "Venstre",
+    "marginRight": "Høyre",
+    "spacingHint": "Punkter med tomrom seksjonen holder rundt seg i flyten.",
+    "logo": "Logo",
+    "size": "Størrelse",
+    "logoHint": "Slå av logoen under Felter for å skrive ut firmanavnet i stedet.",
+    "fields": "Felter",
+    "removeField": "Fjern fra denne seksjonen",
+    "yourCustomFields": "Dine egendefinerte felter",
+    "appearance": "Utseende",
+    "details": "Detaljer",
+    "text": "Tekst",
+    "companyName": "Firmanavn",
+    "heading": "Overskrift",
+    "fill": "Fyll",
+    "border": "Ramme",
+    "lineWidth": "Linjebredde",
+    "borderWidth": "Rammebredde",
+    "outerBorder": "Ytre ramme",
+    "rowBanding": "Radstriper",
+    "likeSheet": "Som arket",
+    "on": "På",
+    "off": "Av",
+    "font": "Skrift",
+    "inherit": "Arv",
+    "auto": "auto",
+    "sectionDragHint": "Dra denne seksjonen i listen, eller på siden, for å flytte den. Når den er plassert for hånd, flytter piltastene den ett punkt om gangen, ti med Shift, og Escape avbryter et dra.",
+    "document": "Dokument",
+    "documentSubtitle": "Gjelder hele arket",
+    "headerStyleTitle": "Topptekststil",
+    "headerStyle": {
+      "standard": {
+        "name": "Standard",
+        "desc": "Navn og detaljer på hvitt, med strek under"
+      },
+      "compact": {
+        "name": "Kompakt",
+        "desc": "Stram topp, tette rader"
+      },
+      "modern": {
+        "name": "Moderne",
+        "desc": "Farget banner i full bredde"
+      },
+      "framed": {
+        "name": "Innrammet",
+        "desc": "Bånd over toppen, stripe ned venstre side"
+      }
+    },
+    "colors": "Farger",
+    "primary": "Primær",
+    "background": "Bakgrunn",
+    "accent": "Aksent",
+    "frame": "Ramme",
+    "rail": "Stripe",
+    "leftEdge": "Venstre kant",
+    "rightEdge": "Høyre kant",
+    "frameLine": "Rammelinje",
+    "cornerRadius": "Hjørneradius",
+    "shadow": "Skygge",
+    "shadowThin": "Tynn",
+    "shadowNormal": "Normal",
+    "shadowWide": "Bred",
+    "typography": "Typografi",
+    "baseSize": "Grunnstørrelse",
+    "page": "Side",
+    "margins": "Marger",
+    "rowHeight": "Radhøyde",
+    "band": "Stripe",
+    "sample": {
+      "itemLabor": "Bremser foran skiftet",
+      "itemDisc": "Bremseskive, foran",
+      "itemPads": "Bremseklosser, foraksel",
+      "itemConsumables": "Forbruksmateriell",
+      "unitPcs": "stk",
+      "unitSet": "sett",
+      "unitEach": "x",
+      "findingPads": "Bakre klosser på 15 %",
+      "findingPadsNote": "Skiftes innen 5 000 km",
+      "findingOilWeep": "Liten oljelekkasje ved ventildeksel",
+      "notes": "Takk for at du valgte verkstedet vårt. Ta kontakt hvis du har spørsmål.",
+      "warranty": "12 måneders garanti på deler og arbeid.",
+      "serviceTitle": "Årsservice og bremser",
+      "serviceType": "Reparasjon",
+      "companyName": "Ditt verksted",
+      "slogan": "Kvalitetsservice du kan stole på",
+      "footerNote": "Takk for handelen",
+      "value": "Eksempel"
+    },
+    "logoUpload": "Last opp logo",
+    "logoReplace": "Bytt logo",
+    "logoUploading": "Laster opp…",
+    "logoFailed": "Kunne ikke laste opp bildet",
+    "footerLogoHint": "Slå på logoen under Felter for å skrive den ut nederst på siden også.",
+    "logoReset": "Bruk firmalogoen",
+    "logoOwn": "Skrives bare ut på dette dokumentet. Firmalogoen er uendret.",
+    "logoInherited": "Bruker firmalogoen. Last opp en her for å bruke en annen logo bare på dette dokumentet.",
+    "slogan": "Slagord",
+    "sloganPlaceholderHint": "Det er ikke satt noe slagord, så arket viser en plassholder som ikke skrives ut.",
+    "sloganSetHint": "Slagordet hentes fra firmaopplysningene dine.",
+    "sloganLink": "Firmainnstillinger",
+    "placeholder": "Plassholder",
+    "leaveTitle": "Forlate uten å lagre?",
+    "leaveBody": "Endringene i dette designet er ikke lagret. De går tapt.",
+    "leaveConfirm": "Forlat",
+    "boldField": "Fet"
+  },
+  "preview": {
+    "title": "Bremseservice og oljeskift",
+    "serviceType": "Vedlikehold",
+    "findingPads": "Bakre bremseklosser slitt til 15 %",
+    "findingPadsNote": "Anbefaler bytte innen 8 000 km",
+    "findingOilLeak": "Liten oljelekkasje ved ventildekselpakning",
+    "invoiceNotes": "Fremre bremseklosser er skiftet. Olje og filter byttet med syntetisk 5W-30. Neste service anbefales ved 80 000 km.",
+    "quoteNotes": "Bytte av fremre bremseklosser anbefales. Olje- og filterskift med syntetisk 5W-30.",
+    "partBrakePads": "Bremseklosser (foran)",
+    "partOilFilter": "Oljefilter",
+    "partSyntheticOil": "Syntetisk olje 5W-30",
+    "laborBrakeReplacement": "Bremseskift",
+    "laborOilChange": "Oljeskift"
   }
 }

+ 4 - 2
messages/nb/share.json

@@ -71,7 +71,8 @@
     "findingSeverityUrgent": "Høy",
     "findingSeverityNeedsWork": "Middels",
     "findingSeverityMonitor": "Lav",
-    "tel": "Tlf: {phone}"
+    "tel": "Tlf: {phone}",
+    "customFields": "Tilleggsinformasjon"
   },
   "quote": {
     "title": "Tilbud",
@@ -125,7 +126,8 @@
       "converted": "Konvertert",
       "changes_requested": "Endringer forespurt"
     },
-    "tel": "Tlf: {phone}"
+    "tel": "Tlf: {phone}",
+    "customFields": "Tilleggsinformasjon"
   },
   "inspection": {
     "title": "Kjøretøykontroll",

+ 2 - 1
messages/nb/tireHotel.json

@@ -464,7 +464,8 @@
     "none": "Ingenting lagt ved ennå. Ta bilde av en skadet felg mens dekkene står foran deg.",
     "captionPlaceholder": "Hva viser dette?",
     "onInvoice": "På fakturaen",
-    "invoiceHint": "Filer merket for faktura kopieres til arbeidsordren eller fakturaen når settet faktureres.",
+    "invoiceHint": "Bilder merket for faktura kopieres til arbeidsordren eller fakturaen når settet faktureres. Dokumenter blir liggende her på settet.",
+    "documentStays": "Blir på settet, kopieres ikke til fakturaer",
     "deleteTitle": "Fjerne denne filen?",
     "deleteBody": "{name} fjernes fra settet. Det som allerede er kopiert til en faktura, blir stående.",
     "failed": "Kunne ikke lagre",

+ 3 - 1
messages/nb/vehicles.json

@@ -259,7 +259,9 @@
     "previousPage": "Previous page",
     "nextPage": "Next page",
     "lastPage": "Last page",
-    "openMenu": "Open menu"
+    "openMenu": "Open menu",
+    "concernLabel": "Svarer på hvilket punkt?",
+    "concernNone": "Ikke noe kunden spurte om"
   },
   "observationsPage": {
     "searchPlaceholder": "Søk i beskrivelse, notater eller kjøretøy...",

+ 4 - 1
messages/nb/workBoard.json

@@ -75,7 +75,10 @@
     "standalone": "Uavhengig tekniker",
     "deleteTitle": "Slett tekniker",
     "deleteDescription": "Fjern \"{name}\" fra arbeidstavlen? Deres eksisterende tilordninger vil også bli fjernet.",
-    "addTechnician": "Legg til tekniker"
+    "addTechnician": "Legg til tekniker",
+    "standaloneOnly": "Et navn på tavlen for noen som ikke logger inn, for eksempel en lærling eller innleid. En mekaniker som bruker appen legger du til på Team-siden.",
+    "linkedTo": "Logger inn som {name}",
+    "linkedManagedOnTeam": "Styres fra Team-siden, sammen med apptilgangen."
   },
   "jobDetail": {
     "viewDetails": "Vis detaljer",

+ 12 - 2
messages/nl/audit.json

@@ -140,9 +140,18 @@
     "work_bay_create": "Werkplek aangemaakt",
     "work_bay_update": "Werkplek bijgewerkt",
     "work_bay_delete": "Werkplek verwijderd",
+    "auth_appSetupRedeemed": "Ingelogd met installatiecode",
+    "auth_technicianCodeSignIn": "Ingelogd met eenmalige code",
+    "team_createAppSetupCode": "Installatiecode voor de app uitgegeven",
+    "team_createTechnicianAccount": "Monteursaccount aangemaakt",
+    "team_removeTechnicianAccess": "Monteur verwijderd en toegang ingetrokken",
+    "team_setMemberTechnician": "Gewijzigd of een lid monteur is",
     "settings_whatsappUpdated": "WhatsApp-instellingen bijgewerkt",
+    "settings_whatsappDisconnected": "WhatsApp losgekoppeld",
     "settings_whatsappNumberRegistered": "WhatsApp-nummer geregistreerd",
-    "settings_whatsappDisconnected": "WhatsApp losgekoppeld"
+    "team_giveTechnicianTheApp": "Bordmonteur een account gegeven",
+    "team_createDefaultRoles": "Standaardrollen aangemaakt",
+    "settings_setCustomFieldPlacement": "Plaatsing van aangepast veld bijgewerkt"
   },
   "summary": {
     "customField_create": "Aangepast veld \"{name}\" aangemaakt",
@@ -265,6 +274,7 @@
     "whatsapp_send": "WhatsApp-bericht verzonden naar {name}",
     "work_bay_create": "Werkplek \"{name}\" aangemaakt",
     "work_bay_update": "Werkplek \"{name}\" bijgewerkt",
-    "work_bay_delete": "Werkplek {id} verwijderd"
+    "work_bay_delete": "Werkplek {id} verwijderd",
+    "settings_setCustomFieldPlacement": "Wijzigde waar een aangepast veld wordt afgedrukt"
   }
 }

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