diff --git a/apps/web/src/messages/de.json b/apps/web/src/messages/de.json index 0c74903..0e47de6 100644 --- a/apps/web/src/messages/de.json +++ b/apps/web/src/messages/de.json @@ -6,10 +6,10 @@ "cancel": "Abbrechen", "menu": "Menu", "confirm": "Bestaetigen", - "delete": "Loeschen", + "delete": "Löschen", "edit": "Bearbeiten", "create": "Erstellen", - "close": "Schliessen", + "close": "Schließen", "yes": "Ja", "no": "Nein", "active": "Aktiv", @@ -28,40 +28,40 @@ "submit": "Anmelden", "forgotPassword": "Passwort vergessen?", "error": { - "invalidCredentials": "Benutzername oder Passwort ungueltig", + "invalidCredentials": "Benutzername oder Passwort ungültig", "networkError": "Verbindungsfehler. Bitte versuchen Sie es erneut." }, "branding": { - "tagline": "Modulare Workflow-Plattform fuer Ihr Unternehmen" + "tagline": "Modulare Workflow-Plattform für Ihr Unternehmen" }, "resetPassword": { - "title": "Passwort zuruecksetzen", + "title": "Passwort zurücksetzen", "email": "E-Mail-Adresse", "submit": "Link senden", - "success": "Falls ein Konto mit dieser E-Mail existiert, wurde ein Link zum Zuruecksetzen gesendet.", - "backToLogin": "Zurueck zur Anmeldung", + "success": "Falls ein Konto mit dieser E-Mail existiert, wurde ein Link zum Zurücksetzen gesendet.", + "backToLogin": "Zurück zur Anmeldung", "newPasswordTitle": "Neues Passwort festlegen", "newPassword": "Neues Passwort", - "confirmPassword": "Passwort bestaetigen", - "submitReset": "Passwort zuruecksetzen", - "resetSuccess": "Ihr Passwort wurde erfolgreich zurueckgesetzt.", + "confirmPassword": "Passwort bestätigen", + "submitReset": "Passwort zurücksetzen", + "resetSuccess": "Ihr Passwort wurde erfolgreich zurückgesetzt.", "redirecting": "Sie werden in wenigen Sekunden zur Anmeldung weitergeleitet...", - "tokenExpired": "Der Link zum Zuruecksetzen ist abgelaufen. Bitte fordern Sie einen neuen an.", + "tokenExpired": "Der Link zum Zurücksetzen ist abgelaufen. Bitte fordern Sie einen neuen an.", "tokenUsed": "Dieser Link wurde bereits verwendet. Bitte fordern Sie einen neuen an.", - "tokenInvalid": "Der Link zum Zuruecksetzen ist ungueltig.", - "passwordMismatch": "Die Passwoerter stimmen nicht ueberein." + "tokenInvalid": "Der Link zum Zurücksetzen ist ungültig.", + "passwordMismatch": "Die Passwörter stimmen nicht überein." }, "changePassword": { - "title": "Passwort aendern", + "title": "Passwort ändern", "currentPassword": "Aktuelles Passwort", "newPassword": "Neues Passwort", - "confirmPassword": "Neues Passwort bestaetigen", - "submit": "Passwort aendern", - "success": "Ihr Passwort wurde erfolgreich geaendert.", - "forceChangeNotice": "Aus Sicherheitsgruenden muessen Sie Ihr Passwort aendern, bevor Sie fortfahren koennen.", + "confirmPassword": "Neues Passwort bestätigen", + "submit": "Passwort ändern", + "success": "Ihr Passwort wurde erfolgreich geändert.", + "forceChangeNotice": "Aus Sicherheitsgründen müssen Sie Ihr Passwort ändern, bevor Sie fortfahren können.", "wrongCurrentPassword": "Das aktuelle Passwort ist falsch.", "networkError": "Verbindungsfehler. Bitte versuchen Sie es erneut.", - "passwordMismatch": "Die Passwoerter stimmen nicht ueberein." + "passwordMismatch": "Die Passwörter stimmen nicht überein." } }, "header": { @@ -109,12 +109,12 @@ "dashboard": { "title": "Dashboard", "empty": "Keine Widgets aktiv", - "addWidget": "Widget hinzufuegen" + "addWidget": "Widget hinzufügen" }, "settings": { "link": "Einstellungen", "navLabel": "Einstellungen", - "backToDashboard": "Zurueck zum Dashboard", + "backToDashboard": "Zurück zum Dashboard", "categoryDashboard": "Dashboard", "categoryWidgets": "Widgets", "categoryCalendar": "Kalender", @@ -124,32 +124,32 @@ "account": { "title": "Konto", "avatarLabel": "Profilbild", - "avatarHelp": "Erlaubte Formate: PNG, JPEG, WebP. Maximale Groesse: 2 MB.", + "avatarHelp": "Erlaubte Formate: PNG, JPEG, WebP. Maximale Größe: 2 MB.", "uploadCta": "Bild hochladen", "uploadSuccess": "Profilbild wurde erfolgreich aktualisiert.", - "uploadError": "Hochladen fehlgeschlagen. Bitte pruefen Sie das Dateiformat und die Dateigröße.", - "ldapManagedNotice": "Ihr Passwort wird ueber das Verzeichnis (LDAP) verwaltet. Eine Aenderung ist hier nicht moeglich.", - "passwordSectionTitle": "Passwort aendern", + "uploadError": "Hochladen fehlgeschlagen. Bitte prüfen Sie das Dateiformat und die Dateigröße.", + "ldapManagedNotice": "Ihr Passwort wird über das Verzeichnis (LDAP) verwaltet. Eine Aenderung ist hier nicht möglich.", + "passwordSectionTitle": "Passwort ändern", "accentColorLabel": "Akzentfarbe", - "accentColorHelp": "Passt die Hauptfarbe der Oberflaeche an.", - "accentColorReset": "Zuruecksetzen", + "accentColorHelp": "Passt die Hauptfarbe der Oberfläche an.", + "accentColorReset": "Zurücksetzen", "accentColorSave": "Farbe speichern", "accentColorSuccess": "Akzentfarbe erfolgreich gespeichert.", "accentColorError": "Speichern fehlgeschlagen.", - "deleteAvatarCta": "Bild loeschen", - "deleteAvatarSuccess": "Profilbild erfolgreich geloescht.", - "deleteAvatarError": "Loeschen fehlgeschlagen." + "deleteAvatarCta": "Bild löschen", + "deleteAvatarSuccess": "Profilbild erfolgreich gelöscht.", + "deleteAvatarError": "Löschen fehlgeschlagen." }, - "sourceDeleteConfirm": "Moechten Sie diese Kalenderquelle wirklich loeschen?", - "sourceDeleteCta": "Quelle loeschen", - "providerDeleteConfirm": "Moechten Sie diesen Suchanbieter wirklich loeschen?", - "providerDeleteCta": "Anbieter loeschen", + "sourceDeleteConfirm": "Möchten Sie diese Kalenderquelle wirklich löschen?", + "sourceDeleteCta": "Quelle löschen", + "providerDeleteConfirm": "Möchten Sie diesen Suchanbieter wirklich löschen?", + "providerDeleteCta": "Anbieter löschen", "cancel": "Abbrechen", "smtp": { "title": "SMTP-Konfiguration", "host": "Host", "port": "Port", - "encryption": "Verschluesselung", + "encryption": "Verschlüsselung", "username": "Benutzername", "password": "Passwort", "fromAddress": "Absenderadresse (Von)", @@ -168,9 +168,9 @@ }, "widgets": { "emptyHeading": "Keine Widgets aktiv", - "emptyBody": "Klicken Sie auf Bearbeiten, um Widgets hinzuzufuegen.", - "addWidget": "Widget hinzufuegen", - "catalogTitle": "Widget hinzufuegen", + "emptyBody": "Klicken Sie auf Bearbeiten, um Widgets hinzuzufügen.", + "addWidget": "Widget hinzufügen", + "catalogTitle": "Widget hinzufügen", "deleteTooltip": "Widget entfernen", "editMode": "Dashboard bearbeiten", "saveChanges": "Aenderungen speichern", @@ -186,8 +186,8 @@ "description": "Schnellsuche im Web", "placeholder": "Suchen...", "providers": "Suchanbieter", - "addProvider": "Eigenen Suchanbieter hinzufuegen", - "addProviderButton": "Anbieter hinzufuegen" + "addProvider": "Eigenen Suchanbieter hinzufügen", + "addProviderButton": "Anbieter hinzufügen" }, "calendar": { "name": "Kalender", @@ -196,9 +196,9 @@ "emptyNoSources": "Keine Kalenderquellen konfiguriert", "emptyNoEvents": "Keine anstehenden Termine", "connectionSuccess": "Verbindung erfolgreich", - "connectionError": "Verbindung fehlgeschlagen. Bitte ueberpruefen Sie die URL und Zugangsdaten.", - "addSource": "Quelle hinzufuegen", - "sourceEmpty": "Keine Kalenderquellen eingerichtet. Fuegen Sie eine Quelle hinzu, um Termine anzuzeigen." + "connectionError": "Verbindung fehlgeschlagen. Bitte überprüfen Sie die URL und Zugangsdaten.", + "addSource": "Quelle hinzufügen", + "sourceEmpty": "Keine Kalenderquellen eingerichtet. Fügen Sie eine Quelle hinzu, um Termine anzuzeigen." }, "note": { "name": "Notizen", @@ -219,11 +219,11 @@ "empty": "Noch keine Favoriten.", "addTitle": "Titel", "addUrl": "URL", - "addButton": "Hinzufuegen", + "addButton": "Hinzufügen", "listView": "Liste", "gridView": "Kacheln", "editButton": "Favorit bearbeiten", - "deleteButton": "Favorit loeschen", + "deleteButton": "Favorit löschen", "saveButton": "Speichern", "cancelButton": "Abbrechen", "error": "Fehler beim Laden der Favoriten" @@ -235,11 +235,11 @@ "empty": "Noch kein Link gesetzt.", "addTitle": "Titel", "addUrl": "URL", - "addButton": "Hinzufuegen", + "addButton": "Hinzufügen", "listView": "Liste", "gridView": "Kachel", "editButton": "Link bearbeiten", - "deleteButton": "Link loeschen", + "deleteButton": "Link löschen", "saveButton": "Speichern", "cancelButton": "Abbrechen", "error": "Fehler beim Laden des Links" @@ -258,8 +258,8 @@ "title": "Benutzerverwaltung", "create": "Benutzer erstellen", "edit": "Benutzer bearbeiten", - "delete": "Benutzer loeschen", - "deleteConfirm": "Moechten Sie diesen Benutzer wirklich loeschen?", + "delete": "Benutzer löschen", + "deleteConfirm": "Möchten Sie diesen Benutzer wirklich löschen?", "name": "Name", "username": "Benutzername", "email": "E-Mail", @@ -294,8 +294,8 @@ "userCount": "Benutzer", "actions": "Aktionen", "noTenants": "Keine Mandanten gefunden", - "deleteConfirm": "Moechten Sie diesen Mandanten wirklich loeschen?", - "cannotDeleteActive": "Mandanten mit aktiven Benutzern koennen nicht geloescht werden" + "deleteConfirm": "Möchten Sie diesen Mandanten wirklich löschen?", + "cannotDeleteActive": "Mandanten mit aktiven Benutzern können nicht gelöscht werden" }, "ldap": { "title": "LDAP-Konfiguration", @@ -307,8 +307,8 @@ "bindPassword": "Bind-Passwort", "searchFilter": "Suchfilter", "tlsSkip": { - "label": "TLS-Zertifikat nicht pruefen (unsicher)", - "hint": "Nur fuer ldaps:// noetig, wenn das AD-Zertifikat von einer internen/selbstsignierten CA stammt (Fehler: 'unable to verify the first certificate'). Deaktiviert die Zertifikatspruefung - nur in vertrauenswuerdigen Netzen verwenden." + "label": "TLS-Zertifikat nicht prüfen (unsicher)", + "hint": "Nur für ldaps:// nötig, wenn das AD-Zertifikat von einer internen/selbstsignierten CA stammt (Fehler: 'unable to verify the first certificate'). Deaktiviert die Zertifikatsprüfung - nur in vertrauenswürdigen Netzen verwenden." }, "save": "Speichern", "testConnection": "Verbindung testen", @@ -318,7 +318,7 @@ "disable": "Deaktiviert", "fieldMapping": { "title": "Feld-Zuordnung", - "add": "Zuordnung hinzufuegen", + "add": "Zuordnung hinzufügen", "ldapField": "LDAP-Feld", "tesseraField": "Tessera-Feld", "default": "Standard", @@ -340,16 +340,16 @@ }, "groupFilter": { "title": "Import-Filter (Gruppen/OUs)", - "description": "Optionale zusaetzliche Einschraenkung auf ausgewaehlte AD-Gruppen oder Organisationseinheiten. Ohne Auswahl werden alle Benutzer unter den Basis-DN(s) synchronisiert.", + "description": "Optionale zusätzliche Einschränkung auf ausgewählte AD-Gruppen oder Organisationseinheiten. Ohne Auswahl werden alle Benutzer unter den Basis-DN(s) synchronisiert.", "discover": "Gruppen/OUs suchen", "typeOu": "OU", "typeGroup": "Gruppe", "noneFound": "Keine Gruppen oder OUs gefunden.", "searchPlaceholder": "Gruppen/OUs durchsuchen...", - "noMatches": "Keine Treffer fuer diese Suche.", - "manualDn": "DN manuell hinzufuegen", - "addDn": "Hinzufuegen", - "selected": "Ausgewaehlt", + "noMatches": "Keine Treffer für diese Suche.", + "manualDn": "DN manuell hinzufügen", + "addDn": "Hinzufügen", + "selected": "Ausgewählt", "emptyMeansAll": "Keine Auswahl - alle Benutzer unter den Basis-DN(s) werden synchronisiert.", "save": "Filter speichern" }, @@ -369,25 +369,25 @@ "importError": "Der Import konnte nicht ausgeführt werden. Es wurde keine Gruppe angelegt." }, "userExclude": { - "title": "Benutzer ausschliessen (Denylist)", - "description": "Einzelne Benutzernamen, die nie importiert werden - z. B. Dienstkonten wie administrator, krbtgt, guest oder ldap$. Wirkt zusaetzlich zum Gruppen-/OU-Filter.", + "title": "Benutzer ausschließen (Denylist)", + "description": "Einzelne Benutzernamen, die nie importiert werden - z. B. Dienstkonten wie administrator, krbtgt, guest oder ldap$. Wirkt zusätzlich zum Gruppen-/OU-Filter.", "username": "Benutzername", - "add": "Hinzufuegen", + "add": "Hinzufügen", "excluded": "Ausgeschlossen", "empty": "Keine ausgeschlossen - alle gefundenen Benutzer werden importiert.", "save": "Ausschlussliste speichern" }, "userSearch": { "title": "Einzelbenutzer suchen & importieren", - "description": "Sucht einzelne AD-Benutzer und importiert sie gezielt. Bereits vorhandene Benutzer werden uebersprungen - kein Doppelimport, auch wenn spaeter die Abteilung synchronisiert wird.", + "description": "Sucht einzelne AD-Benutzer und importiert sie gezielt. Bereits vorhandene Benutzer werden übersprungen - kein Doppelimport, auch wenn später die Abteilung synchronisiert wird.", "placeholder": "Name, Benutzername oder E-Mail...", "search": "Suchen", "noResults": "Keine Benutzer gefunden.", "alreadyImported": "Bereits importiert", "import": "Importieren", - "importSelected": "Ausgewaehlte importieren", + "importSelected": "Ausgewählte importieren", "created": "importiert", - "skipped": "uebersprungen", + "skipped": "übersprungen", "errors": "Fehler" } }, @@ -439,14 +439,14 @@ }, "adminModules": { "title": "Modulverwaltung", - "description": "Module fuer Ihren Mandanten aktivieren oder deaktivieren", + "description": "Module für Ihren Mandanten aktivieren oder deaktivieren", "activate": "Aktivieren", "deactivate": "Deaktivieren", "activated": "Aktiviert", "deactivated": "Deaktiviert", "system": "System", "version": "Version", - "noModules": "Keine Module verfuegbar", + "noModules": "Keine Module verfügbar", "activateSuccess": "Modul erfolgreich aktiviert", "deactivateSuccess": "Modul erfolgreich deaktiviert", "error": "Fehler bei der Modulverwaltung", @@ -483,9 +483,9 @@ "noModules": "Keine aktiven Module in dieser Kategorie", "notFound": "Modul nicht gefunden", "notFoundDescription": "Das angeforderte Modul existiert nicht oder ist nicht aktiviert.", - "backToCategory": "Zurueck zur Kategorie", + "backToCategory": "Zurück zur Kategorie", "allModules": "Module", - "allModulesDescription": "Verfuegbare Module fuer Ihren Mandanten", + "allModulesDescription": "Verfügbare Module für Ihren Mandanten", "noActiveModules": "Keine Module aktiviert. Bitten Sie Ihren Administrator, Module zu aktivieren.", "accessDenied": { "title": "Kein Zugriff auf dieses Modul", @@ -495,30 +495,30 @@ }, "domaincheck": { "title": "Domaincheck", - "description": "Pruefe ob eine Domain verfuegbar ist", + "description": "Prüfe ob eine Domain verfügbar ist", "inputPlaceholder": "Domain eingeben (z.B. beispiel.de)", "suggestions": "Alternativen", - "checkButton": "Pruefen", - "statusAvailable": "Verfuegbar", + "checkButton": "Prüfen", + "statusAvailable": "Verfügbar", "statusRegistered": "Registriert", - "noResults": "Gib einen Domain-Namen ein um die Verfuegbarkeit zu pruefen", - "checking": "Pruefe...", - "error": "Fehler bei der Pruefung" + "noResults": "Gib einen Domain-Namen ein um die Verfügbarkeit zu prüfen", + "checking": "Prüfe...", + "error": "Fehler bei der Prüfung" }, "dkvFleet": { "pageTitle": "DKV-Rechnung", - "checkNow": "Jetzt pruefen", - "checking": "Wird geprueft...", - "lastChecked": "Zuletzt geprueft: {time} Uhr", - "neverChecked": "Noch nie geprueft", + "checkNow": "Jetzt prüfen", + "checking": "Wird geprüft...", + "lastChecked": "Zuletzt geprüft: {time} Uhr", + "neverChecked": "Noch nie geprüft", "settingsTitle": "Moduleinstellungen", "historyTitle": "Verarbeitungshistorie", "exportFilesTitle": "Letzte Exportdateien", "emptyHistory": "Noch keine Rechnungen verarbeitet", - "emptyHistoryBody": "Klicke auf 'Jetzt pruefen', um den Posteingang zu pruefen. Neue Rechnungen erscheinen hier automatisch.", + "emptyHistoryBody": "Klicke auf 'Jetzt prüfen', um den Posteingang zu prüfen. Neue Rechnungen erscheinen hier automatisch.", "emptyExports": "Noch keine Exportdateien vorhanden", "emptyVehicles": "Keine Fahrzeuge hinterlegt", - "emptyVehiclesBody": "Fuege Fahrzeuge manuell hinzu oder lade eine CSV-Datei hoch.", + "emptyVehiclesBody": "Füge Fahrzeuge manuell hinzu oder lade eine CSV-Datei hoch.", "status": { "processed": "Verarbeitet", "error": "Fehler", @@ -537,19 +537,19 @@ "driver": "Fahrer", "actions": "Aktionen" }, - "addVehicle": "Fahrzeug hinzufuegen", + "addVehicle": "Fahrzeug hinzufügen", "editVehicle": "Fahrzeug bearbeiten", - "deleteVehicle": "Fahrzeug loeschen", - "deleteVehicleBody": "Das Fahrzeug {plate} wird dauerhaft aus der Stammdatenliste entfernt. Diese Aktion kann nicht rueckgaengig gemacht werden.", + "deleteVehicle": "Fahrzeug löschen", + "deleteVehicleBody": "Das Fahrzeug {plate} wird dauerhaft aus der Stammdatenliste entfernt. Diese Aktion kann nicht rückgängig gemacht werden.", "importCsv": "CSV importieren", "csvFormatHelp": "CSV-Format (Semikolon): Kennzeichen;Marke;Modell;Fahrer", "csvFormatExample": "Beispiel: GP-JL 728E;Mercedes;GLC 300;Max Mustermann", "importMode": "Importmodus", - "importMerge": "Zusammenfuehren — neue Fahrzeuge hinzufuegen, vorhandene behalten", - "importReplace": "Ersetzen — alle vorhandenen Fahrzeuge loeschen und neu importieren", + "importMerge": "Zusammenführen — neue Fahrzeuge hinzufügen, vorhandene behalten", + "importReplace": "Ersetzen — alle vorhandenen Fahrzeuge löschen und neu importieren", "importReplaceWarning": "Alle vorhandenen Fahrzeuge werden ersetzt.", "importReplaceConfirmTitle": "Fahrzeuge ersetzen?", - "importReplaceConfirmBody": "Alle vorhandenen Fahrzeuge werden durch die CSV-Daten ersetzt. Diese Aktion kann nicht rueckgaengig gemacht werden.", + "importReplaceConfirmBody": "Alle vorhandenen Fahrzeuge werden durch die CSV-Daten ersetzt. Diese Aktion kann nicht rückgängig gemacht werden.", "importReplaceConfirmButton": "Ersetzen", "importSuccess": "{count} Fahrzeuge importiert", "vehicleCount": "{count} Fahrzeuge", @@ -562,20 +562,20 @@ "host": "Host", "hostExchange": "EWS-URL", "domain": "Domain", - "domainHelp": "Optional — Windows-Domaene (z.B. CONTOSO). Leer lassen wenn nicht benoetigt.", + "domainHelp": "Optional — Windows-Domäne (z.B. CONTOSO). Leer lassen wenn nicht benötigt.", "port": "Port", - "encryption": "Verschluesselung", + "encryption": "Verschlüsselung", "encryptionNone": "Keine", "folder": "Ordner / Postfach", - "folderExchangeHelp": "Standard-Postfaecher: Inbox, SentItems, DeletedItems, Drafts, JunkEmail", + "folderExchangeHelp": "Standard-Postfächer: Inbox, SentItems, DeletedItems, Drafts, JunkEmail", "senderFilter": "Absenderfilter", "pollInterval": "Abrufintervall", "pollIntervalSuffix": "Minuten", "username": "Benutzername", "password": "Passwort", - "exportRecipient": "Export-Empfaenger", + "exportRecipient": "Export-Empfänger", "vehicleFormat": "Fahrzeug-Formatstring", - "vehicleFormatHelp": "Verfuegbare Platzhalter: {Marke}, {Modell}, {Kennzeichen}, {Fahrer}", + "vehicleFormatHelp": "Verfügbare Platzhalter: {Marke}, {Modell}, {Kennzeichen}, {Fahrer}", "active": "Aktiv", "testConnection": "Verbindung testen", "testTesting": "Verbindung wird getestet...", @@ -586,44 +586,44 @@ "cancelDialog": "Abbrechen", "showPassword": "Passwort anzeigen", "hidePassword": "Passwort verbergen", - "exchangeAuthHint": "401 — moegliche Ursachen:", + "exchangeAuthHint": "401 — mögliche Ursachen:", "exchangeAuthHint1": "Falsches Passwort oder Benutzername", "exchangeAuthHint2": "Domain: Windows-Kurzname (z.B. FIRMA, nicht firma.de)", - "exchangeAuthHint3": "Benutzername ohne Domain-Praefix (z.B. 'max.muster', nicht 'FIRMA\\max.muster')", - "exchangeAuthHint4": "Office 365 / Exchange Online: EWS-Basisauthentifizierung seit Okt. 2022 deaktiviert — nicht unterstuetzt" + "exchangeAuthHint3": "Benutzername ohne Domain-Präfix (z.B. 'max.muster', nicht 'FIRMA\\max.muster')", + "exchangeAuthHint4": "Office 365 / Exchange Online: EWS-Basisauthentifizierung seit Okt. 2022 deaktiviert — nicht unterstützt" }, "errors": { - "pollFailed": "Posteingang konnte nicht geprueft werden. Ueberpruefe die Konfiguration unter 'Moduleinstellungen > Posteingang'.", - "smtpFailed": "Export wurde erstellt, konnte aber nicht gesendet werden. Die Datei ist weiterhin zum Download verfuegbar." + "pollFailed": "Posteingang konnte nicht geprüft werden. Überprüfe die Konfiguration unter 'Moduleinstellungen > Posteingang'.", + "smtpFailed": "Export wurde erstellt, konnte aber nicht gesendet werden. Die Datei ist weiterhin zum Download verfügbar." } }, "marketplace": { "title": "Marktplatz", - "subtitle": "Entdecken und aktivieren Sie Module fuer Ihren Mandanten", + "subtitle": "Entdecken und aktivieren Sie Module für Ihren Mandanten", "activate": "Modul aktivieren", "deactivate": "Deaktivieren", "searchPlaceholder": "Module suchen...", "statusAll": "Alle", "statusActive": "Aktiviert", - "statusAvailable": "Verfuegbar", + "statusAvailable": "Verfügbar", "categoryAll": "Alle", - "emptyTitle": "Noch keine Module verfuegbar", - "emptyBody": "Module werden vom Systemadministrator bereitgestellt. Schauen Sie spaeter noch einmal vorbei.", + "emptyTitle": "Noch keine Module verfügbar", + "emptyBody": "Module werden vom Systemadministrator bereitgestellt. Schauen Sie später noch einmal vorbei.", "filteredEmptyTitle": "Keine Ergebnisse", - "filteredEmptyBody": "Versuchen Sie einen anderen Suchbegriff oder aendern Sie die Filter.", + "filteredEmptyBody": "Versuchen Sie einen anderen Suchbegriff oder ändern Sie die Filter.", "errorLoad": "Module konnten nicht geladen werden. Bitte laden Sie die Seite neu.", "toastActivated": "Modul erfolgreich aktiviert", "toastDeactivated": "Modul erfolgreich deaktiviert", "toastActivateError": "Aktivierung fehlgeschlagen. Bitte versuchen Sie es erneut.", "toastDeactivateError": "Deaktivierung fehlgeschlagen. Bitte versuchen Sie es erneut.", "deactivateDialogTitle": "Modul deaktivieren", - "deactivateDialogBody": "Moechten Sie {moduleName} fuer diesen Mandanten deaktivieren? Das Modul wird aus der Seitenleiste entfernt.", + "deactivateDialogBody": "Möchten Sie {moduleName} für diesen Mandanten deaktivieren? Das Modul wird aus der Seitenleiste entfernt.", "deactivateDialogConfirm": "Deaktivieren", "deactivateDialogCancel": "Abbrechen", "tenantContextLabel": "Mandanten-Kontext", - "backToMarketplace": "Zurueck zum Marktplatz", + "backToMarketplace": "Zurück zum Marktplatz", "detailVersion": "Version {version}", - "detailStatusActive": "Aktiviert fuer diesen Mandanten", + "detailStatusActive": "Aktiviert für diesen Mandanten", "detailStatusInactive": "Nicht aktiviert", "accessDenied": "Zugriff verweigert", "statusNoAccess": "Kein Zugriff", @@ -631,11 +631,11 @@ }, "certManager": { "title": "Zertifikat-Manager", - "description": "Zertifikate analysieren, aufteilen, zusammenfuehren und konvertieren.", + "description": "Zertifikate analysieren, aufteilen, zusammenführen und konvertieren.", "tabs": { "inspect": "Analysieren", "split": "Aufteilen", - "merge": "Zusammenfuehren", + "merge": "Zusammenführen", "convert": "Konvertieren" }, "dropZone": { @@ -643,7 +643,7 @@ "formats": ".pem, .crt, .cer, .der, .pfx, .p12, .p7b, .p7c" }, "paste": { - "placeholder": "PEM-Inhalt einfuegen (-----BEGIN ...)" + "placeholder": "PEM-Inhalt einfügen (-----BEGIN ...)" }, "password": { "label": "Passwort (PFX/P12)" @@ -652,7 +652,7 @@ "actions": { "inspect": "Analysieren", "split": "Aufteilen", - "merge": "Zusammenfuehren", + "merge": "Zusammenführen", "convert": "Konvertieren", "download": "Herunterladen", "downloadZip": "Alle als ZIP herunterladen", @@ -665,17 +665,17 @@ }, "emptyState": { "inspect": "Kein Zertifikat geladen.", - "inspectBody": "Lade eine Datei hoch oder fuege PEM-Text ein.", + "inspectBody": "Lade eine Datei hoch oder füge PEM-Text ein.", "split": "Keine Datei geladen.", "splitBody": "Lade eine Fullchain- oder P7B-Datei hoch.", - "merge": "Keine Zertifikate ausgewaehlt.", + "merge": "Keine Zertifikate ausgewählt.", "mergeBody": "Lade mindestens zwei Dateien hoch.", "convert": "Keine Datei geladen.", - "convertBody": "Lade eine Datei hoch und waehle ein Ausgabeformat." + "convertBody": "Lade eine Datei hoch und wähle ein Ausgabeformat." }, "error": { - "generic": "Verarbeitung fehlgeschlagen. Pruefe das Dateiformat oder das Passwort.", - "wrongPassword": "Falsches Passwort. PFX/P12-Datei konnte nicht entschluesselt werden.", + "generic": "Verarbeitung fehlgeschlagen. Prüfe das Dateiformat oder das Passwort.", + "wrongPassword": "Falsches Passwort. PFX/P12-Datei konnte nicht entschlüsselt werden.", "unknownFormat": "Unbekanntes Format. Die Datei konnte nicht als Zertifikat erkannt werden." } }, @@ -756,8 +756,6 @@ "DEG": "Thüringen" }, "cpvDivisions": { - "03": "Landwirtschaftliche, fischereiwirtschaftliche, forstwirtschaftliche und verwandte Erzeugnisse", - "09": "Mineralölerzeugnisse, Brennstoffe, Elektrizität und andere Energiequellen", "14": "Bergbauerzeugnisse, Grundstoffe und verwandte Erzeugnisse", "15": "Nahrungsmittel, Getränke, Tabak und verwandte Erzeugnisse", "16": "Land- und forstwirtschaftliche Maschinen", @@ -800,7 +798,9 @@ "85": "Dienste im Gesundheits- und Sozialwesen", "90": "Abwasser- und Abfallbeseitigung, Reinigung und Umweltschutzdienste", "92": "Dienstleistungen der Freizeitgestaltung, der Kultur und des Sports", - "98": "Sonstige Gemeinschafts-, Sozial- und Individualdienstleistungen" + "98": "Sonstige Gemeinschafts-, Sozial- und Individualdienstleistungen", + "03": "Landwirtschaftliche, fischereiwirtschaftliche, forstwirtschaftliche und verwandte Erzeugnisse", + "09": "Mineralölerzeugnisse, Brennstoffe, Elektrizität und andere Energiequellen" } }, "savedSearch": { diff --git a/apps/web/src/messages/umlaut-dictionary.ts b/apps/web/src/messages/umlaut-dictionary.ts new file mode 100644 index 0000000..c0e41c8 --- /dev/null +++ b/apps/web/src/messages/umlaut-dictionary.ts @@ -0,0 +1,160 @@ +/** + * umlaut-dictionary — single source of truth for the ae/oe/ue/ss umlaut + * correction in `de.json` and for the `umlaut-guard.spec.ts` regression + * guard. + * + * Why an explicit token list instead of a character rule (`ue` -> `ü`, + * `oe` -> `ö`, `ae` -> `ä`): a blanket character substitution destroys + * correct German. `Quelle` would become `Qülle`, `manuell` would become + * `manüll`, `neuen` would become `nün`, `Erzeugnisse` would become + * `Erzügnisse`. Replacement therefore only ever targets a whole token + * that is an exact key in `UMLAUT_REPLACEMENTS`. + * + * `UMLAUT_ALLOWLIST` lists every token that legitimately contains + * `ae`/`oe`/`ue`/`ss` and is already correct German — it must never be + * replaced. `empfaenger` sits on this list purely because it is part of + * the example placeholder address `empfaenger@example.com` + * (key `testToPlaceholder`): an umlaut inside a placeholder email address + * would wrongly suggest umlaut addresses are the expected format, so that + * value is skipped entirely (any string containing `@`) rather than + * "corrected". + */ + +/** Wrong substitute spelling -> correct German spelling, exact token match only. */ +export const UMLAUT_REPLACEMENTS: Record = { + loeschen: 'löschen', + Loeschen: 'Löschen', + geloescht: 'gelöscht', + hinzufuegen: 'hinzufügen', + Hinzufuegen: 'Hinzufügen', + hinzuzufuegen: 'hinzuzufügen', + einfuegen: 'einfügen', + fuege: 'füge', + Fuege: 'Füge', + Fuegen: 'Fügen', + fuer: 'für', + pruefen: 'prüfen', + Pruefen: 'Prüfen', + Pruefe: 'Prüfe', + Pruefung: 'Prüfung', + geprueft: 'geprüft', + ueberpruefen: 'überprüfen', + Ueberpruefe: 'Überprüfe', + Zertifikatspruefung: 'Zertifikatsprüfung', + aendern: 'ändern', + geaendert: 'geändert', + Moechten: 'Möchten', + moeglich: 'möglich', + moegliche: 'mögliche', + koennen: 'können', + verfuegbar: 'verfügbar', + Verfuegbar: 'Verfügbar', + Verfuegbare: 'Verfügbare', + Verfuegbarkeit: 'Verfügbarkeit', + Zurueck: 'Zurück', + Zuruecksetzen: 'Zurücksetzen', + zuruecksetzen: 'zurücksetzen', + zurueckgesetzt: 'zurückgesetzt', + rueckgaengig: 'rückgängig', + Zusammenfuehren: 'Zusammenführen', + zusammenfuehren: 'zusammenführen', + bestaetigen: 'bestätigen', + Passwoerter: 'Passwörter', + spaeter: 'später', + ueberein: 'überein', + uebersprungen: 'übersprungen', + ueber: 'über', + ungueltig: 'ungültig', + Verschluesselung: 'Verschlüsselung', + entschluesselt: 'entschlüsselt', + ausgewaehlt: 'ausgewählt', + Ausgewaehlt: 'Ausgewählt', + ausgewaehlte: 'ausgewählte', + Ausgewaehlte: 'Ausgewählte', + waehle: 'wähle', + benoetigt: 'benötigt', + noetig: 'nötig', + muessen: 'müssen', + Domaene: 'Domäne', + Einschraenkung: 'Einschränkung', + Empfaenger: 'Empfänger', + Oberflaeche: 'Oberfläche', + Postfaecher: 'Postfächer', + Praefix: 'Präfix', + Sicherheitsgruenden: 'Sicherheitsgründen', + unterstuetzt: 'unterstützt', + vertrauenswuerdigen: 'vertrauenswürdigen', + zusaetzlich: 'zusätzlich', + zusaetzliche: 'zusätzliche', + Groesse: 'Größe', + Schliessen: 'Schließen', + ausschliessen: 'ausschließen', +}; + +/** + * Tokens containing `ae`/`oe`/`ue`/`ss` that are already correct German + * and must never be touched by the replacement or flagged by the guard. + */ +export const UMLAUT_ALLOWLIST: readonly string[] = [ + 'manuell', + 'Manuell', + 'Quelle', + 'Quellen', + 'Quell', + 'Quellportal', + 'Kalenderquelle', + 'Kalenderquellen', + 'Energiequellen', + 'neue', + 'neuen', + 'Neue', + 'Neues', + 'aktuelle', + 'Aktuell', + 'Aktuelle', + 'Aktuelles', + 'zuerst', + 'dauerhaft', + 'Schauen', + 'Taktfrequenz', + 'Feuerlösch', + 'Bergbauerzeugnisse', + 'true', + 'guest', + 'Passwort', + 'Adresse', + 'Absenderadresse', + 'muss', + 'musste', + 'müssen', + 'lassen', + 'vergessen', + 'stattdessen', + 'Wasser', + 'Abwasser', + 'Hessen', + 'Erzeugnisse', + 'Druckerzeugnisse', + 'Gummierzeugnisse', + 'Mineralölerzeugnisse', + 'Ausschreibung', + 'Ausschreibungen', + 'Ausschreibungs', + 'Ausschreibungsdetails', + 'erfasst', + 'erfasster', + 'Erfassung', + 'Ergebnisse', + 'gedrosselt', + 'ausgeschlossen', + 'Ausgeschlossen', + 'Ausschlussliste', + 'Informationssysteme', + 'Zeitmessung', + 'Tessera', + 'Passen', + 'Passt', + 'Fasst', + 'Verschlüsselung', + 'empfaenger', +];