From 9ef696591e61884f6de769c2803b4f73c34b6f10 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Tue, 20 Feb 2024 10:04:42 +0100
Subject: [PATCH 01/16] Bug Fixes AZUPF-55,56,30,52,62
---
.../rest/DataTransferPersonalBoxPageRest.kt | 1 -
.../org/projectforge/mail/MailAccount.java | 10 +-
.../main/resources/I18nResources.properties | 42 +-
.../resources/I18nResources_de.properties | 1560 +++++++++--------
.../projectforge/rest/AddressViewPageRest.kt | 4 +-
.../kotlin/org/projectforge/rest/dto/User.kt | 4 +
.../rest/fibu/CustomerPagesRest.kt | 1 -
.../projectforge/rest/poll/PollCronJobs.kt | 13 +-
.../rest/poll/PollInfoPageRest.kt | 12 +-
.../projectforge/rest/poll/PollMailService.kt | 22 +-
.../projectforge/rest/poll/PollPageRest.kt | 81 +-
.../rest/poll/PollResponsePageRest.kt | 2 +-
.../rest/poll/types/PremadeQuestions.kt | 2 +-
.../projectforge/rest/poll/types/Question.kt | 1 +
14 files changed, 983 insertions(+), 772 deletions(-)
diff --git a/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt b/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt
index 1773efe6d4..11d5168650 100644
--- a/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt
+++ b/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt
@@ -25,7 +25,6 @@ package org.projectforge.plugins.datatransfer.rest
import org.projectforge.business.user.UserGroupCache
import org.projectforge.business.user.service.UserPrefService
-import org.projectforge.framework.i18n.translate
import org.projectforge.framework.utils.NumberHelper
import org.projectforge.model.rest.RestPaths
import org.projectforge.plugins.datatransfer.DataTransferAreaDao
diff --git a/projectforge-business/src/main/java/org/projectforge/mail/MailAccount.java b/projectforge-business/src/main/java/org/projectforge/mail/MailAccount.java
index d351546191..2a47cac83d 100644
--- a/projectforge-business/src/main/java/org/projectforge/mail/MailAccount.java
+++ b/projectforge-business/src/main/java/org/projectforge/mail/MailAccount.java
@@ -35,7 +35,7 @@
/**
* Connects to a mail server and receives mails.
- *
+ *
* @author Kai Reinhard (k.reinhard@micromata.de)
*/
public class MailAccount
@@ -75,7 +75,7 @@ public MailAccount(Store store, Folder folder)
/**
* Gets a list of all Emails matching the given filter.
- *
+ *
* @return ArrayList of all found Email.
*/
public Mail[] getMails(final MailFilter filter)
@@ -134,7 +134,7 @@ public Mail[] getMails(final MailFilter filter)
/**
* Opens the connection to the mailserver. Don't forget to call disconnect if this method returns true!
- *
+ *
* @param mbox The folder name to open. If null then the default folder will be opened.
* @param readwrite If false then the mbox is connected in readonly mode.
* @return true on success, otherwise false.
@@ -207,7 +207,7 @@ public Mail[] getMails(final MailFilter filter)
/**
* Disconnects the folder and store if given and is opened yet.
- *
+ *
* @return
*/
// @Deprecated
@@ -360,4 +360,4 @@ private void getContent(final Part msg, final StringBuffer buf) throws Messaging
}
}
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-business/src/main/resources/I18nResources.properties b/projectforge-business/src/main/resources/I18nResources.properties
index c84d171c90..d52c25cf05 100644
--- a/projectforge-business/src/main/resources/I18nResources.properties
+++ b/projectforge-business/src/main/resources/I18nResources.properties
@@ -187,7 +187,14 @@ moreEntriesAvailable=More entries available.
name=Name
new=New
nickname=Nickname
-no=No
+
+
+
+
+
+
+
+
notEnded=not ended
nothingFound=Nothing found.
notLoggedIn=Not logged in.
@@ -281,7 +288,6 @@ username=User name
value=Value
values=Values
weekOfYear=Week of year
-yes=Yes
access=Accessright
access.accessTable=Access table
@@ -1976,10 +1982,19 @@ plugins.teamcal.title.edit=Edit team calendar
plugins.teamcal.title.heading=Calendar
plugins.teamcal.title.list=List of calendars
+
+
+
+
# poll plugin
+TextQuestion=Text Question
+SingleResponseQuestion=Single Response Question
+MultiResponseQuestion=Multiple Choice Question
+
+
poll=Poll
poll.access=Access
-poll.answer=Answer
+poll.answer=Option
poll.assignment=Assignment
poll.attendee=Attendee
poll.attendees=Attendees
@@ -1990,6 +2005,7 @@ poll.confirmation.creation=Do you really want to create the poll? You won't be a
Also make sure to add attendees for your poll.
poll.confirmation.deleteAnswer=Do you really want to delete this answer?
poll.confirmation.deleteQuestion=Do you really want to delete this question?
+poll.confirmation.deleteButton=Yes
poll.confirmation.finish=Do you really want to finish this Poll?
poll.date=Date
poll.deadline=Deadline
@@ -2036,8 +2052,26 @@ poll.other=Other
poll.owner=Owner
poll.popup.closed=The poll was already closed.
poll.question=Question
-poll.question.textQuestion=Text Question
poll.questionType=Question Type
+poll.questionType.TextQuestion=Text Question
+poll.questionType.SingleResponseQuestion=Single response Question
+poll.questionType.MultiResponseQuestion=Multiple Choice Questions
+
+poll.question.texttitle= Text Questions
+poll.question.singletitel= Singel response Question
+poll.question.multititle= Multiple Choice Questions
+
+poll.question.text=Question
+poll.question.single=Question
+poll.question.multi=Question
+
+
+
+
+
+
+
+
poll.respond=Send responses
poll.response.mail.update.content=Dear {0},
\
I wanted to inform you that Person {2} has updated their answer to Poll {1}.
\
diff --git a/projectforge-business/src/main/resources/I18nResources_de.properties b/projectforge-business/src/main/resources/I18nResources_de.properties
index 3d7a6b76e9..4ce0303f60 100644
--- a/projectforge-business/src/main/resources/I18nResources_de.properties
+++ b/projectforge-business/src/main/resources/I18nResources_de.properties
@@ -93,23 +93,23 @@
# Wicket:
-datatable.no-records-found=Keine Einträge gefunden.
+datatable.no-records-found=Keine Einträge gefunden.
NavigatorLabel=Zeile ${from} bis ${to} von ${of}.
StringValidator.exact=Das Feld ''${label}'' ist nicht exakt ${exact} Zeichen lang, sondern ${length} Zeichen lang.
StringValidator.maximum=Das Feld ''${label}'' mit ${length} Zeichen darf maximal ${maximum} Zeichen lang sein.
StringValidator.minimum=Das Feld ''${label}'' mit ${length} Zeichen muss mindestens ${minimum} Zeichen lang sein.
StringValidator.range=Das Feld ''${label}'' mit ${length} Zeichen muss zwischen ${minimum} und ${maximum} Zeichen lang sein.
-validation.error.fieldRequired=Feld ''{0}'' muss ausgefüllt werden.
-validation.error.format.integer=Ungültiger Ganzzahlwert.
-validation.error.generic=Ungültige Eingabe.
-validation.error.nothingToExport=Keine Daten für den Export vorhanden.
-validation.error.range.integerOutOfRange=Wert außerhalb des Bereichs {0} - {1}.
-validation.error.range.integerToHigh=Wert darf nicht größer als {0} sein.
+validation.error.fieldRequired=Feld ''{0}'' muss ausgefüllt werden.
+validation.error.format.integer=Ungültiger Ganzzahlwert.
+validation.error.generic=Ungültige Eingabe.
+validation.error.nothingToExport=Keine Daten für den Export vorhanden.
+validation.error.range.integerOutOfRange=Wert außerhalb des Bereichs {0} - {1}.
+validation.error.range.integerToHigh=Wert darf nicht größer als {0} sein.
validation.error.range.integerToLow=Wert darf nicht kleiner als {0} sein.
validation.required.valueNotPresent=Wert ''{0}'' nicht gegeben.
# React UI
-select.placeholder=Auswählen...
+select.placeholder=Auswählen...
table.showing=Anzeige
# own validations:
@@ -117,7 +117,7 @@ bicvalidator.wronglength=Das Feld ''${label}'' muss 8 oder 11 Zeichen lang sein.
ibanvalidator.wronglength.de=Das Feld ''${label}'' beginnt mit ''DE''. Eine deutsche IBAN muss jedoch aus 22 Zeichen bestehen.
# Currency format
-currencyConverter.percentage.help=Es können sowohl Beträge als auch Prozentzahlen (z. B. 10%) eingegeben werden.
+currencyConverter.percentage.help=Es können sowohl Beträge als auch Prozentzahlen (z. B. 10%) eingegeben werden.
currencyFormat={0,number,,##0.00}
# Not internationalized properties:
@@ -131,73 +131,75 @@ currencyFormat={0,number,,##0.00}
### not translated: message.notYetImplemented=Not yet implemented.
# Buttons:
-add=Hinzufügen
+add=Hinzufügen
assign=Zuweisen
-back=Zurück
+back=Zurück
cancel=Abbrechen
-change=Ändern
+
+create=Anlegen
+change=Ändern
check=Check
clone=Klonen
-close=Schließen
+close=Schließen
copy=Kopieren
-create=Anlegen
-delete=Löschen
-deselectAll=Alle abwählen
-download=Download
-download.expired=Downloaddatei nicht mehr verfügbar. Bitte Aktion wiederholen.
-drop=Drop
-execute=Ausführen
-exportAsPdf=Pdf-Export
-exportAsXls=Excel-Export
+delete=Löschen
+deselectAll=Alle abwählen
+download=Herunterladen
+download.expired=Downloaddatei nicht mehr verfügbar. Bitte Aktion wiederholen.
+drop=Verwerfern
+execute=Ausführen
+exportAsPdf=Pdf-Exportieren
+exportAsXls=Excel-Exportieren
favorite=Favorit
favorite.addNew=Neuer Favorit
favorite.filter.addNew=Neuer Filter
favorite.untitled=unbenannt
favorites=Favoriten
-favorites.saveModification=Änderungen speichern
+favorites.saveModification=Änderungen speichern
finish=Fertig
-forceDelete=Unwiderruflich löschen
+Button_Finish=Ja
+forceDelete=Unwiderruflich löschen
import=Importieren
login=Anmelden
mark=Markieren
-markAsDeleted=Löschen
-massUpdate=Massenänderung
+markAsDeleted=Löschen
+massUpdate=Massenänderung
more=Mehr
next=Weiter
ok=OK
-paste=Einfügen
+paste=Einfügen
preview=Vorschau
recalculate=Neu berechnen
redraw=Neu zeichnen
refresh=Neu laden
reload=Neu laden
rename=Umbenennen
-reset=Rücksetzen
+reset=Rücksetzen
save=Speichern
search=Suchen
-select=Auswählen
-selectAll=Alle auswählen
-selectDate=Auswählen
-selectGroup=Auswählen
-selectTask=Auswählen
+select=Auswählen
+selectAll=Alle auswählen
+selectDate=Auswählen
+selectGroup=Auswählen
+selectTask=Auswählen
send=Senden
show=Anzeigen
stop=Beenden
unassign=Entfernen
undelete=Wiederherstellen
unkown=unbekannt
-update=Ändern
-updateAll=Alle ändern
-updateAndNext=Ändern und nächster
+update=Ändern
+updateAll=Alle ändern
+updateAndNext=Ändern und nächster
upload=Hochladen
uptodate=aktuell
wizard=Assistent
# Common
akquise=Akquise
-changes=Änderungen
-charactersLeft=Zeichen übrig.
-color.error.unknownFormat=Farbcode kann nicht verarbeitet werden. Unterstützte Hex-Farbformate: #abc or #abcdef
+changes=Änderungen
+charactersLeft=Zeichen übrig.
+color.error.unknownFormat=Farbcode kann nicht verarbeitet werden. Unterstützte Hex-Farbformate: #abc or #abcdef
comment=Bemerkung
completed=erledigt
contactPerson=Ansprechpartner:in
@@ -214,9 +216,9 @@ day=Tag(e)
days=Tage
deadline=Frist
default=Standard
-deleted=gelöscht
+deleted=gelöscht
description=Beschreibung
-dueDate=Fälligkeit
+dueDate=Fälligkeit
edit=Bearbeiten
email=E-Mail
ended=beendet
@@ -225,22 +227,22 @@ errors=Fehler
export=Export
fieldNotHistorizable=Dieses Feld wird nicht historisiert!
file=Datei
-file.upload.audit.action.delete=gelöscht
+file.upload.audit.action.delete=gelöscht
file.upload.audit.action.download=heruntergeladen
file.upload.audit.action.downloadAll=alles heruntergeladen
file.upload.audit.action.downloadMulti=mehrere heruntergeladen
-file.upload.audit.action.modification=geändert (Dateiname oder Beschreibung)
+file.upload.audit.action.modification=geändert (Dateiname oder Beschreibung)
file.upload.audit.action.upload=hochgeladen
-file.upload.choose=Datei wählen
-file.upload.deleteSelected=Ausgewählte Dateien löschen
-file.upload.deleteSelected.confirm=Sollen jetzt wirklich alle ausgewählten Dateien unwiderruflich gelöscht werden?
-file.upload.downloadSelected=Ausgewählte Dateien herunterladen
-file.upload.dropArea=Datei auswählen oder hier hinziehen.
+file.upload.choose=Datei wählen
+file.upload.deleteSelected=Ausgewählte Dateien löschen
+file.upload.deleteSelected.confirm=Sollen jetzt wirklich alle ausgewählten Dateien unwiderruflich gelöscht werden?
+file.upload.downloadSelected=Ausgewählte Dateien herunterladen
+file.upload.dropArea=Datei auswählen oder hier hinziehen.
file.upload.error.fileAlreadyExists=Die Datei ''{0}'' existiert bereits.
-file.upload.error.maxSizeExceeded=Datei ''{0}'' kann nicht hochgeladen werden. Die konfigurierte Maximalgröße wurde überschritten: {1}>{2}.
-file.upload.error.maxSizeOfExceeded=Die Datei konnte nicht hochgeladen werden. Die Maximalgröße von {0} wurde überschritten.
-file.upload.error.noFileSelected=Keine Datei gewählt
-file.upload.error.toManyFiles=Es wurden zu viele Dateien für das gleichzeitige Hochladen ausgewählt.
+file.upload.error.maxSizeExceeded=Datei ''{0}'' kann nicht hochgeladen werden. Die konfigurierte Maximalgröße wurde überschritten: {1}>{2}.
+file.upload.error.maxSizeOfExceeded=Die Datei konnte nicht hochgeladen werden. Die Maximalgröße von {0} wurde überschritten.
+file.upload.error.noFileSelected=Keine Datei gewählt
+file.upload.error.toManyFiles=Es wurden zu viele Dateien für das gleichzeitige Hochladen ausgewählt.
filing=Ablageort
filter=Filter
filter.all=alle
@@ -252,7 +254,7 @@ firstName=Vorname
gender=Geschlecht
gender.diverse=divers
gender.female=weiblich
-gender.male=männlich
+gender.male=männlich
gender.notApplicable=nicht zutreffend
gender.notKnown=unbekannt
gender.unknown=unbekannt
@@ -262,9 +264,9 @@ hours=Stunden
id=Id
imageFile=Bild
inherit=vererbt
-key=Schlüssel
+key=Schlüssel
language=Sprache
-lastUpdate=letzte Änderung
+lastUpdate=letzte Änderung
legend=Legende
list=Liste
listView=Listenansicht
@@ -272,36 +274,35 @@ loading=Laden...
loggedInUserInfo=Angemeldet als:
longFormat=Langes Format
misc=Verschiedenes
-modifications=Änderungen
-modificationTime=Änderungszeitraum
-modified=geändert
-modifiedBy=geändert durch
-modifiedHistoryValue=Wert in der Änderungshistorie
-moreEntriesAvailable=Mehr Einträge vorhanden.
+modifications=Änderungen
+modificationTime=Änderungszeitraum
+modified=geändert
+modifiedBy=geändert durch
+modifiedHistoryValue=Wert in der Änderungshistorie
+moreEntriesAvailable=Mehr Einträge vorhanden.
name=Name
new=Neu
nickname=Rufname
-no=Nein
notEnded=nicht beendet
nothingFound=Nichts gefunden.
notLoggedIn=Nicht angemeldet
notVisible=nicht sichtbar
oclock=Uhr
-onlyDeleted=nur gelöschte
-onlyDeleted.tooltip=Es werden nur gelöschte Datensätze angezeigt (i. d. R. unabhängig von anderen Filterangaben).
-operation.deleted=gelöscht
+onlyDeleted=nur gelöschte
+onlyDeleted.tooltip=Es werden nur gelöschte Datensätze angezeigt (i. d. R. unabhängig von anderen Filterangaben).
+operation.deleted=gelöscht
operation.inserted=angelegt
-operation.markAsDeleted=als gelöscht markiert
+operation.markAsDeleted=als gelöscht markiert
operation.undefined=undefiniert
operation.undeleted=wiederhergestellt
-operation.updated=geändert
+operation.updated=geändert
organization=Firma
password=Passwort
passwordRepeat=Passwort wiederholen
percent=Prozent
-pleaseChoose=Bitte wählen
+pleaseChoose=Bitte wählen
printView=Druckansicht
-priority=Priorität
+priority=Priorität
priority.high=hoch
priority.highest=sehr hoch
priority.least=gering
@@ -360,7 +361,7 @@ timeNotation=Uhrzeitformat
timeNotation.12=12 Stunden
timeNotation.24=24 Stunden
timeOfCreation=Anlagezeitpunkt
-timeOfLastUpdate=Zeitpunkt der letzten Änderung
+timeOfLastUpdate=Zeitpunkt der letzten Änderung
timePeriod=Zeitraum
timestamp=Zeitstempel
timezone=Zeitzone
@@ -375,27 +376,26 @@ username=Benutzer:innenname
value=Wert
values=Werte
weekOfYear=Kalenderwoche
-yes=Ja
access=Zugriffsrecht
access.accessTable=Zugriffstabelle
-access.exception.demoUserHasNoAccess=Der oder die Demobenutzer:in ist für diese Aktion gesperrt.
+access.exception.demoUserHasNoAccess=Der oder die Demobenutzer:in ist für diese Aktion gesperrt.
access.exception.employeeHasNoVacationDays=Dem oder der Mitarbeiter:in sind keine Urlaubstage zugewiesen
access.exception.noAccess=Kein Zugriff.
-access.exception.noEmployeeToUser=Angemeldete:r Benutzer:in hat keinen zugehörige:n Mitarbeiter:in
+access.exception.noEmployeeToUser=Angemeldete:r Benutzer:in hat keinen zugehörige:n Mitarbeiter:in
access.exception.noReadAccess=Kein lesender Zugriff.
access.exception.noUserGiven=Keine:n angemeldete:n Benutzer:in gefunden.
access.exception.noWriteAccess=Kein schreibender Zugriff.
-access.exception.restrictedUserHasNoAccess=Der oder der eingeschänkte (restricted) Benutzer:in ist für diese Aktion gesperrt.
+access.exception.restrictedUserHasNoAccess=Der oder der eingeschänkte (restricted) Benutzer:in ist für diese Aktion gesperrt.
access.exception.standard=Zugriffsverletzung: {0} - {1}.
-access.exception.standardWithTask=Zugriffsverletzung für Strukturelement\: ''{0}''\: {1} - {2}.
+access.exception.standardWithTask=Zugriffsverletzung für Strukturelement\: ''{0}''\: {1} - {2}.
access.exception.userHasNotRight=Der oder die Benutzer:in hat nicht das geforderte Recht {0} - {1}.
access.exception.violation=Zugriffsverletzung: {0}.
access.filter.includeAncestorTasks=Strukturoberelemente
access.filter.includeDescendentTasks=Strukturunterelemente
access.groups=Gruppen
access.read=Lesezugriff
-access.recursive.help=Rekursiv gilt auch für alle Strukturunterelemente.
+access.recursive.help=Rekursiv gilt auch für alle Strukturunterelemente.
access.right.admin.core=Adminrights
### not translated: access.right.admin.multitenancy=Multi-tenancy administration
access.right.category.fibu=Finanzbuchhaltung
@@ -405,15 +405,15 @@ access.right.category.plugins=Plugins
access.right.category.pm=Projektmanagement
access.right.fibu.accounts=Konten
access.right.fibu.ausgangsrechnungen=Debitorenrechnungen
-access.right.fibu.costUnit=Kostenträger
+access.right.fibu.costUnit=Kostenträger
access.right.fibu.datevImport=Datev-Import
access.right.fibu.eingangsrechnungen=Kreditorenrechnungen
access.right.fibu.employee=Mitarbeiter:in
-access.right.fibu.employeeSalaries=Gehälter
+access.right.fibu.employeeSalaries=Gehälter
access.right.hr.employee=Mitarbeiter:in
-access.right.hr.employeeSalaries=Gehälter
+access.right.hr.employeeSalaries=Gehälter
access.right.hr.vacation=Urlaub
-access.right.orga.contracts=Verträge
+access.right.orga.contracts=Verträge
access.right.orga.incomingmail=Eingangspost
access.right.orga.outgoingmail=Ausgangspost
access.right.orga.visitorbook=Besuchsbuch
@@ -438,17 +438,17 @@ access.title.add=Neues Zugriffsrecht
access.title.edit=Zugriff bearbeiten
access.title.heading=Zugriffsrechte
access.title.list=Liste der Zugriffsrechte
-access.tooltip.deleteAccess=Löschen-Recht (Einträge löschen)
-access.tooltip.filter.includeAncestorTasks=Auch für alle Strukturoberelemente die definierte Zugriffsrechte anzeigen (ein Strukturelement muss ausgewählt sein).
-access.tooltip.filter.includeDescendentTasks=Auch für alle Strukturunterelemente die definierte Zugriffsrechte anzeigen (ein Strukturelement muss ausgewählt sein).
-access.tooltip.filter.inherit=Auch von allen Strukturoberelementen vererbte Zugriffrechte anzeigen (ein Strukturelement muss ausgewählt sein).
-access.tooltip.filter.user=Zeige alle definierten Zugriffsrechten zu Gruppen, denen der ausgewählte Benutzer angehört.
-access.tooltip.insertAccess=Anlegen-Recht (neue Einträge hinzufügen)
+access.tooltip.deleteAccess=Löschen-Recht (Einträge löschen)
+access.tooltip.filter.includeAncestorTasks=Auch für alle Strukturoberelemente die definierte Zugriffsrechte anzeigen (ein Strukturelement muss ausgewählt sein).
+access.tooltip.filter.includeDescendentTasks=Auch für alle Strukturunterelemente die definierte Zugriffsrechte anzeigen (ein Strukturelement muss ausgewählt sein).
+access.tooltip.filter.inherit=Auch von allen Strukturoberelementen vererbte Zugriffrechte anzeigen (ein Strukturelement muss ausgewählt sein).
+access.tooltip.filter.user=Zeige alle definierten Zugriffsrechten zu Gruppen, denen der ausgewählte Benutzer angehört.
+access.tooltip.insertAccess=Anlegen-Recht (neue Einträge hinzufügen)
access.tooltip.selectAccess=Lesen-Recht
-access.tooltip.updateAccess=Änderungs-Recht (bestehende Einträge bearbeiten)
+access.tooltip.updateAccess=Änderungs-Recht (bestehende Einträge bearbeiten)
access.type=Zugriffstyp
access.type.accessManagement=Zugriffsverwaltung
-access.type.delete=Löschen
+access.type.delete=Löschen
access.type.group=Gruppen
access.type.insert=Anlegen
access.type.ownTimesheets=Eigene Zeitberichte
@@ -456,13 +456,13 @@ access.type.select=Lesen
access.type.tasks=Strukturelemente
access.type.timesheets=Zeitberichte
access.type.undelete=Wiederherstellen
-access.type.update=Ändern
+access.type.update=Ändern
access.users=Benutzer:in
-access.violation.userNotMemberOf=Operation ist nur für Benutzer:innen der Gruppe(n) ''{0}'' erlaubt (ggf. auch andere Gruppen möglich).
+access.violation.userNotMemberOf=Operation ist nur für Benutzer:innen der Gruppe(n) ''{0}'' erlaubt (ggf. auch andere Gruppen möglich).
access.write=Schreibzugriff
-address.accessException.userHasNoRightForAddressbook=Benutzer:in hat keine Berechtigung für die ausgewählte Adresse und dessen Addressbuch
-address.accessException.userIsNotOwnerOfPersonalAddress=Benutzer:in ist nicht Besitzer:in der persönlichen Adresse.
-address.addressbooks=Adressbücher
+address.accessException.userHasNoRightForAddressbook=Benutzer:in hat keine Berechtigung für die ausgewählte Adresse und dessen Addressbuch
+address.accessException.userIsNotOwnerOfPersonalAddress=Benutzer:in ist nicht Besitzer:in der persönlichen Adresse.
+address.addressbooks=Adressbücher
address.addresses=Adressen
address.addressStatus=Adressstatus
address.addressStatus.leaved=Unternehmen verlassen
@@ -476,25 +476,25 @@ address.birthday=Geburtstag
address.birthName=Geburtsname
address.book.export=Excel-Export
address.book.export.appleScript4Notes=Apple-Script
-address.book.export.appleScript4Notes.tooltip=Zum Löschen von Notizen (mit Mehrfacheinträgen) aus den aus ProjectForge exportierten Adressen (s. Handbuch). Anschließend sollten die Adressen erneut importiert werden, um die bereinigten Notizen aus ProjectForge zu importieren.
-address.book.export.tooltip=Exportiert die gefilterten Adressen (nur Favoriten) als Excel-Tabelle mit allen Feldern. Eine Komplettliste kann aus Datenschutzgründen nur über die Finanzbuchhaltung abgerufen werden.
-address.book.hasNoVCards=Es sind keine persönlichen Adressen als Favoriten hinterlegt. Bitte erst Adressen zur persönlichen vCard-Liste hinzufügen.
+address.book.export.appleScript4Notes.tooltip=Zum Löschen von Notizen (mit Mehrfacheinträgen) aus den aus ProjectForge exportierten Adressen (s. Handbuch). Anschließend sollten die Adressen erneut importiert werden, um die bereinigten Notizen aus ProjectForge zu importieren.
+address.book.export.tooltip=Exportiert die gefilterten Adressen (nur Favoriten) als Excel-Tabelle mit allen Feldern. Eine Komplettliste kann aus Datenschutzgründen nur über die Finanzbuchhaltung abgerufen werden.
+address.book.hasNoVCards=Es sind keine persönlichen Adressen als Favoriten hinterlegt. Bitte erst Adressen zur persönlichen vCard-Liste hinzufügen.
address.book.vCardExport=Export vCards
-address.book.vCardExport.tooltip.content=VCards markierter Adressen können für externe Adressprogramme (z. B. Apple Adressbuch) exportiert werden (utf-8 sollte im Adressprogramm eingestellt sein).
-address.book.vCardExport.tooltip.title=Persönliches Adressbuch
+address.book.vCardExport.tooltip.content=VCards markierter Adressen können für externe Adressprogramme (z. B. Apple Adressbuch) exportiert werden (utf-8 sollte im Adressprogramm eingestellt sein).
+address.book.vCardExport.tooltip.title=Persönliches Adressbuch
address.book.vCardImport=Import vCard
address.book.vCardImport.compare=Adressvergleichsseite
address.book.vCardImport.existingEntry=Eintrag ist schon vorhanden.
-address.book.vCardImport.fileUploadPanel=Datei auswählen
-address.book.vCardImport.noFile=Keine Datei ausgewählt!
+address.book.vCardImport.fileUploadPanel=Datei auswählen
+address.book.vCardImport.noFile=Keine Datei ausgewählt!
address.book.vCardImport.title.add=vCard importieren
-address.book.vCardImport.tooltip=Hier Dateipfad einfügen.
+address.book.vCardImport.tooltip=Hier Dateipfad einfügen.
address.book.vCardImport.wrongFileType=Falsches Dateiformat. Bitte nur ".vcf"-Format verwenden.
address.book.vCardSingleExport=Export vCard
-address.business=geschäftlich
+address.business=geschäftlich
address.cardDAV.infopage.description=Der CardDAV-Service von ProjectForge kann genutzt werden, indem ein CardDAV-Account in der Clientsoftware wie z. B. im Apple Adressbuch eingerichtet wird.
-address.cardDAV.infopage.description2=Es werden die persönlichen Favoriten synchronisiert. Wenn Adressen per CardDAV-Client gelöscht werden, so werden die Adressen nicht gelöscht, sondern lediglich als Favorit entfernt.
-address.cardDAV.infopage.description3=Das Anlegen und Editieren von Adressen kann nur direkt in ProjectForge getätigt werden, um Dupletten zu verhindern.
+address.cardDAV.infopage.description2=Es werden die persönlichen Favoriten synchronisiert. Wenn Adressen per CardDAV-Client gelöscht werden, so werden die Adressen nicht gelöscht, sondern lediglich als Favorit entfernt.
+address.cardDAV.infopage.description3=Das Anlegen und Editieren von Adressen kann nur direkt in ProjectForge getätigt werden, um Dupletten zu verhindern.
address.cardDAV.infopage.title=Einrichten des CardDAV-Services
address.city=Stadt
address.columnHead.myFavorites=F
@@ -510,12 +510,12 @@ address.country=Land
address.directCall.call=Anrufen
address.directCall.confirm=Soll jetzt eine Telefonverbindung von Telefon ''{0}'' aus initiiert werden?
address.directCall.destinationPhone=Zielrufnummer
-address.directCall.noPhoneDefined=Es ist kein Telefon ausgewählt (bitte auswählen bzw. unter Mein Zugang festlegen).
-address.directCall.number.tooltip=Anstelle einer Rufnummer können auch Vor- und Nachnamen sowie Firmennamen eingegeben werden oder aus der Adressliste eine Nummer angeklickt werden.
+address.directCall.noPhoneDefined=Es ist kein Telefon ausgewählt (bitte auswählen bzw. unter Mein Zugang festlegen).
+address.directCall.number.tooltip=Anstelle einer Rufnummer können auch Vor- und Nachnamen sowie Firmennamen eingegeben werden oder aus der Adressliste eine Nummer angeklickt werden.
address.division=Bereich
address.emails=E-Mails
-address.error.phone.invalidFormat=Es sind nur Zahlen sowie '+' am Anfang, '-', '/' und Leerzeichen erlaubt. Die führende Ländervorwahl ist zwingend. Beispiel\: +49 561 316793-0
-address.favorites.info=Favoriten können über CardDAV mit einem Adressbuch synchronisiert werden oder als Excel exportiert werden.
+address.error.phone.invalidFormat=Es sind nur Zahlen sowie '+' am Anfang, '-', '/' und Leerzeichen erlaubt. Die führende Ländervorwahl ist zwingend. Beispiel\: +49 561 316793-0
+address.favorites.info=Favoriten können über CardDAV mit einem Adressbuch synchronisiert werden oder als Excel exportiert werden.
address.filter.doublets=Dupletten
address.filter.images=Adressen mit Bildern
address.filter.myFavorites=meine Favoriten
@@ -528,32 +528,32 @@ address.form.miss=Frau
address.form.mister=Herr
address.form.unknown=unbekannt
address.formerly=geb.
-address.heading.businessAddress=Geschäftsadresse
-address.heading.businessContact=Geschäftlicher Kontakt
-address.heading.personalData=Persönliche Daten
+address.heading.businessAddress=Geschäftsadresse
+address.heading.businessContact=Geschäftlicher Kontakt
+address.heading.personalData=Persönliche Daten
address.heading.postalAddress=Briefanschrift
address.heading.postalAddress2=Briefanschrift 2
address.heading.privateAddress=Privatadresse
address.heading.privateAddress2=Privatadresse 2
address.heading.privateContact=Privater Kontakt
address.image=Bild
-address.image.upload.error=Bild kann nicht hochgeladen werden. Bisher wird nur das Bildformat PNG unterstützt mit der Maximalgröße von {0}.
+address.image.upload.error=Bild kann nicht hochgeladen werden. Bisher wird nur das Bildformat PNG unterstützt mit der Maximalgröße von {0}.
address.mailing=Mailing
address.myCurrentCallerId=Anruferkennung
address.myCurrentCallerId.tooltip.content=Diese Anruferkennung wird dem/der Angerufenen angezeigt.
address.myCurrentCallerId.tooltip.title=Direkwahl
address.myCurrentPhoneId=Mein Telefon
-address.myCurrentPhoneId.tooltip.content=Unter Mein Zugang können persönliche Zuordnungen zu firmen-internen Telefonen vorgenommen werden (interne Rufnummer). Wird auf eine Telefonnummer in der Adressliste geklickt, so kann eine Direktwahl für das hier angegebene Telefon initiiert werden.
+address.myCurrentPhoneId.tooltip.content=Unter Mein Zugang können persönliche Zuordnungen zu firmen-internen Telefonen vorgenommen werden (interne Rufnummer). Wird auf eine Telefonnummer in der Adressliste geklickt, so kann eine Direktwahl für das hier angegebene Telefon initiiert werden.
address.myCurrentPhoneId.tooltip.title=Direktwahl
address.phone=Telefon
-address.phoneCall.number.invalid=Ungültige Telefonnummer.
+address.phoneCall.number.invalid=Ungültige Telefonnummer.
address.phoneCall.number.label=Telefonnummer
-address.phoneCall.number.labeldescription=Zu wählen
-address.phoneCall.result.callingError=Fehler beim Wählen.
-address.phoneCall.result.successful=Erfolgreich gewählt.
+address.phoneCall.number.labeldescription=Zu wählen
+address.phoneCall.result.callingError=Fehler beim Wählen.
+address.phoneCall.result.successful=Erfolgreich gewählt.
address.phoneCall.title=Direktwahl Telefonanlage
address.phoneNumbers=Telefonnummern
-address.phoneType.business=Telefon geschäftlich
+address.phoneType.business=Telefon geschäftlich
address.phoneType.fax=Fax
address.phoneType.mobile=Telefon mobil
address.phoneType.private=Telefon privat
@@ -565,13 +565,13 @@ address.private=privat
address.privateAddressText=Privatadresse
address.privateEmail=Private E-Mail
address.publicKey=Public key
-address.question.changeName=Soll der Name der Adresse "{1}, {0}" wirklich geändert werden?
+address.question.changeName=Soll der Name der Adresse "{1}, {0}" wirklich geändert werden?
address.sendSms.doNotReply=Sent by ProjectForge!
address.sendSms.message=Nachricht
address.sendSms.phoneNumber=Mobilfunknummer
-address.sendSms.phoneNumber.info=Hier kann eine Mobilfunknummer eingegeben oder über Namen eine aus dem Adressbuch gesucht werden.
+address.sendSms.phoneNumber.info=Hier kann eine Mobilfunknummer eingegeben oder über Namen eine aus dem Adressbuch gesucht werden.
address.sendSms.sendMessage.result.messageError=Fehler in Nachricht.
-address.sendSms.sendMessage.result.messageToLarge=Nachricht ist größer als 160 Zeichen.
+address.sendSms.sendMessage.result.messageToLarge=Nachricht ist größer als 160 Zeichen.
address.sendSms.sendMessage.result.successful=Nachricht wurde erfolgreich an {0} versendet: {1}
address.sendSms.sendMessage.result.unknownError=Unbekannter Fehler.
address.sendSms.sendMessage.result.wrongOrMissingNumber=Rufnummer fehlerhaft bzw. fehlt.
@@ -584,8 +584,8 @@ address.title.edit=Adresse bearbeiten
address.title.heading=Adressmanagement
address.title.list=Adressliste
address.title.view=Adressansicht
-address.tooltip.phonelist=Die Nummer zur persönlichen Telefonliste hinzufügen.
-address.tooltip.vCardList=Die Adresse zur persönlichen vCard-Liste hinzufügen.
+address.tooltip.phonelist=Die Nummer zur persönlichen Telefonliste hinzufügen.
+address.tooltip.vCardList=Die Adresse zur persönlichen vCard-Liste hinzufügen.
address.tooltip.writeSMS=SMS schreiben
address.view.title=Adresse ansehen
address.website=Webseite
@@ -603,34 +603,34 @@ addressbook.owner=Eigner:in
addressbook.readonlyAccess=Nur lesend
addressbook.readonlyAccess.tooltip=Diese Benutzer:innen haben einen reinen Lesezugriff auf alle Adressen, die diesem Adressbuch zugeordnet sind.
addressbook.title=Titel
-addressbook.title.add=Adressbuch hinzufügen
+addressbook.title.add=Adressbuch hinzufügen
addressbook.title.edit=Adressbuch editieren
addressbook.title.heading=Adressbuch
-addressbook.title.list=Adressbücherliste
+addressbook.title.list=Adressbücherliste
administration.configuration=Konfiguration
-administration.configuration.param.calendarDomain=Kalenderdomäne
-administration.configuration.param.calendarDomain.description=Die Domäne wird vom Teamkalender-Modul benötigt, um weltweit eindeutige Ereignis-IDs zu erzeugen. Verwenden Sie Zeichenketten der Art 'projectforge.my-company.com' und vermeiden Sie nachträgliche Änderungen.
-administration.configuration.param.countryPhonePrefix=Standardländervorwahl
-administration.configuration.param.countryPhonePrefix.description=Wird für die Konvertierung von Telefonnummern genutzt (Standardwert ist +49). Für alle Telefonnummern, die mit diesem Ländercode beginnen wird dieser Prefix durch eine 0 ersetzt (z. B. bei der Funktion Direktwahl). Für alle andere Telefonnummern wird der Ländercode durch 00 und Ländercode ersetzt (+49 123 -> 0123; +31 123 -> 0031123).
+administration.configuration.param.calendarDomain=Kalenderdomäne
+administration.configuration.param.calendarDomain.description=Die Domäne wird vom Teamkalender-Modul benötigt, um weltweit eindeutige Ereignis-IDs zu erzeugen. Verwenden Sie Zeichenketten der Art 'projectforge.my-company.com' und vermeiden Sie nachträgliche Änderungen.
+administration.configuration.param.countryPhonePrefix=Standardländervorwahl
+administration.configuration.param.countryPhonePrefix.description=Wird für die Konvertierung von Telefonnummern genutzt (Standardwert ist +49). Für alle Telefonnummern, die mit diesem Ländercode beginnen wird dieser Prefix durch eine 0 ersetzt (z. B. bei der Funktion Direktwahl). Für alle andere Telefonnummern wird der Ländercode durch 00 und Ländercode ersetzt (+49 123 -> 0123; +31 123 -> 0031123).
administration.configuration.param.dateFormats=Datumsformate
-administration.configuration.param.dateFormats.description=Diese Datumsformate werden unterstützt. Für jede:n Benutzer:in kann ein Format aus dieser komma-separierten Liste ausgewählt werden. Bei der Anlage neue:r Benutzer:in wird der erste Eintrag vorgewählt.
-administration.configuration.param.defaultTask4Books=Standardstrukturelement (Id) für Bücher
+administration.configuration.param.dateFormats.description=Diese Datumsformate werden unterstützt. Für jede:n Benutzer:in kann ein Format aus dieser komma-separierten Liste ausgewählt werden. Bei der Anlage neue:r Benutzer:in wird der erste Eintrag vorgewählt.
+administration.configuration.param.defaultTask4Books=Standardstrukturelement (Id) für Bücher
administration.configuration.param.defaultTask4Books.description=Nicht mehr benutzt.
-administration.configuration.param.excelDateFormats=Datumsformate für Excel
-administration.configuration.param.excelDateFormats.description=Diese Datumsformate werden in Excel-Exporten unterstützt. Für jede:n Benutzer:in kann ein Format aus dieser komma-separierten Liste ausgewählt werden. Bei der Anlage neue:r Benutzer:innen wird der erste Eintrag vorgewählt.
-administration.configuration.param.feedbackEMail=E-Mail für Feedback
-administration.configuration.param.feedbackEMail.description=Wenn diese E-Mail-Adresse angegeben ist, wird ein Feedback-Panel angezeigt, wenn ein Fehler auftritt. Der oder die Anwender:in kann dann eine Feedback-Meldung auslösen (z. B. an ein JIRA-System oder Helpdesk).
+administration.configuration.param.excelDateFormats=Datumsformate für Excel
+administration.configuration.param.excelDateFormats.description=Diese Datumsformate werden in Excel-Exporten unterstützt. Für jede:n Benutzer:in kann ein Format aus dieser komma-separierten Liste ausgewählt werden. Bei der Anlage neue:r Benutzer:innen wird der erste Eintrag vorgewählt.
+administration.configuration.param.feedbackEMail=E-Mail für Feedback
+administration.configuration.param.feedbackEMail.description=Wenn diese E-Mail-Adresse angegeben ist, wird ein Feedback-Panel angezeigt, wenn ein Fehler auftritt. Der oder die Anwender:in kann dann eine Feedback-Meldung auslösen (z. B. an ein JIRA-System oder Helpdesk).
administration.configuration.param.feedbackEMail.label=Feedback
administration.configuration.param.fibu.costConfigured=Kostenkalkulation freigeschaltet?
-administration.configuration.param.fibu.costConfigured.description=Wenn die Kostenkalkulation verwendet werden soll (s. Dokumentation) dann muss diese hier grundsätzlich aktiviert werden. Anschließend sind Entitäten wie Projekte und Kunden nutzbar. Bitte beachten: Die Projektentität ist nur sinnvoll, wenn auch eine Kostenträgerrechnung verwendet werden soll. Andernfalls können die Projekte z. B. über den Strukturbaum ab (Kunde -> Projekt -> Release -> Arbeitspakete ...) abgebildet werden. Eine erneutes Ab- und Wiederanmelden ist ggf. erforderlich, damit das Menü aktualisiert wird.
+administration.configuration.param.fibu.costConfigured.description=Wenn die Kostenkalkulation verwendet werden soll (s. Dokumentation) dann muss diese hier grundsätzlich aktiviert werden. Anschließend sind Entitäten wie Projekte und Kunden nutzbar. Bitte beachten: Die Projektentität ist nur sinnvoll, wenn auch eine Kostenträgerrechnung verwendet werden soll. Andernfalls können die Projekte z. B. über den Strukturbaum ab (Kunde -> Projekt -> Release -> Arbeitspakete ...) abgebildet werden. Eine erneutes Ab- und Wiederanmelden ist ggf. erforderlich, damit das Menü aktualisiert wird.
administration.configuration.param.fibu.defaultVAT=Standardsteuersatz (in %)
-administration.configuration.param.fibu.defaultVAT.description=Wird für die Vorbelegung in Formularen verwendet (z. B. Rechnungseingabe).
+administration.configuration.param.fibu.defaultVAT.description=Wird für die Vorbelegung in Formularen verwendet (z. B. Rechnungseingabe).
administration.configuration.param.hr.emailaddress=HR-E-Mailadresse
-administration.configuration.param.hr.emailaddress.description=Mailadresse von HR für Urlaubseinträge
+administration.configuration.param.hr.emailaddress.description=Mailadresse von HR für Urlaubseinträge
administration.configuration.param.messageOfTheDay=Meldung des Tages
-administration.configuration.param.messageOfTheDay.description=Diese Meldung wird im Logindialog angezeigt. Achtung, sie ist auch für nicht autorisierte Besucher sichtbar\!
-administration.configuration.param.minPasswordLength=Passwortmindestlänge
-administration.configuration.param.minPasswordLength.description=Die Mindestlänge der Benutzer:innenpasswörter.
+administration.configuration.param.messageOfTheDay.description=Diese Meldung wird im Logindialog angezeigt. Achtung, sie ist auch für nicht autorisierte Besucher sichtbar\!
+administration.configuration.param.minPasswordLength=Passwortmindestlänge
+administration.configuration.param.minPasswordLength.description=Die Mindestlänge der Benutzer:innenpasswörter.
administration.configuration.param.organization=Organisation
administration.configuration.param.organization.description=Der Name der Organisation wird auf PDF-Exports (Zeitberichte oder Monatsberichte) als Titel platziert.
administration.configuration.param.password.flag.checkChange=Keine Passwortwiederholung
@@ -638,20 +638,20 @@ administration.configuration.param.password.flag.checkChange.description=Ein neu
administration.configuration.param.pluginsActivated=Aktivierte Plugins
administration.configuration.param.pluginsActivated.description=Liste der aktivierten Plugins. Bitte nicht direkt editieren.
administration.configuration.param.systemAdministratorEMail=E-Mail-Adressen der Systemadministratoren
-administration.configuration.param.systemAdministratorEMail.description=Im schwerwiegenderen Fehlerfalle versendet ProjectForge eine E-Mail an diese Adresse. Es können mehrere Adressen eingegeben werden, getrennt durch Leerzeichen und Kommata (RFC822).
+administration.configuration.param.systemAdministratorEMail.description=Im schwerwiegenderen Fehlerfalle versendet ProjectForge eine E-Mail an diese Adresse. Es können mehrere Adressen eingegeben werden, getrennt durch Leerzeichen und Kommata (RFC822).
administration.configuration.param.systemAdministratorEMail.label=Administrator:innen
-administration.configuration.param.timesheetTags=Tags für Zeitberichte
-administration.configuration.param.timesheetTags.description=Hier können Semikolon-separierte Tags für die Verwendung in Zeitberichten angegeben werden. Diese Tags gelten global.
+administration.configuration.param.timesheetTags=Tags für Zeitberichte
+administration.configuration.param.timesheetTags.description=Hier können Semikolon-separierte Tags für die Verwendung in Zeitberichten angegeben werden. Diese Tags gelten global.
administration.configuration.param.timezone=Standard-Zeitzone
-administration.configuration.param.timezone.description=Diese Zeitzone wird standardmäßig verwendet, wenn nichts anderes angegeben ist. Sie wird auch für neue Nutzer:innen voreingestellt. Wenn nichts konfiguriert ist, wird die Zeitzone des Systems (Java VM) verwendet. Diese Zeitzone kann jederzeit geändert werden, da alle Zeitangaben in der Datenbank im unabhängigen UTC-Format gespeichert werden.
+administration.configuration.param.timezone.description=Diese Zeitzone wird standardmäßig verwendet, wenn nichts anderes angegeben ist. Sie wird auch für neue Nutzer:innen voreingestellt. Wenn nichts konfiguriert ist, wird die Zeitzone des Systems (Java VM) verwendet. Diese Zeitzone kann jederzeit geändert werden, da alle Zeitangaben in der Datenbank im unabhängigen UTC-Format gespeichert werden.
administration.configuration.param.vacation.cal.id=Abwesenheitskalender
-administration.configuration.param.vacation.cal.id.description=Der Abwesenheitskalender für Urlaubseinträge
+administration.configuration.param.vacation.cal.id.description=Der Abwesenheitskalender für Urlaubseinträge
administration.configuration.param.vacation.lastyear.enddate=Endezeitpunkt Vorjahresurlaub
-administration.configuration.param.vacation.lastyear.enddate.description=Endezeitpunkt für Urlaub aus Vorjahr (Format: DD.MM.)
+administration.configuration.param.vacation.lastyear.enddate.description=Endezeitpunkt für Urlaub aus Vorjahr (Format: DD.MM.)
administration.configuration.parameter=Parameter
### not translated: administration.configuration.parameter.pluginsActivated=Activated Plugins
### not translated: administration.configuration.parameter.pluginsActivated.description=List of activated Plugins. Please don't edit directly.
-administration.configuration.title.edit=Konfigurationsparameter ändern
+administration.configuration.title.edit=Konfigurationsparameter ändern
### not translated: administration.configuration.title.heading=Configuration parameter
administration.configuration.title.list=Konfigurationsparameter
administration.configuration.value=Wert
@@ -659,68 +659,68 @@ administration.configuration.value=Wert
### not translated: administration.missingDatabaseIndicesCreated={0} missing data base indices were successful created.
### not translated: administration.refreshCachesDone=Refresh of caches done for: {0}.
administration.reindexFull.successful=Die Voll-Reindizierung war erfolgreich.
-administration.reindexNewest.successful=Die Teil-Reindizierung der neuesten Einträge war erfolgreich.
+administration.reindexNewest.successful=Die Teil-Reindizierung der neuesten Einträge war erfolgreich.
### not translated: administration.rereadConfiguration=Reread of configuration file config.xml: {0}
administration.setup=Einrichten
administration.setup.dumpFile=Dumpfile
administration.setup.error.import=Beim Import trat ein Fehler auf. In den Protokollen finden sich weitere Informationen.
administration.setup.error.uploadfile=Unbekanntes Dateiformat. Diese Datei kann nicht importiert werden.
administration.setup.finish=Fertig stellen
-administration.setup.heading=Herzlichen Glückwunsch, du hast es fast geschafft\!
-administration.setup.heading.subtitle=Danke, dass du ProjectForge gewählt hast.
-administration.setup.message.emptyDatabase=Die Datenbank ist nun für den produktiven Einsatz erfolgreich eingerichtet. Viel Spaß\!
-administration.setup.message.testdata=Die Datenbank ist nun mit Testdaten erfolgreich angelegt. Viel Spaß\!
+administration.setup.heading=Herzlichen Glückwunsch, du hast es fast geschafft\!
+administration.setup.heading.subtitle=Danke, dass du ProjectForge gewählt hast.
+administration.setup.message.emptyDatabase=Die Datenbank ist nun für den produktiven Einsatz erfolgreich eingerichtet. Viel Spaß\!
+administration.setup.message.testdata=Die Datenbank ist nun mit Testdaten erfolgreich angelegt. Viel Spaß\!
administration.setup.target=Zielsystem
administration.setup.target.emptyDatabase=Produktivsystem
-administration.setup.target.emptyDatabase.tooltip=Leere Datenbank (für Produktivsysteme erforderlich)
+administration.setup.target.emptyDatabase.tooltip=Leere Datenbank (für Produktivsysteme erforderlich)
administration.setup.target.testdata=Testsystem
-administration.setup.target.testdata.tooltip=Datenbank mit Testdaten (für Testsysteme)
+administration.setup.target.testdata.tooltip=Datenbank mit Testdaten (für Testsysteme)
administration.setup.title=Erstanmeldung - ProjectForge einrichten
administration.title=Administration
-agGrid.sortInfo=Es können mehrere Spalten sortiert werden, indem die Hochstelltaste beim Anklicken von weiteren Spaltenköpfen gedrückt gehalten wird. Außerdem können Spalten umsortiert und in der Breite verändert werden.
+agGrid.sortInfo=Es können mehrere Spalten sortiert werden, indem die Hochstelltaste beim Anklicken von weiteren Spaltenköpfen gedrückt gehalten wird. Außerdem können Spalten umsortiert und in der Breite verändert werden.
attachment=Anhang
-attachment.checksum=Prüfsumme
-attachment.encrypt=Verschlüsseln
-attachment.encrypt.question=Soll diese Datei nun verschlüsselt werden? Das Passwort wird nicht gespeichert.
-attachment.encryption=Verschlüsselung
-attachment.expires=Löschfrist
+attachment.checksum=Prüfsumme
+attachment.encrypt=Verschlüsseln
+attachment.encrypt.question=Soll diese Datei nun verschlüsselt werden? Das Passwort wird nicht gespeichert.
+attachment.encryption=Verschlüsselung
+attachment.expires=Löschfrist
attachment.fileId=Dateikennung
attachment.fileName=Dateiname
-attachment.fileSize=Dateigröße
+attachment.fileSize=Dateigröße
attachment.info=Info
-attachment.list=Anhänge
-attachment.onlyAvailableAfterSave=Anhänge können erst hochgeladen werden, nachdem dieses Objekt gespeichert wurde.
-attachment.password.info=Dieses Passwort wird ausschließlich zur Verschlüsselung verwendet und nirgends im System gespeichert oder protokolliert.
-attachment.showEncryptionOption=Verschlüsselungsoption
-attachment.size=Dateigröße
-attachment.testDecryption=Entschlüsselung testen
-attachment.testDecryption.failed=Entschlüsselung fehlgeschlagen (falsches Passwort oder ungültiges ZIP-Archiv?)
-attachment.testDecryption.successful=Entschlüsselung erfolgreich.
-attachment.upload.title=Dateien durch Klick auswählen oder Dateien hier hinziehen.
-attachment.zip.encrypted=verschlüsselt
-attachment.zip.encryptedStandard=verschlüsselt (ZIP-Standard)
-attachment.zip.encryptionAlgorithm=Verschlüsselungsalgorithmus
-attachment.zip.encrytpedAes128=verschlüsselt (AES-128)
-attachment.zip.encrytpedAes256=verschlüsselt (AES-256, hohe Sicherheit)
-attachment.zip.standard=ohne Verschlüsselung
-attachments=Anhänge
+attachment.list=Anhänge
+attachment.onlyAvailableAfterSave=Anhänge können erst hochgeladen werden, nachdem dieses Objekt gespeichert wurde.
+attachment.password.info=Dieses Passwort wird ausschließlich zur Verschlüsselung verwendet und nirgends im System gespeichert oder protokolliert.
+attachment.showEncryptionOption=Verschlüsselungsoption
+attachment.size=Dateigröße
+attachment.testDecryption=Entschlüsselung testen
+attachment.testDecryption.failed=Entschlüsselung fehlgeschlagen (falsches Passwort oder ungültiges ZIP-Archiv?)
+attachment.testDecryption.successful=Entschlüsselung erfolgreich.
+attachment.upload.title=Dateien durch Klick auswählen oder Dateien hier hinziehen.
+attachment.zip.encrypted=verschlüsselt
+attachment.zip.encryptedStandard=verschlüsselt (ZIP-Standard)
+attachment.zip.encryptionAlgorithm=Verschlüsselungsalgorithmus
+attachment.zip.encrytpedAes128=verschlüsselt (AES-128)
+attachment.zip.encrytpedAes256=verschlüsselt (AES-256, hohe Sicherheit)
+attachment.zip.standard=ohne Verschlüsselung
+attachments=Anhänge
attachments.short=Anh.
birthday=Geburtstag
book.abstract=Zusammenfassung
book.authors=Autor:innen
-book.books=Bücher
+book.books=Bücher
book.editor=Herausgeber:in
-book.error.number=Im Veröffentlichungsjahr sind nur Zahlen erlaubt
+book.error.number=Im Veröffentlichungsjahr sind nur Zahlen erlaubt
book.error.signatureAlreadyExists=Signatur existiert bereits.
-book.error.toFewFields=Für einen Eintrag sollten weitere Felder ausgefüllt werden.
+book.error.toFewFields=Für einen Eintrag sollten weitere Felder ausgefüllt werden.
book.isbn=ISBN
-book.keywords=Schlüsselworte
+book.keywords=Schlüsselworte
book.lending=Ausleihe
book.lendOut=Ausleihen
book.lendOutBy=Ausgeliehen von
book.lendOutNote=Ausleihnotiz (optional)
book.publisher=Verlag
-book.returnBook=Zurückgeben
+book.returnBook=Zurückgeben
book.signature=Signatur
book.status.disposed=entsorgt
book.status.missed=vermisst
@@ -729,28 +729,28 @@ book.status.unknown=unbekannt
book.title=Titel
book.title.add=Neues Buch
book.title.edit=Buch bearbeiten
-book.title.heading=Bücher
-book.title.list=Bücherliste
+book.title.heading=Bücher
+book.title.list=Bücherliste
book.type=Typ
book.type.article=Artikel
-book.type.audiobook=Hörbuch
+book.type.audiobook=Hörbuch
book.type.book=Buch
book.type.ebook=E-Book
-book.type.film=Film (Datenträger)
+book.type.film=Film (Datenträger)
book.type.magazine=Magazin
book.type.misc=Sonstiges
book.type.newspaper=Zeitung
book.type.periodical=Periodika
-book.type.software=Software (Datenträger)
+book.type.software=Software (Datenträger)
book.type.thesis=Abschlussarbeit
-book.yearOfPublishing=Jahr der Veröffentlichung
+book.yearOfPublishing=Jahr der Veröffentlichung
book.yearOfPublishing.short=Jahr
bookmark.directPageExtendedLink=Direkter Link zu dieser Seite mit Parametern
bookmark.directPageExtendedLink.editPage=Direkter Link zu dieser Seite zur Neuanlage mit vorbelegten Feldern
bookmark.directPageLink=Direkter Link zu dieser Seite
bookmark.title=Seite als Link
-button.fileUploadProxy.label=Auswählen
-calendar.abonnement.url=URL für Abonnement
+button.fileUploadProxy.label=Auswählen
+calendar.abonnement.url=URL für Abonnement
calendar.allday=ganztags
calendar.birthdays.all=Geburtstage
calendar.birthdays.favorites=Geburtstage (Adressfavoriten)
@@ -768,14 +768,14 @@ calendar.dd.copy.save=Kopieren & Speichern
calendar.dd.move.edit=Verschieben & Bearbeiten
calendar.dd.move.save=Verschieben & Speichern
calendar.defaultCalendar=Standardkalender
-calendar.defaultCalendar.tooltip=Der Standardkalender ist der voreingestellte Kalender für neue Einträge.
+calendar.defaultCalendar.tooltip=Der Standardkalender ist der voreingestellte Kalender für neue Einträge.
calendar.filter.dialog.title=Kalendarfilter
-calendar.filter.showCalendarEntries=Kalendereinträge anzeigen
+calendar.filter.showCalendarEntries=Kalendereinträge anzeigen
calendar.filter.untitled=Unbenannt
calendar.filter.vacation.groups=Urlaubskalender Gruppen
-calendar.filter.vacation.groups.tooltip=Für Mitglieder dieser Gruppen werden die Urlaube angezeigt.
+calendar.filter.vacation.groups.tooltip=Für Mitglieder dieser Gruppen werden die Urlaube angezeigt.
calendar.filter.vacation.users=Urlaubskalender Benutzer:in
-calendar.filter.vacation.users.tooltip=Für diese Personen werden die Urlaube angezeigt.
+calendar.filter.vacation.users.tooltip=Für diese Personen werden die Urlaube angezeigt.
calendar.filter.visible=sichtbar
calendar.firstDayOfWeek=Wochenanfang
calendar.holiday.ascension=Christi Himmelfahrt
@@ -785,7 +785,7 @@ calendar.holiday.easterMonday=Ostermontag
calendar.holiday.easterSunday=Ostersonntag
calendar.holiday.firstXmasDay=1. Weihnachtstag
calendar.holiday.goodFriday=Karfreitag
-calendar.holiday.maundyThursday=Gründonnerstag
+calendar.holiday.maundyThursday=Gründonnerstag
calendar.holiday.newYear=Neujahr
calendar.holiday.newYearsEve=Silvester
calendar.holiday.palmSunday=Palmsonntag
@@ -795,7 +795,7 @@ calendar.holiday.shroveTuesday=Faschingsdienstag
calendar.holiday.whitMonday=Pfingstmontag
calendar.holiday.whitSunday=Pfingstsonntag
calendar.holiday.xmasEve=Heiligabend
-calendar.icsExport.securityAdvice=Diese URL enthält deinen persönlichen Anmeldeschlüssel für ProjectForge (er ist verschlüsselt und unabhängig von deinem Passwort). Sollte der Verdacht bestehen, dass diese Daten ggf. Dritten vorliegen, so bitte den 'Schlüssel zur Authentifizierung' unter 'Mein Zugang' erneuern. Andernfalls könnten Dritte ebenfalls diesen Kalender abonnieren.
+calendar.icsExport.securityAdvice=Diese URL enthält deinen persönlichen Anmeldeschlüssel für ProjectForge (er ist verschlüsselt und unabhängig von deinem Passwort). Sollte der Verdacht bestehen, dass diese Daten ggf. Dritten vorliegen, so bitte den 'Schlüssel zur Authentifizierung' unter 'Mein Zugang' erneuern. Andernfalls könnten Dritte ebenfalls diesen Kalender abonnieren.
calendar.month=Monat
calendar.month.april=April
calendar.month.august=August
@@ -804,7 +804,7 @@ calendar.month.february=Februar
calendar.month.january=Januar
calendar.month.july=Juli
calendar.month.june=Juni
-calendar.month.march=März
+calendar.month.march=März
calendar.month.may=Mai
calendar.month.november=November
calendar.month.october=Oktober
@@ -813,15 +813,15 @@ calendar.navigation.today=Heute
calendar.newEntry=Neuer Eintrag
calendar.option.birthdays=Geburtstage
calendar.option.firstHour=Tagesbeginn
-calendar.option.firstHour.tooltip=Die erste Stunde, die in der Wochen- und Tagesansicht standardmäßig angezeigt werden soll. Für neue Zeitberichte wird bei Klick auf den Tag dieser Stundenwert als vorgeschlagener Beginn verwendet.
+calendar.option.firstHour.tooltip=Die erste Stunde, die in der Wochen- und Tagesansicht standardmäßig angezeigt werden soll. Für neue Zeitberichte wird bei Klick auf den Tag dieser Stundenwert als vorgeschlagener Beginn verwendet.
calendar.option.gridSize=Raster in Minuten
-calendar.option.gridSize.tooltip=Die Auflösung des Kalenders in der Wochen- und Tagesansicht.
+calendar.option.gridSize.tooltip=Die Auflösung des Kalenders in der Wochen- und Tagesansicht.
calendar.option.planning=Planung
calendar.option.planning.tooltip=Zeigt geplante Projektzeiten, sofern in der Personalplanung vorgenommen.
calendar.option.showBreaks=Pausen
calendar.option.showBreaks.tooltip=Pausen zwischen den Zeitberichten innerhalb eines Tages anzeigen.
calendar.option.slot30=30
-calendar.option.slot30.tooltip=Setzt die Rastergröße des Kalenders auf 30 Minuten (statt 15).
+calendar.option.slot30.tooltip=Setzt die Rastergröße des Kalenders auf 30 Minuten (statt 15).
calendar.option.statistics=Statistik
calendar.option.statistics.tooltip=Zeigt Kalenderwochen und Summen von Zeitberichten pro Tag/Woche an.
calendar.option.timesheets=Zeitberichte
@@ -842,8 +842,8 @@ calendar.settings.colors.timesheetBreaks=Zeitberichtspausen
calendar.settings.colors.timesheets=Zeitberichte
calendar.settings.colors.timesheetStats=Zeitberichtsstatistiken
calendar.settings.colors.vacations=Urlaube
-calendar.settings.colors.vacations.info=Diese Farbe wird für Urlaube verwendet, die in den Ansichtseinstellungen über das Zahnrad ausgewählt wurden.\n\nWenn verschiedene Farben für verschiedene Urlaube von Teams und/oder Personen gewünscht sind, dann kann leicht ein Urlaubskalender für Gruppen/Personen [hier](/react/teamCal/edit) eingerichtet werden.
-calendar.settings.intro=Beachte: Die Farben von anderen Kalendern kann einfach durch Klicken auf die Pillen in der Kalenderauswahl oben in der Zeile der Kalenderseite verändert werden.
+calendar.settings.colors.vacations.info=Diese Farbe wird für Urlaube verwendet, die in den Ansichtseinstellungen über das Zahnrad ausgewählt wurden.\n\nWenn verschiedene Farben für verschiedene Urlaube von Teams und/oder Personen gewünscht sind, dann kann leicht ein Urlaubskalender für Gruppen/Personen [hier](/react/teamCal/edit) eingerichtet werden.
+calendar.settings.intro=Beachte: Die Farben von anderen Kalendern kann einfach durch Klicken auf die Pillen in der Kalenderauswahl oben in der Zeile der Kalenderseite verändert werden.
calendar.settings.title=Kalendereinstellungen
calendar.shortday.friday=Fr
calendar.shortday.monday=Mo
@@ -854,20 +854,20 @@ calendar.shortday.tuesday=Di
calendar.shortday.wednesday=Mi
calendar.showMore=mehr
calendar.templates.new=Neuer Kalenderfilter
-calendar.templates.new.tooltip=Hier kannst du einen neuen Kalenderfilter unter einem Namen speichern, um schneller zwischen verschiedenen Sichten wechseln zu können.
+calendar.templates.new.tooltip=Hier kannst du einen neuen Kalenderfilter unter einem Namen speichern, um schneller zwischen verschiedenen Sichten wechseln zu können.
calendar.templates.tooltip=Kalenderfilter verwalten
calendar.title=Kalender
calendar.today=Heute
-calendar.tooltip.selectMonth=Ganzen Monat als Zeitraum wählen
-calendar.tooltip.selectNext=Zum nachfolgenden Monat blättern
-calendar.tooltip.selectPrevious=Zum vorangehenden Monat blättern
-calendar.tooltip.selectWeek=Ganze Woche als Zeitraum wählen
-calendar.tooltip.unselectPeriod=Zeitraum löschen
+calendar.tooltip.selectMonth=Ganzen Monat als Zeitraum wählen
+calendar.tooltip.selectNext=Zum nachfolgenden Monat blättern
+calendar.tooltip.selectPrevious=Zum vorangehenden Monat blättern
+calendar.tooltip.selectWeek=Ganze Woche als Zeitraum wählen
+calendar.tooltip.unselectPeriod=Zeitraum löschen
calendar.unit.day=d
calendar.unit.hour=h
calendar.view.agenda=Agenda
calendar.view.oldVersion=Alte Version
-calendar.view.oldVersion.tooltip=Die alte Version wird demnächst entfernt.
+calendar.view.oldVersion.tooltip=Die alte Version wird demnächst entfernt.
calendar.view.overview=Ãœbersicht
calendar.view.settings.tooltip=Einstellungen der Ansicht
calendar.view.workDays=Werktage
@@ -877,21 +877,21 @@ calendar.year=Jahr
common.attention=Achtung!
common.customized=Angepasst
common.import.action.commit=Ãœbernehmen
-common.import.action.commit.error.notReconciled=Die Datensätze, die übernommen werden sollen, sind noch nicht abgeglichen, bitte erst abgleichen.
-common.import.action.commit.tooltip=Hiermit werden alle selektierten Datensätze in die Datenbank übernommen.
-common.import.action.deselectAll=Alle abwählen
+common.import.action.commit.error.notReconciled=Die Datensätze, die übernommen werden sollen, sind noch nicht abgeglichen, bitte erst abgleichen.
+common.import.action.commit.tooltip=Hiermit werden alle selektierten Datensätze in die Datenbank übernommen.
+common.import.action.deselectAll=Alle abwählen
common.import.action.downloadValidatedExcel=validatierte Exceldatei
common.import.action.reconcile=Abgleichen
-common.import.action.reconcile.tooltip=Beim Abgleichen werden alle hochgeladenen Datensätze mit den in der Datenbank bereits vorhandenen Daten verglichen.
-common.import.action.select100=Die ersten 100 Einträge auswählen
-common.import.action.select500=Die ersten 500 Einträge auswählen
-common.import.action.selectAll=Alle auswählen
+common.import.action.reconcile.tooltip=Beim Abgleichen werden alle hochgeladenen Datensätze mit den in der Datenbank bereits vorhandenen Daten verglichen.
+common.import.action.select100=Die ersten 100 Einträge auswählen
+common.import.action.select500=Die ersten 500 Einträge auswählen
+common.import.action.selectAll=Alle auswählen
common.import.action.showErrorLog=Fehlerprotokoll anzeigen
common.import.action.showErrorSummary=Fehlerzusammenfassung anzeigen
common.import.action.showInfoLog=Infoprotokoll anzeigen
common.import.clearStorage=Leeren
-common.import.commitQuestionDialog.heading=Alle ausgewählten Einträge übernehmen?
-common.import.commitQuestionDialog.question=Sollen wirklich alle ausgewählten Einträge übernommen werden? Diese Funktion kann nicht wieder rückgängig gemacht werden.
+common.import.commitQuestionDialog.heading=Alle ausgewählten Einträge übernehmen?
+common.import.commitQuestionDialog.question=Sollen wirklich alle ausgewählten Einträge übernommen werden? Diese Funktion kann nicht wieder rückgängig gemacht werden.
common.import.excel.error=Fehler beim Excelimport: {0} in row {1} and column ''{2}''.
common.import.excel.error1=Falscher Datentyp in Zeile
common.import.excel.error2=Spalte
@@ -905,25 +905,25 @@ common.import.status.imported=importiert
common.import.status.nothingToDo=nichts zu tun
common.import.status.notReconciled=nicht abgeglichen
common.import.status.reconciled=abgeglichen
-common.import.upload.tooltip=Die Daten werden zunächst zur Prüfung hochgeladen. Insbesondere werden sie nicht direkt in die Datenbank geschrieben.
-common.recurrence.frequency.daily=Täglich
-common.recurrence.frequency.hourly=Stündlich
+common.import.upload.tooltip=Die Daten werden zunächst zur Prüfung hochgeladen. Insbesondere werden sie nicht direkt in die Datenbank geschrieben.
+common.recurrence.frequency.daily=Täglich
+common.recurrence.frequency.hourly=Stündlich
common.recurrence.frequency.monthly=Monatlich
common.recurrence.frequency.none=Ohne
-common.recurrence.frequency.weekly=Wöchentlich
-common.recurrence.frequency.yearly=Jährlich
+common.recurrence.frequency.weekly=Wöchentlich
+common.recurrence.frequency.yearly=Jährlich
common.resultholder.error=Fehler
common.resultholder.failed=fehlgeschlagen
common.resultholder.ok=OK
common.resultholder.warning=Warnung
-common.uploadpanel.filetolarge=Die ausgewählte Datei ist zu groß. Die maximale Größe beträgt {0}.
-common.uploadpanel.filewrongtype=Die ausgewählte Datei besitzt ein nicht unterstütztes Dateiformat. Unterstützte Formate: {0}.
+common.uploadpanel.filetolarge=Die ausgewählte Datei ist zu groß. Die maximale Größe beträgt {0}.
+common.uploadpanel.filewrongtype=Die ausgewählte Datei besitzt ein nicht unterstütztes Dateiformat. Unterstützte Formate: {0}.
contact.birthday=Geburtstag
contact.contacts=Adressen
contact.emailValues=E-Mailadressen
contact.firstname=Vorname
contact.form=Anrede
-contact.imValues=Zugänge zu sozialen Medien
+contact.imValues=Zugänge zu sozialen Medien
contact.name=Nchname
contact.phoneValues=Telefonnummern
contact.title=Titel
@@ -931,13 +931,13 @@ contact.title.add=Neue Adresse
contact.title.edit=Adresse bearbeiten
### not translated: contact.title.heading=Address management
contact.title.list=Adressliste
-contact.type.business=geschäftlich
+contact.type.business=geschäftlich
contact.type.other=andere
contact.type.own=eigene
contact.type.postal=postalisch
contact.type.private=privat
contextMenu.cancel=Abbrechen
-contextMenu.newTab=Link in neuem Tab öffnen
+contextMenu.newTab=Link in neuem Tab öffnen
dialog.title.error=Es ist ein Fehler aufgetreten!
dialog.title.information=Information
dialog.title.message=Meldung
@@ -952,29 +952,29 @@ duration.minutes.one=1 Minute
duration.seconds={0} Sekunden
duration.seconds.one=1 Sekunde
### not translated: dvelop.title=D-velop
-error.date.yearOutOfRange=Das Jahr liegt außerhalb des zulässigen Bereichs: ${minimumYear} - ${maximumYear}.
+error.date.yearOutOfRange=Das Jahr liegt außerhalb des zulässigen Bereichs: ${minimumYear} - ${maximumYear}.
error.dateInFuture=Datum darf nicht in der Zukunft liegen.
error.endDateBeforeBeginDate=Das Endedatum darf nicht vor dem Anfangsdatum liegen.
-error.language.unsupported=Sprache wird nicht unterstützt.
-error.notAvailableForLoggedInUsers=Diese Funktion ist für angemeldete Benutzer:innen nicht verfügbar.
+error.language.unsupported=Sprache wird nicht unterstützt.
+error.notAvailableForLoggedInUsers=Diese Funktion ist für angemeldete Benutzer:innen nicht verfügbar.
error.posFromDateBeforeFromDate=Das Anfangsdatum einer Position darf nicht vor dem Anfangsdatum des Auftrages liegen.
-error.timezone.unsupported=Zeitzone wird nicht unterstützt.
-error.yearOutOfRange=Das Jahr liegt außerhalb des zulässigen Bereichs: {0} - {1}.
-errorpage.csrfError=Bitte die Aktion wiederholen, da sich der interne Kommunikationsschlüssel geändert hat. Wenn diese Seite überraschend erschienen ist, nachdem z. B. auf einen E-Mail-Link geklickt wurde, so könnte ein möglicher Angriff namens CSRF die Ursache sein. In diesem Falle bitte die Sicherheitsbeauftragten kontaktieren.
+error.timezone.unsupported=Zeitzone wird nicht unterstützt.
+error.yearOutOfRange=Das Jahr liegt außerhalb des zulässigen Bereichs: {0} - {1}.
+errorpage.csrfError=Bitte die Aktion wiederholen, da sich der interne Kommunikationsschlüssel geändert hat. Wenn diese Seite überraschend erschienen ist, nachdem z. B. auf einen E-Mail-Link geklickt wurde, so könnte ein möglicher Angriff namens CSRF die Ursache sein. In diesem Falle bitte die Sicherheitsbeauftragten kontaktieren.
errorpage.feedback.description=Fehlerbeschreibung (optional)
errorpage.feedback.messageNumber=Fehlernummer
errorpage.feedback.placeholder=Bitte hier beschreiben, wie es zum Fehlverhalten kam.
errorpage.title=Ein Fehler ist aufgetreten.
errorpage.unknownError=Ein interner Fehler ist aufgetreten.
-exception.constraintViolation=Es trat eine Verletzung der Datenintegrität in der Datenbank auf. Dies kann daran liegen, dass z. B. der aktuelle Datensatz mit einem anderen (ggf. auch gelöschten) kollidiert.
-exception.flowscope.notExists=Flow existiert nicht (vielleicht auf Grund einer Zeitüberschreitung). Bitte nochmals versuchen.
+exception.constraintViolation=Es trat eine Verletzung der Datenintegrität in der Datenbank auf. Dies kann daran liegen, dass z. B. der aktuelle Datensatz mit einem anderen (ggf. auch gelöschten) kollidiert.
+exception.flowscope.notExists=Flow existiert nicht (vielleicht auf Grund einer Zeitüberschreitung). Bitte nochmals versuchen.
exception.internalError=Es ist ein interner Fehler aufgetreten. Dieser wurde protokolliert.
exception.luceneParseError=Fehler bei der Vearbeitung des Suchtextes: {0}
exception.pleaseContactDeveloperTeam=Interner Fehler, bitte die Entwickler:innen informieren. Die Fehlerkennung in den Fehlerprotokollen lautet #{0}.
-exception.scriptError=Fehler bei der Script-Ausführung\: {0}
+exception.scriptError=Fehler bei der Script-Ausführung\: {0}
feedback.link.tooltip=Feedback senden
-feedback.mailSendSuccessful=Eine E-Mail wurde erfolgreich versendet. Vielen Dank für die Mithilfe\!
-feedback.receiver=Empfänger:in
+feedback.mailSendSuccessful=Eine E-Mail wurde erfolgreich versendet. Vielen Dank für die Mithilfe\!
+feedback.receiver=Empfänger:in
feedback.send.title=Feedback senden
feedback.sender=Sender:in
fibu.amountType.all=alle
@@ -983,7 +983,7 @@ fibu.amountType.debit=Debit
fibu.attachment=Anlagen
fibu.auftrag=Auftrag
fibu.auftrag.angebot.datum=Angebotsdatum
-fibu.auftrag.auftraege=Aufträge
+fibu.auftrag.auftraege=Aufträge
fibu.auftrag.beauftragungsdatum=Beauftragungsdatum
fibu.auftrag.bindungsFrist=Bindungsfrist
fibu.auftrag.commissioned=beauftragt
@@ -991,21 +991,21 @@ fibu.auftrag.datum=Angebotsdatum
fibu.auftrag.datum.short=Datum
fibu.auftrag.entscheidung.datum=Entscheidungsdatum
fibu.auftrag.erfassung.datum=Erfassungsdatum
-fibu.auftrag.error.amountsInPaymentScheduleAreGreaterThanNetSumOfPosition=Die Summe der Beträge von Position {0} im Zahlplan übersteigt die Nettosumme dieser Position.
+fibu.auftrag.error.amountsInPaymentScheduleAreGreaterThanNetSumOfPosition=Die Summe der Beträge von Position {0} im Zahlplan übersteigt die Nettosumme dieser Position.
fibu.auftrag.error.auftragHatKeinePositionen=Der Auftrag hat keine Auftragspositionen.
fibu.auftrag.error.datesInPaymentScheduleNotWithinPeriodOfPerformanceOfPosition=Mindestens ein Datum des Zahlplans zu (den) Position(en) {0} liegt nicht im Leistungszeitraum (plus 3 Monate).
-fibu.auftrag.error.invalidPosition=Ungültige Auftragsposition.
+fibu.auftrag.error.invalidPosition=Ungültige Auftragsposition.
fibu.auftrag.error.nummerBereitsVergeben=Die Auftragsnummer ist bereits vergeben.
-fibu.auftrag.error.nummerIstNichtFortlaufend=Die Auftragsnummer ist nicht die nächstfolgende (nicht fortlaufend).
-fibu.auftrag.error.nurAbgeschlosseneAuftragsPositionenKoennenVollstaendigFakturiertSein=Nur abgeschlossene Auftragspositionen können vollständig fakturiert sein.
-fibu.auftrag.error.vollstaendigFakturiertProtection=Das Flag "vollständig fakturiert" darf nur durch die Buchhaltung manipuliert werden.
+fibu.auftrag.error.nummerIstNichtFortlaufend=Die Auftragsnummer ist nicht die nächstfolgende (nicht fortlaufend).
+fibu.auftrag.error.nurAbgeschlosseneAuftragsPositionenKoennenVollstaendigFakturiertSein=Nur abgeschlossene Auftragspositionen können vollständig fakturiert sein.
+fibu.auftrag.error.vollstaendigFakturiertProtection=Das Flag "vollständig fakturiert" darf nur durch die Buchhaltung manipuliert werden.
fibu.auftrag.ersetzen=Ersetzen
fibu.auftrag.filter.type.all=alle
-fibu.auftrag.filter.type.nochNichtVollstaendigFakturiert=noch nicht vollständig fakturiert
-fibu.auftrag.filter.type.vollstaendigFakturiert=vollständig fakturiert
+fibu.auftrag.filter.type.nochNichtVollstaendigFakturiert=noch nicht vollständig fakturiert
+fibu.auftrag.filter.type.vollstaendigFakturiert=vollständig fakturiert
fibu.auftrag.filter.type.zuFakturieren=zu fakturieren
fibu.auftrag.forecastExportAsXls=Forecast
-fibu.auftrag.forecastExportAsXls.tooltip=Export des Forecasts für die aktuelle Auftragsliste. Das Startdatum wird aus dem Leistungszeitraum Start Filter verwendet. Wenn nicht angegeben wird der 01.01.[aktuelles Jahr] verwendet.
+fibu.auftrag.forecastExportAsXls.tooltip=Export des Forecasts für die aktuelle Auftragsliste. Das Startdatum wird aus dem Leistungszeitraum Start Filter verwendet. Wenn nicht angegeben wird der 01.01.[aktuelles Jahr] verwendet.
fibu.auftrag.hint.kannVonProjektKundenAbweichen=Kunde kann vom Projektkunden abweichen.
fibu.auftrag.invoice.info=, fakturiert: {0}, noch nicht fakturiert: {1}
fibu.auftrag.mail.intro=der Auftrag #{0} wurde geändert bzw. angelegt.
@@ -1056,14 +1056,14 @@ fibu.auftrag.title.add=Neuer/s Auftrag/Angebot
fibu.auftrag.title.edit=Auftrag/Angebot bearbeiten
fibu.auftrag.title.heading=Auftragsmanagement
fibu.auftrag.title.list=Auftrags- und Angebotsbuch
-fibu.auftrag.tooltip.addPaymentschedule=Zahlplanposition hinzufügen
-fibu.auftrag.tooltip.addPosition=Auftragsposition hinzufügen
+fibu.auftrag.tooltip.addPaymentschedule=Zahlplanposition hinzufügen
+fibu.auftrag.tooltip.addPosition=Auftragsposition hinzufügen
fibu.auftrag.type=Typ
-fibu.auftrag.vollstaendigFakturiert=vollständig fakturiert
+fibu.auftrag.vollstaendigFakturiert=vollständig fakturiert
fibu.auftrag.zahlung=Zahlung
-fibu.buchungssaetze=Buchungssätze
+fibu.buchungssaetze=Buchungssätze
fibu.buchungssatz.beleg=Beleg
-fibu.buchungssatz.error.invalidTimeperiod=Ungültige Zeitraumangabe
+fibu.buchungssatz.error.invalidTimeperiod=Ungültige Zeitraumangabe
fibu.buchungssatz.gegenKonto=Gegenkonto
fibu.buchungssatz.konto=Konto
fibu.buchungssatz.menge=Menge
@@ -1071,12 +1071,12 @@ fibu.buchungssatz.satznr=Satznummer
fibu.buchungssatz.text=Text
fibu.buchungssatz.title.add=Neuer Buchungssatz
fibu.buchungssatz.title.edit=Buchungssatz bearbeiten
-fibu.buchungssatz.title.heading=Buchungssätze
-fibu.buchungssatz.title.list=Liste der Buchungssätze
+fibu.buchungssatz.title.heading=Buchungssätze
+fibu.buchungssatz.title.list=Liste der Buchungssätze
fibu.businessAssessment=BWA
fibu.businessAssessment.merchandisePurchase=Mat./Wareneinkauf
fibu.businessAssessment.overallPerformance=Gesamtleistung
-fibu.businessAssessment.preliminaryResult=Vorläufiges Ergebnis
+fibu.businessAssessment.preliminaryResult=Vorläufiges Ergebnis
fibu.common.assignedPersons=PL/BUL/KAM/AP
fibu.common.betrag=Betrag
fibu.common.brutto=Brutto
@@ -1120,13 +1120,13 @@ fibu.employee.error.employeWithUserExists=Es existiert bereits ein:e Mitarbeiter
fibu.employee.iban=IBAN
fibu.employee.iststunden=Iststunden
fibu.employee.panel.error.employeeNotFound=Mitarbeiter:in nicht gefunden.
-fibu.employee.salaries=Gehälter
+fibu.employee.salaries=Gehälter
fibu.employee.salary=Gehaltszahlung
fibu.employee.salary.agAnteil=AG-Anteil
fibu.employee.salary.bruttoMitAgAnteil=Brutto mit AG-Anteil
-fibu.employee.salary.error.monthNotGiven=Ein Monat muss ausgewählt werden.
-fibu.employee.salary.error.salaryAlreadyExist=Das Monatsgehalt für diese:n Mitarbeiter:in existiert bereits.
-fibu.employee.salary.exportXls.tooltip=Gehaltsexport mit Kostenträgerzuweisungen gemäß der Zeitberichtsbuchungen.
+fibu.employee.salary.error.monthNotGiven=Ein Monat muss ausgewählt werden.
+fibu.employee.salary.error.salaryAlreadyExist=Das Monatsgehalt für diese:n Mitarbeiter:in existiert bereits.
+fibu.employee.salary.exportXls.tooltip=Gehaltsexport mit Kostenträgerzuweisungen gemäß der Zeitberichtsbuchungen.
fibu.employee.salary.id=Gehalts-ID
fibu.employee.salary.title.add=Neue Gehaltszahlung
fibu.employee.salary.title.edit=Gehaltszahlung bearbeiten
@@ -1134,7 +1134,7 @@ fibu.employee.salary.title.heading=Gehaltszahlungen
fibu.employee.salary.title.list=Gehaltsliste
fibu.employee.salary.type=Zahlungstyp
fibu.employee.salary.type.gehalt=Gehalt
-fibu.employee.salary.type.praemie=Prämie
+fibu.employee.salary.type.praemie=Prämie
fibu.employee.salary.type.sonderzahlung=Sonderzahlung
fibu.employee.salary.type.tantieme=Tantieme
fibu.employee.salary.type.zielvereinbarung=Zielvereinbarung
@@ -1150,7 +1150,7 @@ fibu.employee.status.freelancer=Freelancer:in
fibu.employee.status.praktikant=Praktikant:in
fibu.employee.status.studentischeAbschlussarbeit=Studentische Abschlussarbeit
fibu.employee.status.studentischeHilfskraft=Studentische Hilfskraft
-fibu.employee.street=Straße
+fibu.employee.street=Straße
fibu.employee.title.add=Neue:r Mitarbeiter:in
fibu.employee.title.edit=Mitarbeiter:in bearbeiten
fibu.employee.title.heading=Mitarbeiter:in
@@ -1165,7 +1165,7 @@ fibu.fakturiert.not=nicht fakturiert
fibu.headOfBusinessManager=Management Business Unit
fibu.konto=Konto
fibu.konto.bezeichnung=Bezeichnung
-fibu.konto.error.invalidKonto=Ungültiges Konto.
+fibu.konto.error.invalidKonto=Ungültiges Konto.
fibu.konto.konten=Konten
fibu.konto.nummer=Kontonummer
fibu.konto.status.active=aktiv
@@ -1175,9 +1175,9 @@ fibu.konto.title.edit=Konto bearbeiten
fibu.konto.title.heading=Buchungskonten
fibu.konto.title.list=Liste der Konten
fibu.konto.validate.duplicate=Ein Konto mit der angegeben Nummer existiert bereits
-fibu.kost.error.collision=Kollision mit bereits vorhandenem Kostenträger.
-fibu.kost.error.invalidKost=Ungültiger Kostenträger.
-fibu.kost.kostentraeger=Kostenträger
+fibu.kost.error.collision=Kollision mit bereits vorhandenem Kostenträger.
+fibu.kost.error.invalidKost=Ungültiger Kostenträger.
+fibu.kost.kostentraeger=Kostenträger
fibu.kost.reporting=Reporting
fibu.kost.reporting.clearStorage=Leeren
fibu.kost.reporting.createReport=Report erstellen
@@ -1189,16 +1189,16 @@ fibu.kost1=Kost1
fibu.kost1.art=Art
fibu.kost1.id=Kost1-ID
fibu.kost1.kost1s=Kost1s
-fibu.kost1.list.select.title=Kost1 wählen
+fibu.kost1.list.select.title=Kost1 wählen
fibu.kost1.number=Kost1-Nummer
fibu.kost1.title.add=Neue Kost1
fibu.kost1.title.edit=Kost1 bearbeiten
fibu.kost1.title.heading=Kost1
fibu.kost1.title.list=Liste der Kost1s
-fibu.kost1.title.list.select=Kost1 wählen
+fibu.kost1.title.list.select=Kost1 wählen
fibu.kost2=Kost2
fibu.kost2.art=Art
-fibu.kost2.error.projektNeededForNummernkreis=Das Projekt muss für die Nummernkreise 4 und 5 zwingend angegeben sein.
+fibu.kost2.error.projektNeededForNummernkreis=Das Projekt muss für die Nummernkreise 4 und 5 zwingend angegeben sein.
fibu.kost2.id=Kost2-ID
fibu.kost2.kost2s=Kost2s
fibu.kost2.number=Kost2-Nummer
@@ -1206,7 +1206,7 @@ fibu.kost2.title.add=Neue Kost2
fibu.kost2.title.edit=Kost2 bearbeiten
fibu.kost2.title.heading=Kost2
fibu.kost2.title.list=Liste der Kost2s
-fibu.kost2.title.list.select=Kost2 wählen
+fibu.kost2.title.list.select=Kost2 wählen
fibu.kost2.workFraction=Arbeitszeitanteil
fibu.kost2art.error.notFound=Kost2-Art existiert nicht.
fibu.kost2art.kost2arten=Kost2-Arten
@@ -1223,10 +1223,10 @@ fibu.kunde.division=Bereich
fibu.kunde.identifier=Kurzbezeichner
fibu.kunde.konto.tooltip=Dieses Konto wird bei einem Export von Debitorenrechnungen mit ausgegeben, sofern im konkreten Projekt, welches der Rechnung evtl. zugewiesen ist, kein anderes Konto angegeben ist.
fibu.kunde.kunden=Kunden
-fibu.kunde.list.select.title=Kunde wählen
+fibu.kunde.list.select.title=Kunde wählen
fibu.kunde.name=Kundenname
fibu.kunde.nummer=Kundennummer
-fibu.kunde.pleaseSelectKunde=Bitte Kunde wählen
+fibu.kunde.pleaseSelectKunde=Bitte Kunde wählen
fibu.kunde.select=Auswahl Kunde
fibu.kunde.status.acquisition=Akquise
fibu.kunde.status.active=aktiv
@@ -1238,18 +1238,18 @@ fibu.kunde.title.add=Neuer Kunde
fibu.kunde.title.edit=Kunde bearbeiten
fibu.kunde.title.heading=Kunden
fibu.kunde.title.list=Kunden
-fibu.kunde.title.list.select=Kunde auswählen
+fibu.kunde.title.list.select=Kunde auswählen
fibu.kunde.validation.existingCustomerNr=Es existiert bereits ein Kunde mit dieser Kundennummer
-fibu.kunde.wizard.notYetAvailable=Der Assistent ist noch nicht verfügbar. Bitte beachten\: Kundenobjekte werden aktuell nur und nur für Kostenträgerrechnungen benötigt (s. Dokumentation). Bitte benutzen Sie den Strukturbaum, um eine Kunden-Projekt-Hierarchie abzubilden.
+fibu.kunde.wizard.notYetAvailable=Der Assistent ist noch nicht verfügbar. Bitte beachten\: Kundenobjekte werden aktuell nur und nur für Kostenträgerrechnungen benötigt (s. Dokumentation). Bitte benutzen Sie den Strukturbaum, um eine Kunden-Projekt-Hierarchie abzubilden.
fibu.kundeProjekt=Kunde/Projekt
-fibu.modeOfPayment.type.annual=jährlich
+fibu.modeOfPayment.type.annual=jährlich
fibu.modeOfPayment.type.fixed=fix
fibu.modeOfPayment.type.monthly=monatlich
fibu.modeOfPayment.type.quarterly=quartalsweise
fibu.monthlyEmployeeReport.daysCountWithoutTimesheets=Anzahl AT ohne Zeitberichte
fibu.monthlyEmployeeReport.daysWithoutTimesheets=AT ohne Zeitberichte
fibu.monthlyEmployeeReport.totalSum=Bruttoarbeitszeit
-fibu.monthlyEmployeeReport.totalSum.tooltip=Die Bruttoarbeitszeit kann von der Summe abweichen, wenn für bestimmte Kostenarten nur ein Anteil als Arbeitszeit gerechnet wird.
+fibu.monthlyEmployeeReport.totalSum.tooltip=Die Bruttoarbeitszeit kann von der Summe abweichen, wenn für bestimmte Kostenarten nur ein Anteil als Arbeitszeit gerechnet wird.
fibu.monthlyEmployeeReport.withoutTimesheets=ohne Zeitberichte
fibu.notYetInvoiced=noch nicht fakturiert
fibu.payment.type=Zahlungsart
@@ -1273,13 +1273,13 @@ fibu.projekt=Projekt
fibu.projekt.edit.kost2DoesAlreadyExists=Kost2 existiert bereits.
fibu.projekt.identifier=Kurzbezeichner
fibu.projekt.internKost2_4=Intern: Koststellen 2-4
-fibu.projekt.konto.tooltip=Wird für den Export von Debitorenrechnungen verwendet. Wenn kein Konto angegeben, wird ein evtl. vorhandenes Konto des diesem Projekt zugeordneten Kundens verwendet.
+fibu.projekt.konto.tooltip=Wird für den Export von Debitorenrechnungen verwendet. Wenn kein Konto angegeben, wird ein evtl. vorhandenes Konto des diesem Projekt zugeordneten Kundens verwendet.
fibu.projekt.leiter=Projektmanagement
-fibu.projekt.list.select.title=Projekt wählen
+fibu.projekt.list.select.title=Projekt wählen
fibu.projekt.multiselected.title=Mehrfachauswahl Projekte
fibu.projekt.name=Name
fibu.projekt.nummer=Nummer
-fibu.projekt.pleaseSelectProjekt=Bitte Projekt wählen
+fibu.projekt.pleaseSelectProjekt=Bitte Projekt wählen
fibu.projekt.projekte=Projekte
fibu.projekt.projektManagerGroup=Projektmanagergruppe
fibu.projekt.status.acquisition=Akquise
@@ -1287,15 +1287,15 @@ fibu.projekt.status.build=Entwicklungsphase
fibu.projekt.status.ended=beendet
fibu.projekt.status.maintenance=Wartung
fibu.projekt.status.none=Nicht gesetzt.
-fibu.projekt.status.onhold=vorrübergehend (noch) nicht aktiv
+fibu.projekt.status.onhold=vorrübergehend (noch) nicht aktiv
fibu.projekt.status.productive=produktiv (ohne Wartung)
fibu.projekt.title.add=Neues Projekt
fibu.projekt.title.edit=Projekt bearbeiten
fibu.projekt.title.heading=Projekte
fibu.projekt.title.list=Projekte
-fibu.projekt.title.list.select=Projekt auswählen
-fibu.projekt.validation.numbernotfreeforcustomer=Nummer bereits für anderes Kundenprojekt vergeben
-fibu.projekt.wizard.notYetAvailable=Der Assistent ist noch nicht verfügbar. Bitte beachten\: Projektobjekte werden aktuell nur und nur für Kostenträgerrechnungen benötigt (s. Dokumentation). Bitte benutzen Sie den Strukturbaum, um eine Kunden-Projekt-Hierarchie abzubilden.
+fibu.projekt.title.list.select=Projekt auswählen
+fibu.projekt.validation.numbernotfreeforcustomer=Nummer bereits für anderes Kundenprojekt vergeben
+fibu.projekt.wizard.notYetAvailable=Der Assistent ist noch nicht verfügbar. Bitte beachten\: Projektobjekte werden aktuell nur und nur für Kostenträgerrechnungen benötigt (s. Dokumentation). Bitte benutzen Sie den Strukturbaum, um eine Kunden-Projekt-Hierarchie abzubilden.
fibu.rechnung=Debitorenrechnung
fibu.rechnung.beschreibung=Beschreibung
fibu.rechnung.besonderheiten=Besonderheiten
@@ -1308,38 +1308,38 @@ fibu.rechnung.customernr=Kundennummer
fibu.rechnung.datum=Rechnungsdatum
fibu.rechnung.datum.short=Datum
fibu.rechnung.discount=Skonto (Datum und %-Wert)
-fibu.rechnung.discountMaturity=Skonto Fälligkeit
+fibu.rechnung.discountMaturity=Skonto Fälligkeit
fibu.rechnung.discountPercent=Skonto Prozent
-fibu.rechnung.error.bezahlDatumRequired=Wenn der Zahlbetrag gegeben ist muss auch das zugehörige Bezahldatum eingegeben sein.
+fibu.rechnung.error.bezahlDatumRequired=Wenn der Zahlbetrag gegeben ist muss auch das zugehörige Bezahldatum eingegeben sein.
fibu.rechnung.error.gutschriftsanzeigeDarfKeineRechnungsnummerHaben=Eine Gutschriftsanzeige durch den Kunden hat keine Rechnungsnummer.
-fibu.rechnung.error.kundeTextOderProjektRequired=Ein Kundentext oder ein Projekt müssen angegeben sein.
+fibu.rechnung.error.kundeTextOderProjektRequired=Ein Kundentext oder ein Projekt müssen angegeben sein.
fibu.rechnung.error.negativAmount=Bei Ãœberweisung kann kein negativer Brutto-Betrag existieren
fibu.rechnung.error.rechnungHatKeinePositionen=Die Rechnung hat keine Rechnungspositionen.
fibu.rechnung.error.rechnungsNummerBereitsVergeben=Die Rechnungsnummer ist bereits vergeben.
-fibu.rechnung.error.rechnungsNummerIstNichtFortlaufend=Die Rechnungsnummer ist nicht die nächstfolgende (nicht fortlaufend).
+fibu.rechnung.error.rechnungsNummerIstNichtFortlaufend=Die Rechnungsnummer ist nicht die nächstfolgende (nicht fortlaufend).
fibu.rechnung.error.statusBezahltErfordertZahlBetrag=Die Rechnung kann nur auf "bezahlt" gesetzt werden, wenn auch ein Zahlbetrag eingetragen wurde.
-fibu.rechnung.error.zahlbetragRequired=Wenn das Bezahldatum gegeben ist muss auch der zugehörige Zahlbetrag eingegeben sein.
+fibu.rechnung.error.zahlbetragRequired=Wenn das Bezahldatum gegeben ist muss auch der zugehörige Zahlbetrag eingegeben sein.
fibu.rechnung.exportInvoice=Rechnung exportieren
-fibu.rechnung.faelligkeit=Fälligkeit
-fibu.rechnung.faelligkeit.short=Fällig
-fibu.rechnung.filter.ueberfaellig=überfällig
+fibu.rechnung.faelligkeit=Fälligkeit
+fibu.rechnung.faelligkeit.short=Fällig
+fibu.rechnung.filter.ueberfaellig=überfällig
fibu.rechnung.filter.unbezahlt=unbezahlt
-fibu.rechnung.hint.kannVonProjektKundenAbweichen=Rechnungsempfänger kann vom Projektkunden abweichen.
+fibu.rechnung.hint.kannVonProjektKundenAbweichen=Rechnungsempfänger kann vom Projektkunden abweichen.
fibu.rechnung.iban=IBAN
-fibu.rechnung.konto.tooltip=Wird für den Export von Debitorenrechnungen verwendet. Wenn kein Konto angegeben, wird ein evtl. vorhandenes Konto des dieser Rechnung zugeordneten Projekts bzw. Kundens verwendet.
+fibu.rechnung.konto.tooltip=Wird für den Export von Debitorenrechnungen verwendet. Wenn kein Konto angegeben, wird ein evtl. vorhandenes Konto des dieser Rechnung zugeordneten Projekts bzw. Kundens verwendet.
fibu.rechnung.kostExcelExport=Kostenzuweisungen exportieren
-fibu.rechnung.kostExcelExport.tootlip=Excel-Export aller Rechnungen für den gewählten Zeitraum im Excel-Format inklusive der Kostenträgerzuweisungen.
+fibu.rechnung.kostExcelExport.tootlip=Excel-Export aller Rechnungen für den gewählten Zeitraum im Excel-Format inklusive der Kostenträgerzuweisungen.
fibu.rechnung.kostZuweisungFehlbetrag=Kostzuweisungfehlbetrag
fibu.rechnung.mehrwertSteuerSatz=Mwst-Satz
fibu.rechnung.menge=Menge
fibu.rechnung.mitSkonto=mit Skonto
-fibu.rechnung.multiselected.info=Wenn das Bezahldatum ausgewählt ist werden alle Einträge auf bezahlt gesetzt. Der Bezahltbetrag wird ebenfalls gesetzt. Wenn der Betrag gelöscht werden soll, wird auch der Zahlbetrag gelöscht.
+fibu.rechnung.multiselected.info=Wenn das Bezahldatum ausgewählt ist werden alle Einträge auf bezahlt gesetzt. Der Bezahltbetrag wird ebenfalls gesetzt. Wenn der Betrag gelöscht werden soll, wird auch der Zahlbetrag gelöscht.
fibu.rechnung.multiselected.title=Mehrfachauswahl Rechnungen
fibu.rechnung.nummer=Nummer
fibu.rechnung.nummer.short=Nr.
fibu.rechnung.offen=Offen
fibu.rechnung.position.einzelNetto=Einzelnettopreis
-fibu.rechnung.receiver=Empfänger
+fibu.rechnung.receiver=Empfänger
fibu.rechnung.rechnungen=Debitorenrechnungen
fibu.rechnung.showEditableKostZuweisungen=Kostzuweisungen editieren
fibu.rechnung.showKostZuweisungen=Kostzuweisungen
@@ -1359,11 +1359,11 @@ fibu.rechnung.title.add=Neue Debitorenrechnung
fibu.rechnung.title.edit=Debitorenrechnung bearbeiten
fibu.rechnung.title.heading=Debitorenrechnungen
fibu.rechnung.title.list=Debitorenrechnungsliste
-fibu.rechnung.tooltip.addPosition=Rechnungsposition hinzufügen
+fibu.rechnung.tooltip.addPosition=Rechnungsposition hinzufügen
fibu.rechnung.transferExport=Ãœberweisungen exportieren
-fibu.rechnung.transferExport.error=Während des Exportes der Überweisung ist ein unerwarteter Fehler aufgetreten.
-fibu.rechnung.transferExport.error.entries=Export aufgrund fehlender oder ungültiger Angaben in den folgenden Rechnungen nicht möglich: {0}.
-fibu.rechnung.transferExport.error.missing=Export aufgrund fehlender oder ungültiger Angaben in den folgenden Feldern nicht möglich: {0}.
+fibu.rechnung.transferExport.error=Während des Exportes der Ãœberweisung ist ein unerwarteter Fehler aufgetreten.
+fibu.rechnung.transferExport.error.entries=Export aufgrund fehlender oder ungültiger Angaben in den folgenden Rechnungen nicht möglich: {0}.
+fibu.rechnung.transferExport.error.missing=Export aufgrund fehlender oder ungültiger Angaben in den folgenden Feldern nicht möglich: {0}.
fibu.rechnung.transferExport.tootlip=Export der Ãœberweisung dieser Rechnung im pain.001.003.03-Format.
fibu.rechnung.typ=Typ
fibu.rechnung.typ.cancellation=Storno
@@ -1372,7 +1372,7 @@ fibu.rechnung.typ.rechnung=Rechnung
fibu.rechnung.zahlBetrag=Zahlbetrag
fibu.rechnung.zahlBetrag.short=Bezahlt
fibu.rechnung.zahlungsZiel=Zahlungsziel
-fibu.rechnung.zahlungsZiel.actual=Tatsächliches Zahlungsziel
+fibu.rechnung.zahlungsZiel.actual=Tatsächliches Zahlungsziel
fibu.rechnungen=Debitorenrechnungen
fibu.reporting.duplicates=Dubletten
fibu.reporting.other=Sonstige
@@ -1382,16 +1382,16 @@ fibu.title.fakturiert=Fakturiert
fibu.title.fakturiert.not=Nicht fakturiert
fibu.toBeInvoiced=zu fakturieren
fibu.tooltip.nummerWirdAutomatischVergeben=Nummer wird automatisch vergeben.
-fibu.tooltip.selectKost1=Kost1 wählen
-fibu.tooltip.selectKost2=Kost2 wählen
-fibu.tooltip.selectKunde=Kunde wählen
-fibu.tooltip.selectProjekt=Projekt wählen
+fibu.tooltip.selectKost1=Kost1 wählen
+fibu.tooltip.selectKost2=Kost2 wählen
+fibu.tooltip.selectKunde=Kunde wählen
+fibu.tooltip.selectProjekt=Projekt wählen
fibu.tooltip.unselectKost1=Kost1-Auswahl aufheben
fibu.tooltip.unselectKost2=Kost2-Auswahl aufheben
fibu.tooltip.unselectKunde=Kundenauswahl aufheben
fibu.tooltip.unselectProjekt=Projektauswahl aufheben
-file.panel.deleteExistingFile.heading=Datei wirklich löschen?
-file.panel.deleteExistingFile.question=Soll die vorhandene Datei wirklich gelöscht bzw. überschrieben werden?
+file.panel.deleteExistingFile.heading=Datei wirklich löschen?
+file.panel.deleteExistingFile.question=Soll die vorhandene Datei wirklich gelöscht bzw. überschrieben werden?
finance.accountingRecord.dc=SH
finance.accountingRecord.dc.credit=Haben
finance.accountingRecord.dc.debit=Soll
@@ -1403,17 +1403,17 @@ form.ajaxEditableLabel.tooltip=Zum Editieren bitte anklicken.
gantt.access.all=Alle
gantt.access.owner=Eigner:in
gantt.access.projectmanager=Projektmanager
-gantt.action.move=Verschieben (Unteraktivität)
-gantt.action.moveToTop=Verschieben (als Hauptaktivität)
-gantt.action.newActivity=Neue Aktivität
-gantt.contextMenu.newSubActivity=Neue Unteraktivität
+gantt.action.move=Verschieben (Unteraktivität)
+gantt.action.moveToTop=Verschieben (als Hauptaktivität)
+gantt.action.newActivity=Neue Aktivität
+gantt.contextMenu.newSubActivity=Neue Unteraktivität
gantt.contextMenu.saveAsTask=Als ProjectForge-Strukturelement anlegen
gantt.contextMenu.setInvisible=Unsichtbar machen
gantt.contextMenu.setSubTasksVisible=Sichtbar inkl. Untertasks
gantt.duration=Dauer
gantt.endDate=Endedatum
gantt.error.durationAndEndDateAreMutuallyExclusive=Es kann entweder nur die Dauer oder nur ein Endedatum angegeben werden.
-gantt.error.parentObjectIsNotAPFTask=Das übergeordnete Gantt-Objekt muss ein ProjectForge-Strukturelement sein\!
+gantt.error.parentObjectIsNotAPFTask=Das übergeordnete Gantt-Objekt muss ein ProjectForge-Strukturelement sein\!
gantt.export.jpg=JPG (nicht empfohlen)
gantt.export.msproject.mpx=Microsoft® Project (MPX)
gantt.export.msproject.xml=Microsoft® Project (XML)
@@ -1423,7 +1423,7 @@ gantt.export.projectforge=ProjectForge (XML)
gantt.export.svg=SVG
gantt.name=Name
gantt.objectType=Gantt-Objekttyp
-gantt.objectType.activity=Aktivität (Standard)
+gantt.objectType.activity=Aktivität (Standard)
gantt.objectType.activity.short=Std
gantt.objectType.milestone=Meilenstein
gantt.objectType.milestone.short=MS
@@ -1431,11 +1431,11 @@ gantt.objectType.short=Typ
gantt.objectType.summary=Zusammenfassung
gantt.objectType.summary.short=Zus
gantt.owner=Eigner
-gantt.predecessor=Vorgänger
-gantt.predecessor.paste=Als Vorgänger einfügen
+gantt.predecessor=Vorgänger
+gantt.predecessor.paste=Als Vorgänger einfügen
gantt.predecessorOffset=Offset
-gantt.question.moveTask=Soll das zugehörige ProjectForge-Strukturelement wirklich verschoben werden?
-gantt.question.saveGanttObjectAsTask=Soll dieses Gantt-Objekt wirklich als neues ProjectForge-Strukturelement übernommen werden?
+gantt.question.moveTask=Soll das zugehörige ProjectForge-Strukturelement wirklich verschoben werden?
+gantt.question.saveGanttObjectAsTask=Soll dieses Gantt-Objekt wirklich als neues ProjectForge-Strukturelement übernommen werden?
gantt.relationType=Beziehung
gantt.relationType.finish_finish=Ende-Ende
gantt.relationType.finish_finish.short=EE
@@ -1459,8 +1459,8 @@ gantt.title.edit=Ganttdiagramm bearbeiten
gantt.title.heading=Ganttdiagramme
gantt.title.list=Ganttdiagramme
gantt.tooltip.isVisible=Soll dieses Objekt angezeigt werden?
-gantt.tooltip.rejectValue=Diesen Wert verwerfen und den Wert des Strukturelements übernehmen\: ''{0}''.
-gantt.tooltip.returnKeyCallsRedraw=Drücken Sie die Eingabetaste, um das Diagramm erneut zu zeichnen.
+gantt.tooltip.rejectValue=Diesen Wert verwerfen und den Wert des Strukturelements übernehmen\: ''{0}''.
+gantt.tooltip.returnKeyCallsRedraw=Drücken Sie die Eingabetaste, um das Diagramm erneut zu zeichnen.
gantt.tooltip.saveTaskValue=Diesen Wert dem Strukturelement zuweisen und abspeichern.
gantt.x.unit.auto=Automatisch
gantt.x.unit.day=Tag
@@ -1471,32 +1471,32 @@ group.assignedUsers=Assoziierte Benutzer:in
group.error.groupnameAlreadyExists=Gruppenname ist bereits vergeben.
group.groups=Gruppen
group.ldapValues=LDAP
-group.list.select.title=Gruppe wählen
+group.list.select.title=Gruppe wählen
group.localGroup=Lokale Gruppe
group.localGroup.not=Allgemeine Gruppe
group.localGroup.tooltip=Lokale Gruppen werden nicht mit einem externen Benutzer:innensystem synchronisiert (z. B. LDAP).
group.nestedGroups=Eingebettete Gruppen
group.nestedGroupsAllowed=Eingebettete Gruppen erlaubt?
-group.nestedGroupsAllowed.tooltip=Zur Sicherheit sollten für die Gruppen Administrator:innen, Controlling etc. keine eingebetteten Gruppen erlaubt sein, um versehentlichen unbefugten Zugriff zu verhindern.
+group.nestedGroupsAllowed.tooltip=Zur Sicherheit sollten für die Gruppen Administrator:innen, Controlling etc. keine eingebetteten Gruppen erlaubt sein, um versehentlichen unbefugten Zugriff zu verhindern.
group.owner=Gruppenbesitzer
-group.pleaseSelectGroup=Bitte Gruppe wählen
+group.pleaseSelectGroup=Bitte Gruppe wählen
group.systemGroups=Systemgruppen
group.title.add=Neue Gruppe
group.title.edit=Gruppe bearbeiten
group.title.heading=Benutzergruppen
group.title.list=Gruppenliste
-group.title.list.select=Gruppen wählen
+group.title.list.select=Gruppen wählen
group.unassignedUsers=Nicht assoziierte Benutzer:innen
-hint.selectMode.quickselect=Beachte den Quick-Select\: Enthält das Suchergebnis nur einen einzelnen Eintrag, so wird dieser automatisch übernommen.
+hint.selectMode.quickselect=Beachte den Quick-Select\: Enthält das Suchergebnis nur einen einzelnen Eintrag, so wird dieser automatisch übernommen.
history.entryType=Aktion
history.newValue=Neuer Wert
history.oldValue=Alter Wert
history.propertyName=Feld
history.was=war
-hr.planning.description=Tätigkeit
-hr.planning.entry.copyFromPredecessor=Vorgänger kopieren
-hr.planning.entry.error.entryDoesAlreadyExistForUserAndWeekOfYear=Dieser Eintrag kollidiert mit einem bereits vorhandenem für den gleichen Benutzer für die gleiche Kalenderwoche.
-hr.planning.entry.error.noRightForProject=Es fehlt das Recht, Einträge für das Projekt ''{0}'' zu erstellen oder zu ändern
+hr.planning.description=Tätigkeit
+hr.planning.entry.copyFromPredecessor=Vorgänger kopieren
+hr.planning.entry.error.entryDoesAlreadyExistForUserAndWeekOfYear=Dieser Eintrag kollidiert mit einem bereits vorhandenem für den gleichen Benutzer für die gleiche Kalenderwoche.
+hr.planning.entry.error.noRightForProject=Es fehlt das Recht, Einträge für das Projekt ''{0}'' zu erstellen oder zu ändern
hr.planning.entry.error.statusAndProjektNotAllowed=Es darf nur der Status oder das Projekt gesetzt sein.
hr.planning.entry.error.statusOrProjektRequired=Es muss der Status oder das Projekt gesetzt sein.
hr.planning.entry.status.absence=Abwesenheit
@@ -1513,7 +1513,7 @@ hr.planning.hours=Stunden
hr.planning.notPlanned=Ungeplant
hr.planning.period=Zeitraum
hr.planning.plannings=Personaleinsatzplanung
-hr.planning.priority=Priorität
+hr.planning.priority=Priorität
hr.planning.probability=Wahrscheinlichkeit
hr.planning.probability.short=%
hr.planning.sum=Summe
@@ -1521,52 +1521,52 @@ hr.planning.till=bis
hr.planning.title.add=Neue Resourcenplanung
hr.planning.title.edit=Resourcenplanung bearbeiten
hr.planning.title.heading=Resourcenplanung
-hr.planning.title.list=Resourcenplanungsübersicht
-hr.planning.tooltip.addEntry=Eintrag hinzufügen
+hr.planning.title.list=Resourcenplanungsübersicht
+hr.planning.tooltip.addEntry=Eintrag hinzufügen
hr.planning.total=Gesamt
hr.planning.unassignedHours=ohne Tagangabe
-hr.planning.view.title=Planungsübersicht
+hr.planning.view.title=Planungsübersicht
hr.planning.weekend=Wochenende
hr.planning.workdays=Arbeitstage
-import.confirmMessage=Sollen nun alle ausgewählten Einträge importiert werden? Diese Aktion kann nicht rückgängig gemacht werden.
+import.confirmMessage=Sollen nun alle ausgewählten Einträge importiert werden? Diese Aktion kann nicht rückgängig gemacht werden.
import.display.options=Anzeigeoptionen
import.entry.error=Fehler
-import.entry.status.deleted=Gelöscht
+import.entry.status.deleted=Gelöscht
import.entry.status.faulty=Fehlerhaft
import.entry.status.modified=Modifiziert
import.entry.status.new=Neu
import.entry.status.unknown=Unbekannt
import.entry.status.unknown_modification=Unbekannt
-import.entry.status.unmodified=Unverändert
-import.error.noEntrySelected=Kein Eintrag zum Importieren ausgewählt.
+import.entry.status.unmodified=Unverändert
+import.error.noEntrySelected=Kein Eintrag zum Importieren ausgewählt.
import.error.nothingToImport=Nichts zum Importieren gefunden. Bitte eine andere Datei probieren oder die Importeinstellungen entsprechend definieren.
import.field.mapping=Feldzuordnung
import.field.name=Feldname
-import.help.settings.info=Es können Importeinstellungen wie Encoding (Zeichensatz) und Feldzuordnungen sowie Datenformatee definiert werden. Hier ein Beispiel als Kopiervorlage:
+import.help.settings.info=Es können Importeinstellungen wie Encoding (Zeichensatz) und Feldzuordnungen sowie Datenformatee definiert werden. Hier ein Beispiel als Kopiervorlage:
import.help.settings.title=Tipps
import.info.detectedColumns=Erkannte Spalten
import.info.unknownColumns=Unbekannte Spalten
-import.result.numberOfCreated=Anzahl neu angelegter Einträge
-import.result.numberOfDeleted=Anzahl gelöschter Einträge
-import.result.numberOfUnmodified=Anzahl unveränderter Einträge
-import.result.numberOfUpdated=Anzahl geänderter Einträge
+import.result.numberOfCreated=Anzahl neu angelegter Einträge
+import.result.numberOfDeleted=Anzahl gelöschter Einträge
+import.result.numberOfUnmodified=Anzahl unveränderter Einträge
+import.result.numberOfUpdated=Anzahl geänderter Einträge
import.result.title=Importergebnis
-import.stats.deleted=Anzahl zu löschender Einträge
-import.stats.faulty=Anzahl fehlerhafter Einträge (s. Statustooltip)
-import.stats.modified=Anzahl zu ändernder Einträge
-import.stats.new=Anzahl neuer Einträge
+import.stats.deleted=Anzahl zu löschender Einträge
+import.stats.faulty=Anzahl fehlerhafter Einträge (s. Statustooltip)
+import.stats.modified=Anzahl zu ändernder Einträge
+import.stats.new=Anzahl neuer Einträge
import.stats.total=Gesamtanzahl
-import.stats.unknown=Anzahl unbekannter Einträge
-import.stats.unmodified=Anzahl unverändert Einträge
+import.stats.unknown=Anzahl unbekannter Einträge
+import.stats.unmodified=Anzahl unverändert Einträge
import.title=Import-Tool
-index.development=Webseite für Entwicklung
+index.development=Webseite für Entwicklung
index.website=Webseite
index.welcome=Willkommen bei ProjectForge.
-jira.chooseProject=--- JIRA-Projekt wählen ---
-jobs.error.refusedByAnotherRunningJob=Job konnte nicht gestartet werden, weil bereits ein anderer Job für die gleiche Queue läuft.
-jobs.error.waitingTimeExceeded=Job fehlgeschlagen (Zeitüberschreitung). Der Job konnte nicht gestartet werden, weil er von anderen Job(s) zu lange blockiert wurde.
+jira.chooseProject=--- JIRA-Projekt wählen ---
+jobs.error.refusedByAnotherRunningJob=Job konnte nicht gestartet werden, weil bereits ein anderer Job für die gleiche Queue läuft.
+jobs.error.waitingTimeExceeded=Job fehlgeschlagen (Zeitüberschreitung). Der Job konnte nicht gestartet werden, weil er von anderen Job(s) zu lange blockiert wurde.
jobs.import.action.reconcile=Abgleichen
-jobs.import.action.reconcile.tooltip=Beim Abgleichen werden alle hochgeladenen Datensätze mit den in der Datenbank bereits vorhandenen Daten verglichen.
+jobs.import.action.reconcile.tooltip=Beim Abgleichen werden alle hochgeladenen Datensätze mit den in der Datenbank bereits vorhandenen Daten verglichen.
jobs.job.cancel.confirmationMessage=Soll der Job jetzt unwiderruflich abgebrochen werden?
jobs.job.runtime=Laufzeit
jobs.job.startedAt=Gestartet
@@ -1574,7 +1574,7 @@ jobs.job.status.cancelled=Abgebrochen
jobs.job.status.failed=Fehlerhaft
jobs.job.status.finished=Fertig
jobs.job.status.refused=Abgelehnt
-jobs.job.status.running=Läuft
+jobs.job.status.running=Läuft
jobs.job.status.waiting=Wartend
jobs.job.terminatedAt=Beendet
jobs.job.title=Jobtitel
@@ -1585,11 +1585,11 @@ label.exportFormat=Exportformat
label.filterSettings=Filtereinstellungen
label.help=Hilfe
label.hint=Hinweis
-label.historyOfChanges=Änderungshistorie
+label.historyOfChanges=Änderungshistorie
label.null=
-label.onlyActiveEntries=Nur aktive Einträge
+label.onlyActiveEntries=Nur aktive Einträge
label.options=Optionen
-label.pageSize=Seitengröße
+label.pageSize=Seitengröße
label.position.short=Pos
label.result=Ergebnis
label.resultset=Ergebnis
@@ -1599,26 +1599,26 @@ label.sendEMailNotification=E-Mail-Benachrichtigung versenden?
label.sendShortMessage=SMS an Bearbeiter versenden?
ldap=LDAP
ldap.gidNumber=GID number
-ldap.gidNumber.alreadyInUse=Die GID-Nummer ist bereits an eine andere Gruppe vergeben. Die nächste freie GID-Nummer lautet: {0}.
-ldap.gidNumber.createDefault.tooltip=Erzeugt eine neue GID (die nächste freie >= 1.000). Achtung: ProjectForge löscht keine Posix/Samba-Accounts im LDAP, die einmal angelegt worden sind!
-ldap.gidNumber.tooltip=ProjectForges versucht die größte bereits durch ProjectForge vergebene GID-Nummer zu finden und schlägt die nächst höhere Nummer als nächste freie GID-Nummer vor. Dabei startet ProjectForge mit 1.000, um nicht mit GIDs der Betriebssysteme zu kollidieren (z. B. mit Systemgruppen).
+ldap.gidNumber.alreadyInUse=Die GID-Nummer ist bereits an eine andere Gruppe vergeben. Die nächste freie GID-Nummer lautet: {0}.
+ldap.gidNumber.createDefault.tooltip=Erzeugt eine neue GID (die nächste freie >= 1.000). Achtung: ProjectForge löscht keine Posix/Samba-Accounts im LDAP, die einmal angelegt worden sind!
+ldap.gidNumber.tooltip=ProjectForges versucht die größte bereits durch ProjectForge vergebene GID-Nummer zu finden und schlägt die nächst höhere Nummer als nächste freie GID-Nummer vor. Dabei startet ProjectForge mit 1.000, um nicht mit GIDs der Betriebssysteme zu kollidieren (z. B. mit Systemgruppen).
ldap.homeDirectory=Home directory
ldap.loginShell=Login shell
ldap.posixAccount=Posix account
ldap.sambaAccount=Samba account
ldap.sambaNTPassword=Samba-Passwort
ldap.sambaNTPassword.subtitle=NT hashed Passwort
-ldap.sambaNTPassword.tooltip=Das Samba-Passwort wird immer dann im LDAP gesetzt, wenn der Benutzer sein Password ändert. Falls es im LDAP nicht gesetzt wird, muss sich der Benutzer mindestens das nächste Mal an ProjectForge anmelden bevor ein etwaiger Angemeldet-Bleiben-Mechanismum greift.
+ldap.sambaNTPassword.tooltip=Das Samba-Passwort wird immer dann im LDAP gesetzt, wenn der Benutzer sein Password ändert. Falls es im LDAP nicht gesetzt wird, muss sich der Benutzer mindestens das nächste Mal an ProjectForge anmelden bevor ein etwaiger Angemeldet-Bleiben-Mechanismum greift.
ldap.sambaPrimaryGroupSID=Primary group SID.
ldap.sambaPrimaryGroupSID.tooltip=Die Samba primary group SID ist optional.
ldap.sambaSID=Samba SID
-ldap.sambaSID.alreadyInUse=Die Samba-SID ist bereits an einen anderen Benutzer vergeben. Die nächste frei Samba-SID-Endziffer lautet: {0}.
-ldap.sambaSID.createDefault.tooltip=Erzeugt eine neue Samba SID (die nächste freie >= 1.000). Achtung: ProjectForge löscht keine Posix/Samba-Accounts im LDAP, die einmal angelegt worden sind!
+ldap.sambaSID.alreadyInUse=Die Samba-SID ist bereits an einen anderen Benutzer vergeben. Die nächste frei Samba-SID-Endziffer lautet: {0}.
+ldap.sambaSID.createDefault.tooltip=Erzeugt eine neue Samba SID (die nächste freie >= 1.000). Achtung: ProjectForge löscht keine Posix/Samba-Accounts im LDAP, die einmal angelegt worden sind!
ldap.sambaSID.tooltip=Die Samba-SID ist ein Wert, der aus dem in projectforge.properties konfiguriertem Samba-SID-Prefix und der UID number gebildet wird.
ldap.uidNumber=UID number
-ldap.uidNumber.alreadyInUse=Die UID-Nummer ist bereits an eine:n andere:n Benutzer:in vergeben. Die nächste freie UID-Nummer lautet: {0}.
-ldap.uidNumber.createDefault.tooltip=Erzeugt eine neue UID (die nächste freie >= 1.000), setzt die Standard-GID (konfiguriert in projectforge.properties), das Homedirectory und die konfigurierte Standard-Login-Shell. Achtung: ProjectForge löscht keine Posix/Samba-Accounts im LDAP, die einmal angelegt worden sind!
-ldap.uidNumber.tooltip=ProjectForge versucht die größte bereits durch ProjectForge vergebene UID-Nummer zu finden und schlägt die nächst höhere Nummer als nächste freie UID-Nummer vor. Dabei startet ProjectForge mit 1.000, um nicht mit UIDs der Betriebssysteme zu kollidieren (z. B. mit Systembenutzern).
+ldap.uidNumber.alreadyInUse=Die UID-Nummer ist bereits an eine:n andere:n Benutzer:in vergeben. Die nächste freie UID-Nummer lautet: {0}.
+ldap.uidNumber.createDefault.tooltip=Erzeugt eine neue UID (die nächste freie >= 1.000), setzt die Standard-GID (konfiguriert in projectforge.properties), das Homedirectory und die konfigurierte Standard-Login-Shell. Achtung: ProjectForge löscht keine Posix/Samba-Accounts im LDAP, die einmal angelegt worden sind!
+ldap.uidNumber.tooltip=ProjectForge versucht die größte bereits durch ProjectForge vergebene UID-Nummer zu finden und schlägt die nächst höhere Nummer als nächste freie UID-Nummer vor. Dabei startet ProjectForge mit 1.000, um nicht mit UIDs der Betriebssysteme zu kollidieren (z. B. mit Systembenutzern).
ldap.user.gidNumber.tooltip=Der Standardwert kann in projectforge.properties konfiguriert werden: projectforge.ldap.posixAccountsDefaultGidNumber
ldap.wlanSambaPassword=WLAN/Samba Passwort
legalAffaires.contract.coContractorA=Vertragspartner:in A
@@ -1626,7 +1626,7 @@ legalAffaires.contract.coContractorB=Vertragspartner:in B
legalAffaires.contract.contractPersonA=Ansprechpartner:in A
legalAffaires.contract.contractPersonB=Ansprechpartner:in B
legalAffaires.contract.error.numberAlreadyExists=Die Vertragsnummer ist bereits vergeben.
-legalAffaires.contract.error.numberNotConsecutivelyNumbered=Die Vertragsnummer ist nicht die nächstfolgende (nicht fortlaufend).
+legalAffaires.contract.error.numberNotConsecutivelyNumbered=Die Vertragsnummer ist nicht die nächstfolgende (nicht fortlaufend).
legalAffaires.contract.number=Vertragsnummer
legalAffaires.contract.signerA=Unterzeichner:in A
legalAffaires.contract.signerB=Unterzeichner:in B
@@ -1641,8 +1641,8 @@ legalAffaires.contract.status.suspended=verworfen
legalAffaires.contract.status.unknown=unbekannt
legalAffaires.contract.title.add=Neuer Vertrag
legalAffaires.contract.title.edit=Vertrag bearbeiten
-legalAffaires.contract.title.heading=Verträge
-legalAffaires.contract.title.list=Verträge
+legalAffaires.contract.title.heading=Verträge
+legalAffaires.contract.title.list=Verträge
legalAffaires.contract.type=Typ
legalAffaires.contract.validity=Laufzeit
legalAffaires.contract.validity.from=Laufzeit von
@@ -1658,31 +1658,31 @@ locale.zh=Chinesisch
### not translated: log.level.warn=Warn
login.adminLoginRequired=Wartungsmodus: Bitte als Administrator:in anmelden!
login.error.loginExpired=Die Anmeldung war nicht erfolgreich. Bitte Administrator:in kontaktieren, da der Zugang abgelaufen ist.
-login.error.loginFailed=Die Anmeldung war nicht erfolgreich. Bitte Eingabe nochmals prüfen (Groß-/Kleinschreibung bitte beachten).
+login.error.loginFailed=Die Anmeldung war nicht erfolgreich. Bitte Eingabe nochmals prüfen (Groß-/Kleinschreibung bitte beachten).
login.lastLogin=Letze Anmeldung
login.loginFailures=Anmeldefehlversuche
-login.passwordReset=Passwort zurücksetzen
-login.passwordReset.info=Ein Link zum Passwortrücksetzen wird per E-Mail gesendet (ein 2. Faktor wird benötigt).
+login.passwordReset=Passwort zurücksetzen
+login.passwordReset.info=Ein Link zum Passwortrücksetzen wird per E-Mail gesendet (ein 2. Faktor wird benötigt).
login.stayLoggedIn=An diesem Browser angemeldet bleiben.
login.stayLoggedIn.invalidateAllStayLoggedInSessions=Alle Angemeldet-bleiben-Sitzungen beenden.
login.stayLoggedIn.invalidateAllStayLoggedInSessions.successfullDeleted=Alle Angemeldet-bleiben-Sitzungen wurden erfolgreich beendet.
-login.stayLoggedIn.invalidateAllStayLoggedInSessions.tooltip=Über diese wird ein neuer Code generiert. Damit werden alle eventuell noch vorhanden Angemeldet-bleiben-Sitzungen ungültig.
-login.stayLoggedIn.tooltip=Du kannst an diesem Browser angemeldet bleiben, wenn du diese Funktion anwählst. Bei Abmeldung wird dieses Merkmal (Cookie) wieder entfernt. Änderst du dein Passwort und/oder Benutzer:innamen werden alle Browseranmeldungen zunächst ungültig. Außerdem kannst di unter Mein Account alle vorhandenen Browseranmeldungen auf ungültig setzen. Diese Funktion kann immer wieder erneut genutzt werden.
-login.successful=Anmeldung erfolgreich. Viel Spaß mit ProjectForge!
-login.timeOffset=Der Zugang ist noch für {0} Sekunden gesperrt auf Grund von {1} Fehlanmeldungen. Bitte später nochmals versuchen.
+login.stayLoggedIn.invalidateAllStayLoggedInSessions.tooltip=Ãœber diese wird ein neuer Code generiert. Damit werden alle eventuell noch vorhanden Angemeldet-bleiben-Sitzungen ungültig.
+login.stayLoggedIn.tooltip=Du kannst an diesem Browser angemeldet bleiben, wenn du diese Funktion anwählst. Bei Abmeldung wird dieses Merkmal (Cookie) wieder entfernt. Änderst du dein Passwort und/oder Benutzer:innamen werden alle Browseranmeldungen zunächst ungültig. Außerdem kannst di unter Mein Account alle vorhandenen Browseranmeldungen auf ungültig setzen. Diese Funktion kann immer wieder erneut genutzt werden.
+login.successful=Anmeldung erfolgreich. Viel Spaß mit ProjectForge!
+login.timeOffset=Der Zugang ist noch für {0} Sekunden gesperrt auf Grund von {1} Fehlanmeldungen. Bitte später nochmals versuchen.
login.title=Anmeldung
logout.successful=Erfolgreich abgemeldet.
mail.error.exception=Beim E-Mailversand trat ein Fehler auf, der protokolliert wurde. Bitte eine:n Systemadministrator:in kontaktieren.
-mail.error.missingToAddress=Der E-Mailversand wurde abgebrochen, da keine Empfänger:inadresse angegeben ist.
-mail.template.closing=Viel Spaß mit ProjectForge\!
+mail.error.missingToAddress=Der E-Mailversand wurde abgebrochen, da keine Empfänger:inadresse angegeben ist.
+mail.template.closing=Viel Spaß mit ProjectForge\!
mail.template.opening=Hallo {0},
-massUpdate.changeSelection=Auswähl ändern
-massUpdate.confirmQuestion=Sollen nun alle {0} Objekte geändert werden?
-massUpdate.entriesFound=Es sind {0} Einträge ausgewählt.
-massUpdate.error.invalidOptionMix=Sich widersprechende Aktionen gewählt.
-massUpdate.error.maximumNumberOfAllowedMassUpdatesExceeded=Die maximal zulässige Anzahl {0} von zu ändernden Elementen für eine Massenänderung wurde überschritten. Aus Qualitätsgründen wird diese Operation daher nicht zugelassen.
-massUpdate.error.noEntriesSelected=Keine ausgewählten Datensätze gefunden. Bitte vorher eine Auswahl treffen.
-massUpdate.error.nothingToDo=Es gibt nichts zu tun. Bitte Felder zum Ändern auswählen.
+massUpdate.changeSelection=Auswähl ändern
+massUpdate.confirmQuestion=Sollen nun alle {0} Objekte geändert werden?
+massUpdate.entriesFound=Es sind {0} Einträge ausgewählt.
+massUpdate.error.invalidOptionMix=Sich widersprechende Aktionen gewählt.
+massUpdate.error.maximumNumberOfAllowedMassUpdatesExceeded=Die maximal zulässige Anzahl {0} von zu ändernden Elementen für eine Massenänderung wurde überschritten. Aus Qualitätsgründen wird diese Operation daher nicht zugelassen.
+massUpdate.error.noEntriesSelected=Keine ausgewählten Datensätze gefunden. Bitte vorher eine Auswahl treffen.
+massUpdate.error.nothingToDo=Es gibt nichts zu tun. Bitte Felder zum Ändern auswählen.
massUpdate.error.table.element=Element
massUpdate.error.table.message=Meldung
massUpdate.error.table.title=Fehlermeldungen
@@ -1691,52 +1691,52 @@ massUpdate.error.unspecifiedError=Es ist ein Fehler aufgetreten.
massUpdate.excel.column.element=Element
massUpdate.excel.column.new=neu
massUpdate.excel.column.old=alt
-massUpdate.excel.download=Exceldatei mit allen Änderungen
-massUpdate.field.checkbox4appending=Anhängen?
-massUpdate.field.checkbox4appending.info=Wenn ausgewählt, wird der Text angehängt (wenn nicht bereits im Feld enthalten). Wenn nicht ausgewählt, wird das bestehende Feld ersetzt.
-massUpdate.field.checkbox4deletion=Löschen?
-massUpdate.field.checkbox4deletion.info=Wenn diese Option ausgewählt ist, wird für alle Datensätze dieses Feld gelöscht (bzw. geleert). Wenn ein Text angegeben ist, wird nur der Text gelöscht, wenn vorhanden.
+massUpdate.excel.download=Exceldatei mit allen Änderungen
+massUpdate.field.checkbox4appending=Anhängen?
+massUpdate.field.checkbox4appending.info=Wenn ausgewählt, wird der Text angehängt (wenn nicht bereits im Feld enthalten). Wenn nicht ausgewählt, wird das bestehende Feld ersetzt.
+massUpdate.field.checkbox4deletion=Löschen?
+massUpdate.field.checkbox4deletion.info=Wenn diese Option ausgewählt ist, wird für alle Datensätze dieses Feld gelöscht (bzw. geleert). Wenn ein Text angegeben ist, wird nur der Text gelöscht, wenn vorhanden.
massUpdate.field.replace=Ersetzen durch?
massUpdate.field.replace.info=Wenn hier ein Text angegeben ist, werden alle gefundenen Vorkommnisse durch diesen Text ersetzt.
-massUpdate.info=Im Protokoll finden sich detaillierte Informationen zur Massenänderung.
-massUpdate.result={0} Einträge wurden bearbeitet: {1} geändert, {2} unverändert und {3} fehlerhaft.
-massUpdate.result.excel.title=Massenänderungen
+massUpdate.info=Im Protokoll finden sich detaillierte Informationen zur Massenänderung.
+massUpdate.result={0} Einträge wurden bearbeitet: {1} geändert, {2} unverändert und {3} fehlerhaft.
+massUpdate.result.excel.title=Massenänderungen
menu.2FASetup=2. Faktor einrichten
menu.accessList=Zugriffsverwaltung
menu.addNewEntry=Neuer Eintrag
-menu.addressbookList=Adressbücher
+menu.addressbookList=Adressbücher
menu.addressList=Adressen
menu.addressListClassics=Adressen klassisch
menu.administration=Administration
menu.adminLogbuch=Admin-Logbuch
menu.birthdayButler=Geburtstagsbutler
menu.birthdays=Geburtstage
-menu.bookList=Bücher
+menu.bookList=Bücher
menu.calendar=Kalender
-menu.changePassword=Passwort ändern
-menu.changeWlanPassword=WLAN/Samba Passwort ändern
+menu.changePassword=Passwort ändern
+menu.changeWlanPassword=WLAN/Samba Passwort ändern
menu.common=Allgemein
menu.configuration=Konfiguration
-menu.configureMenu.tooltip=Per Drag & Drop kann das persönliche Menü gestaltet werden.
+menu.configureMenu.tooltip=Per Drag & Drop kann das persönliche Menü gestaltet werden.
menu.contactList=Kontakte
-menu.contracts=Verträge
-menu.customize.completeMenu=Komplettes Menü
-menu.customize.create=Neuer Menüordner
+menu.contracts=Verträge
+menu.customize.completeMenu=Komplettes Menü
+menu.customize.create=Neuer Menüordner
menu.customize.enterNewName=Neuen Namen eingeben
-menu.customize.help=Per Drag&Drop können die Menüeinträge umsortiert werden. Bitte beachten, dass nur Menueinträge bis zur 3. Einrückebene genutzt werden. Menüeinträge aus dem rechten, kompletten Menü können per Drag&Drop in das persönliche Menü übernommen werden. Zum Löschen, Anlegen und Umbennen bitte das Kontextmenü verwenden (rechte Maustaste).
+menu.customize.help=Per Drag&Drop können die Menüeinträge umsortiert werden. Bitte beachten, dass nur Menueinträge bis zur 3. Einrückebene genutzt werden. Menüeinträge aus dem rechten, kompletten Menü können per Drag&Drop in das persönliche Menü übernommen werden. Zum Löschen, Anlegen und Umbennen bitte das Kontextmenü verwenden (rechte Maustaste).
menu.customize.remove=Entfernen
menu.customize.rename=Umbenennen
-menu.customize.title=Persönliches Menü
+menu.customize.title=Persönliches Menü
menu.documentation=Dokumentation
### not translated: menu.dvelop=D-velop
menu.faq=FAQ
-menu.favorite.maxSizeExceeded=Das Menü ist leider zu groß geworden und kann daher nicht gespeichert werden.
+menu.favorite.maxSizeExceeded=Das Menü ist leider zu groß geworden und kann daher nicht gespeichert werden.
menu.fibu=Fibu
-menu.fibu.buchungssaetze=Buchungssätze
+menu.fibu.buchungssaetze=Buchungssätze
menu.fibu.datevImport=Datev-Import
menu.fibu.eingangsrechnungen=Kreditorenrechnungen
menu.fibu.employees=Mitarbeitende
-menu.fibu.employeeSalaries=Gehälter
+menu.fibu.employeeSalaries=Gehälter
menu.fibu.konten=Buchungskonten
menu.fibu.kost=Kost
menu.fibu.kost1=Kost1
@@ -1744,12 +1744,12 @@ menu.fibu.kost2=Kost2
menu.fibu.kost2arten=Kost2-Arten
menu.fibu.kunden=Kunden
menu.fibu.orderbook=Auftragsbuch
-menu.fibu.orderbook.htmlSuffixTooltip=Abgeschlossene und noch nicht vollständig fakturierte Aufträge.
+menu.fibu.orderbook.htmlSuffixTooltip=Abgeschlossene und noch nicht vollständig fakturierte Aufträge.
menu.fibu.projekte=Projekte
menu.fibu.rechnungen=Debitorenrechnungen
menu.fibu.reporting.reportObjectives=Report-Objectives
menu.gantt=Gantt
-menu.gear.customizeMenu=Menü anpassen
+menu.gear.customizeMenu=Menü anpassen
menu.gear.feedback=Feedback senden
menu.gear.layoutsettings=Layouteinstellungen
menu.gear.showBookmark=Seite als Link
@@ -1762,9 +1762,9 @@ menu.imageCropper=ImageCropper
menu.login=Anmelden
menu.logout=Abmelden
### not translated: menu.luceneConsole=Lucene Console
-menu.main.tip1=Häufig verwendete Menüeinträge können per Drag&Drop direkt in das persönliche Menü nach oben kopiert werden. Sie sind dann mit einem Mausklick direkt erreichbar.
-menu.main.tip2=Die Menüeinträge können auch in die Lesezeichenleiste per Drag&Drop eingefügt werden. Abhängig vom Browser und Betriebssystem können die Menüeinträge dann auch mit Tastenkürzel aufgerufen werden (z. B. CMD-Nummer unter Apple-Safari).
-menu.main.title=Hauptmenü
+menu.main.tip1=Häufig verwendete Menüeinträge können per Drag&Drop direkt in das persönliche Menü nach oben kopiert werden. Sie sind dann mit einem Mausklick direkt erreichbar.
+menu.main.tip2=Die Menüeinträge können auch in die Lesezeichenleiste per Drag&Drop eingefügt werden. Abhängig vom Browser und Betriebssystem können die Menüeinträge dann auch mit Tastenkürzel aufgerufen werden (z. B. CMD-Nummer unter Apple-Safari).
+menu.main.title=Hauptmenü
menu.misc=Verschiedenes
menu.monthlyEmployeeReport=Monatsbericht
menu.monthlyEmployeeReport.fileprefix=Monatsbericht
@@ -1784,14 +1784,14 @@ menu.plugins.teamcal=Kalenderliste
menu.poll=Umfragen
menu.projectmanagement=Projektmanagement
menu.reindexAllDatabaseEntries=Suchindex voll indizieren
-menu.reindexAllDatabaseEntries.tooltip.content=Der Suchindex wird komplett neu aufgebaut. Bei vielen Einträgen (z. B. 100.000) kann das einige Minuten dauern und die Systemperformance beinträchtigt werden. Deshalb steht diese Funktion nur Administratoren zur Verfügung.
+menu.reindexAllDatabaseEntries.tooltip.content=Der Suchindex wird komplett neu aufgebaut. Bei vielen Einträgen (z. B. 100.000) kann das einige Minuten dauern und die Systemperformance beinträchtigt werden. Deshalb steht diese Funktion nur Administratoren zur Verfügung.
menu.reindexAllDatabaseEntries.tooltip.title=Suchindex voll indizieren
menu.reindexNewestDatabaseEntries=Suchindex reindizieren
-menu.reindexNewestDatabaseEntries.tooltip.content=Es werden alle Einträge, die seit gestern angelegt oder modifiziert wurden, maximal aber 1.000 Einträge, re-indiziert (Dauer weniger als 1 Sekunde).
+menu.reindexNewestDatabaseEntries.tooltip.content=Es werden alle Einträge, die seit gestern angelegt oder modifiziert wurden, maximal aber 1.000 Einträge, re-indiziert (Dauer weniger als 1 Sekunde).
menu.reindexNewestDatabaseEntries.tooltip.title=Suchindex reindizieren
menu.reporting=Reporting
-menu.resetFilter=Filter zurücksetzen
-menu.resetFilter.info=Setzt den aktuellen Suchfilter zurück, wenn Probleme beim Suchen bestehen.
+menu.resetFilter=Filter zurücksetzen
+menu.resetFilter.info=Setzt den aktuellen Suchfilter zurück, wenn Probleme beim Suchen bestehen.
menu.scriptList=Scriptliste
menu.search=Suche
menu.sendSms=SMS senden
@@ -1802,18 +1802,18 @@ menu.taskTree=Strukturbaum
menu.testReports=Testreports
menu.timesheetList=Zeitberichte
menu.userList=Benutzer:innen
-menu.vacation=Urlaubseinträge
+menu.vacation=Urlaubseinträge
menu.vacation.lastyear=Urlaub aus dem Vorjahr
menu.vacation.leaveaccount=Urlaubskonto
menu.vacation.leaveAccountEntry=Urlaubskontokorrekturen
message.cancelAction=Aktion ''{0}'' wurde abgebrochen.
-message.successfullChanged=Änderung erfolgreich durchgeführt.
-message.successfullCompleted=Aktion erfolgreich durchgeführt\: {0}
+message.successfullChanged=Änderung erfolgreich durchgeführt.
+message.successfullCompleted=Aktion erfolgreich durchgeführt\: {0}
message.title=Meldung
-message.wicket.pageExpired=Die aufgerufene Seite ist nicht mehr verfügbar.
+message.wicket.pageExpired=Die aufgerufene Seite ist nicht mehr verfügbar.
multiselection.aggrid.selection.info.message=\
-* Gemeinsam mit der Hochstelltaste bzw. Steuerungstaste können mehrere Zeilen per Mausklick gleichzeitig ausgewählt werden.\n\
-* Mit den Pfeiltasten kann in den Zeilen navigiert werden und über die Leertaste einzelne Zeilen selektiert und deselektiert werden.
+* Gemeinsam mit der Hochstelltaste bzw. Steuerungstaste können mehrere Zeilen per Mausklick gleichzeitig ausgewählt werden.\n\
+* Mit den Pfeiltasten kann in den Zeilen navigiert werden und über die Leertaste einzelne Zeilen selektiert und deselektiert werden.
multiselection.aggrid.selection.info.title=Mehrfachauswahl
multiselection.button=Mehrfachauswahl
orga.post.inhalt=Inhalt
@@ -1821,12 +1821,12 @@ orga.post.type=Art
orga.post.type.brief=Brief
orga.post.type.e-mail=E-Mail
orga.post.type.einschreiben=Einschreiben
-orga.post.type.einschreibenMitRueckschein=Einschreiben mit Rückschein
+orga.post.type.einschreibenMitRueckschein=Einschreiben mit Rückschein
orga.post.type.fax=Fax
orga.post.type.lieferung=Lieferung
-orga.post.type.paeckchen=Päckchen
+orga.post.type.paeckchen=Päckchen
orga.post.type.paket=Paket
-orga.postausgang.empfaenger=Empfänger:in
+orga.postausgang.empfaenger=Empfänger:in
orga.postausgang.person=z. Hd.
orga.postausgang.title.add=Postausgang anlegen
orga.postausgang.title.edit=Postausgang bearbeiten
@@ -1848,7 +1848,7 @@ orga.visitorbook.number=Nummer
orga.visitorbook.timeofvisit=Besuchszeit
orga.visitorbook.timeofvisit.arrive=Ankunftszeit (HH:MM)
orga.visitorbook.timeofvisit.depart=Abreisezeit (HH:MM)
-orga.visitorbook.title.add=Besuch hinzufügen
+orga.visitorbook.title.add=Besuch hinzufügen
orga.visitorbook.title.edit=Besuch anpassen
orga.visitorbook.title.heading=Besuchsbuch
orga.visitorbook.title.list=Besuchsbuch Ãœbersicht
@@ -1864,18 +1864,18 @@ panel.error.groupNotFound=Gruppe nicht existent.
panel.error.projectNotFound=Projekt nicht existent.
password.forgotten.link=Zugangsdaten vergessen?
password.forgotten.mail.subject=Passwortreset ProjectForge®
-password.forgotten.mailSentTo=E-Mail mit dem Passwortrücksetzen-Link wurde gesendet an ''{0}''. Bitte im Spam-Ordner schauen bzw. überprüfen, ob der Benutzer:innenname bzw. E-Mail korrekt ist.
-password.forgotten.request=Rücksetzen anfordern
+password.forgotten.mailSentTo=E-Mail mit dem Passwortrücksetzen-Link wurde gesendet an ''{0}''. Bitte im Spam-Ordner schauen bzw. überprüfen, ob der Benutzer:innenname bzw. E-Mail korrekt ist.
+password.forgotten.request=Rücksetzen anfordern
password.forgotten.title=Passwort vergessen
-password.reset.error=Es wurde keine gültige Passwortreset-Sitzung gefunden. Entweder ist sie schon verbraucht, abgelaufen oder nicht vorhanden. Bitte erneut versuchen.
-password.reset.mail.link=Über diesen Link kann das Passwort zurückgesetzt werden: {0}
-password.reset.mail.message.1=Bitte beachten: Es wird für das Zurücksetzen aus Sicherheitsgründen ein zweiter Faktor benötigt.
-password.reset.mail.message.2=Wenn noch kein zweiter, persönlicher Faktor konfiguriert wurde (Authenticator-App oder Mobilfunknummer), muss ein ProjectForge-Administrator kontaktiert werden.
-password.reset.title=Passwort zurücksetzen
+password.reset.error=Es wurde keine gültige Passwortreset-Sitzung gefunden. Entweder ist sie schon verbraucht, abgelaufen oder nicht vorhanden. Bitte erneut versuchen.
+password.reset.mail.link=Ãœber diesen Link kann das Passwort zurückgesetzt werden: {0}
+password.reset.mail.message.1=Bitte beachten: Es wird für das Zurücksetzen aus Sicherheitsgründen ein zweiter Faktor benötigt.
+password.reset.mail.message.2=Wenn noch kein zweiter, persönlicher Faktor konfiguriert wurde (Authenticator-App oder Mobilfunknummer), muss ein ProjectForge-Administrator kontaktiert werden.
+password.reset.title=Passwort zurücksetzen
password.reset.username_email=Benutzer:inname/E-Mail
personal.statistics.timesheetDisciplineChart.title=Zeitnahes Erfassen von Zeitberichten ist ein wichtiger Grundpfeiler erfolgreichen Projektmanagements!
-personal.statistics.timesheetDisciplineChart1.legend=Insgesamt sind {1} Arbeitszeitstunden in den letzten {0} Tagen angefallen. Bisher wurden für diesen Zeitraum {2} Stunden erfasst.
-personal.statistics.timesheetDisciplineChart2.legend=In den letzten {0} Tagen wurden Zeitberichte nach durchschnittlich {2} Tagen erfasst. Die Zielgröße ist maximal {1} Tage.
+personal.statistics.timesheetDisciplineChart1.legend=Insgesamt sind {1} Arbeitszeitstunden in den letzten {0} Tagen angefallen. Bisher wurden für diesen Zeitraum {2} Stunden erfasst.
+personal.statistics.timesheetDisciplineChart2.legend=In den letzten {0} Tagen wurden Zeitberichte nach durchschnittlich {2} Tagen erfasst. Die Zielgröße ist maximal {1} Tage.
personal.statistics.title=Meine Statistiken
plugins.teamcal.access=Zugriffsrecht
plugins.teamcal.access.groups=Gruppen
@@ -1885,9 +1885,9 @@ plugins.teamcal.adminAccess=Adminrecht
plugins.teamcal.attendee.email.accept=Diesen Termin akzeptieren.
plugins.teamcal.attendee.email.content.deleted={0} hat den Termin "{1}" abgesagt.
plugins.teamcal.attendee.email.content.new={0} hat Sie zu "{1}" eingeladen.
-plugins.teamcal.attendee.email.content.updated={0} hat den Termin "{1}" geändert.
+plugins.teamcal.attendee.email.content.updated={0} hat den Termin "{1}" geändert.
plugins.teamcal.attendee.email.decline=Diesen Termin ablehnen.
-plugins.teamcal.attendee.email.invalid=Mindestens eine Teilnehmer:in E-Mailadresse ist ungültig
+plugins.teamcal.attendee.email.invalid=Mindestens eine Teilnehmer:in E-Mailadresse ist ungültig
plugins.teamcal.attendee.email.subject.deleted="{1}" wurde abgesagt
plugins.teamcal.attendee.email.subject.new={0} hat Sie zu "{1}" eingeladen
plugins.teamcal.attendee.email.subject.updated="{1}" wurde aktuallisiert
@@ -1904,32 +1904,32 @@ plugins.teamcal.attendee.status.new=neu
plugins.teamcal.attendee.status.tentative=unverbindlich
plugins.teamcal.attendees=Teilnehmer:innen
plugins.teamcal.calendar=Kalender
-plugins.teamcal.calendar.filter.choose=Kalenderfilter auswählen oder neue Filter anlegen.
-plugins.teamcal.calendar.filter.edit=Angezeigten Kalenderfilter ändern.
+plugins.teamcal.calendar.filter.choose=Kalenderfilter auswählen oder neue Filter anlegen.
+plugins.teamcal.calendar.filter.edit=Angezeigten Kalenderfilter ändern.
plugins.teamcal.calendar.filter.newEntry=--- Neuer Kalenderfilter ---
-plugins.teamcal.calendar.filterDialog.closeButton.tooltip=Zum Übernehmen der Filteränderungen können Sie irgendwo außerhalb dieses Dialogs klicken. Wenn Sie die Änderungen verwerfen möchten, so drücken Sie bitte den Abbrechen-Knopf.
+plugins.teamcal.calendar.filterDialog.closeButton.tooltip=Zum Ãœbernehmen der Filteränderungen können Sie irgendwo außerhalb dieses Dialogs klicken. Wenn Sie die Änderungen verwerfen möchten, so drücken Sie bitte den Abbrechen-Knopf.
plugins.teamcal.calendar.filterDialog.newTemplateName=Neuer Filter
plugins.teamcal.calendar.filterDialog.title=Kalenderfilter
-plugins.teamcal.calendar.listAndIcsExport.tooltip=Liste der Kalender inklusive Download und Abonnement im ICS-Format. Hier können auch neue Kalender angelegt werden.
+plugins.teamcal.calendar.listAndIcsExport.tooltip=Liste der Kalender inklusive Download und Abonnement im ICS-Format. Hier können auch neue Kalender angelegt werden.
plugins.teamcal.calendar.refresh.tooltip=Kalender neu laden und extern abonnierte Kalender, sofern angezeigt, aktualisieren.
plugins.teamcal.defaultCalendar=Standardkalender
-plugins.teamcal.defaultCalendar.tooltip=Der Standardkalender ist der voreingestellte Kalender für neue Einträge.
+plugins.teamcal.defaultCalendar.tooltip=Der Standardkalender ist der voreingestellte Kalender für neue Einträge.
plugins.teamcal.description=Beschreibung
-plugins.teamcal.download=Download Url für Kalender ''${calendar}''
-plugins.teamcal.dropIcsPanel.tooltip=Hier können ICS-Dateien per Drag&Drop hin gezogen werden, um Kalendereinträge zu importieren bzw. zu aktualisieren.
+plugins.teamcal.download=Download Url für Kalender ''${calendar}''
+plugins.teamcal.dropIcsPanel.tooltip=Hier können ICS-Dateien per Drag&Drop hin gezogen werden, um Kalendereinträge zu importieren bzw. zu aktualisieren.
plugins.teamcal.event.accept=Annehmen
-plugins.teamcal.event.addNewAttendee=Teilnehmer:in hinzufügen ...
+plugins.teamcal.event.addNewAttendee=Teilnehmer:in hinzufügen ...
plugins.teamcal.event.allDay=Ganztags
plugins.teamcal.event.andyou=und Sie
plugins.teamcal.event.beginDate=Beginn
-plugins.teamcal.event.changed=Termin geändert
-plugins.teamcal.event.changedby=Geändert von
+plugins.teamcal.event.changed=Termin geändert
+plugins.teamcal.event.changedby=Geändert von
plugins.teamcal.event.convert2Timesheet=Umwandeln in Zeitbericht
plugins.teamcal.event.decline=Ablehnen
-plugins.teamcal.event.deletedby=Gelöscht von
+plugins.teamcal.event.deletedby=Gelöscht von
plugins.teamcal.event.duplicatedUidFromDifferentUser=Es existiert bereits ein Ereignis mit der UID {0} im Kalendar {1} von einem oder einer anderen Benutzer:in.
plugins.teamcal.event.duration=Dauer
-plugins.teamcal.event.duration.error=Bitte überprüfen Sie das Start- und Enddatum.
+plugins.teamcal.event.duration.error=Bitte überprüfen Sie das Start- und Enddatum.
plugins.teamcal.event.endDate=Ende
plugins.teamcal.event.event=Termin
plugins.teamcal.event.event.allDay=Alle {0} Tage
@@ -1950,22 +1950,22 @@ plugins.teamcal.event.expertSettings=Experteneinstellungen
plugins.teamcal.event.invitation1=hat Sie zu
plugins.teamcal.event.invitation2=eingeladen.
plugins.teamcal.event.location=Ort
-plugins.teamcal.event.location.changed=Ort geändert
+plugins.teamcal.event.location.changed=Ort geändert
plugins.teamcal.event.note=Notiz
-plugins.teamcal.event.ownership=Eigentümer
-plugins.teamcal.event.ownership.tooltip=Ändere diesen Wert nur, wenn du genau weißt, was du tust. Angehakt = ProjectForge ist Eigentümer, das Ereignis kann editiert werden und e-Mails an Teilnehmer werden versandt.
+plugins.teamcal.event.ownership=Eigentümer
+plugins.teamcal.event.ownership.tooltip=Ändere diesen Wert nur, wenn du genau weißt, was du tust. Angehakt = ProjectForge ist Eigentümer, das Ereignis kann editiert werden und e-Mails an Teilnehmer werden versandt.
plugins.teamcal.event.recurrence=Wiederholung
plugins.teamcal.event.recurrence.atthe=Am
plugins.teamcal.event.recurrence.change.all=Alle Ereignisse
-plugins.teamcal.event.recurrence.change.content=Möchten Sie alle Ereignisse, nur zukünftige oder nur dieses einzelne Ereignis ändern?
-plugins.teamcal.event.recurrence.change.future=Alle zukünftigen Ereignisse
+plugins.teamcal.event.recurrence.change.content=Möchten Sie alle Ereignisse, nur zukünftige oder nur dieses einzelne Ereignis ändern?
+plugins.teamcal.event.recurrence.change.future=Alle zukünftigen Ereignisse
plugins.teamcal.event.recurrence.change.single=Nur dieses Ereignis
-plugins.teamcal.event.recurrence.change.text=Alle Änderungen betreffen:
+plugins.teamcal.event.recurrence.change.text=Alle Änderungen betreffen:
plugins.teamcal.event.recurrence.change.text.all=alle Ereignisse
-plugins.teamcal.event.recurrence.change.text.allFuture=alle zukünfigen Ereignisse
+plugins.teamcal.event.recurrence.change.text.allFuture=alle zukünfigen Ereignisse
plugins.teamcal.event.recurrence.change.text.onlyCurrent=nur das aktuelle Ereignis
-plugins.teamcal.event.recurrence.change.title=Sie ändern ein wiederkehrendes Ereignis.
-plugins.teamcal.event.recurrence.changed=Wiederholung geändert
+plugins.teamcal.event.recurrence.change.title=Sie ändern ein wiederkehrendes Ereignis.
+plugins.teamcal.event.recurrence.changed=Wiederholung geändert
plugins.teamcal.event.recurrence.customized=angepasst
plugins.teamcal.event.recurrence.customized.all=Alle
plugins.teamcal.event.recurrence.customized.day=Tag(e)
@@ -1975,8 +1975,8 @@ plugins.teamcal.event.recurrence.customized.year=Jahr(e)
plugins.teamcal.event.recurrence.day=Tag
plugins.teamcal.event.recurrence.each=Jeden
plugins.teamcal.event.recurrence.exDate=Ausnahmetage
-plugins.teamcal.event.recurrence.exDate.tooltip=An diesen Tagen fällt der Wiederholungstermin aus. Bitte diesen Wert nicht manuell ändern, da er in einem besonderen Format vorliegen muss.
-plugins.teamcal.event.recurrence.fifth=Fünfter
+plugins.teamcal.event.recurrence.exDate.tooltip=An diesen Tagen fällt der Wiederholungstermin aus. Bitte diesen Wert nicht manuell ändern, da er in einem besonderen Format vorliegen muss.
+plugins.teamcal.event.recurrence.fifth=Fünfter
plugins.teamcal.event.recurrence.first=Erster
plugins.teamcal.event.recurrence.fourth=Vierter
plugins.teamcal.event.recurrence.friday=Freitag
@@ -2007,7 +2007,7 @@ plugins.teamcal.event.reminder.MINUTES_BEFORE=Minuten davor
plugins.teamcal.event.reminder.NONE=Ohne
plugins.teamcal.event.reminder.options=Erinnerungsoptionen
plugins.teamcal.event.reminder.title=Erinnerung
-plugins.teamcal.event.reminder.tooltip=Die Erinnerung sollte von Endgeräten durchgeführt werden (Apple iCal, iPhone, Android-Telefon, Google-Calendar oder MS Outlook). ProjectForge führt selbst keine Erinnerung durch.
+plugins.teamcal.event.reminder.tooltip=Die Erinnerung sollte von Endgeräten durchgeführt werden (Apple iCal, iPhone, Android-Telefon, Google-Calendar oder MS Outlook). ProjectForge führt selbst keine Erinnerung durch.
plugins.teamcal.event.showreplies=Antworten anzeigen ...
plugins.teamcal.event.status.committed=zugesagt
plugins.teamcal.event.status.declined=abgelehnt
@@ -2016,7 +2016,7 @@ plugins.teamcal.event.status.unknown=unbekannt
plugins.teamcal.event.subject=Betreff
plugins.teamcal.event.teamCal=Teamkalender
plugins.teamcal.event.tentative=Vielleicht
-plugins.teamcal.event.title.add=Ereignis hinzufügen
+plugins.teamcal.event.title.add=Ereignis hinzufügen
plugins.teamcal.event.title.edit=Ereignis bearbeiten
plugins.teamcal.event.title.heading=Ereignis
plugins.teamcal.event.title.list=Ereignisliste
@@ -2024,12 +2024,12 @@ plugins.teamcal.event.uid=UID
plugins.teamcal.event.update=wurde aktualisiert.
plugins.teamcal.events=Ereignisse
plugins.teamcal.export.holidays=Feiertage exportieren
-plugins.teamcal.export.holidays.tooltip=Download oder Abonnement von Feiertagen aus ProjectForge. Die Sprache kann unter 'Mein Zugang' geändert werden.
+plugins.teamcal.export.holidays.tooltip=Download oder Abonnement von Feiertagen aus ProjectForge. Die Sprache kann unter 'Mein Zugang' geändert werden.
plugins.teamcal.export.reminder.checkbox=Erinnerungen exportieren
-plugins.teamcal.export.reminder.checkbox.tooltip=Wenn ausgewählt, werden auch die Erinnerungsfelder der Ereignisse exportiert, andernfalls werden sie ignoriert.
+plugins.teamcal.export.reminder.checkbox.tooltip=Wenn ausgewählt, werden auch die Erinnerungsfelder der Ereignisse exportiert, andernfalls werden sie ignoriert.
plugins.teamcal.export.timesheets=Zeitberichte exportieren
plugins.teamcal.export.weekOfYears=Kalenderwochen exportieren
-plugins.teamcal.export.weekOfYears.tooltip=Download oder Abonnement von Kalenderwochen aus ProjectForge. Die Sprache kann unter 'Mein Zugange' geändert werden.
+plugins.teamcal.export.weekOfYears.tooltip=Download oder Abonnement von Kalenderwochen aus ProjectForge. Die Sprache kann unter 'Mein Zugange' geändert werden.
plugins.teamcal.exportIcsButton=Export ics
plugins.teamcal.externalsubscription.label=Externes Abonnement
plugins.teamcal.externalsubscription.label.tooltip=Externe Kalender abonnieren (im Ics-Format von Google, Apple icloud etc.)
@@ -2038,103 +2038,216 @@ plugins.teamcal.externalsubscription.updateInterval.interval15Min=15 Minuten
plugins.teamcal.externalsubscription.updateInterval.interval1d=1 Tag
plugins.teamcal.externalsubscription.updateInterval.interval1h=1 Stunde
plugins.teamcal.externalsubscription.url=Kalender-URL
-plugins.teamcal.externalsubscription.url.tooltip=Unterstützte Urls sind z. B.\nGoogle-Kalender\: https\://www.google.com/calendar/ical/reinhard%40gmail.com/public/basic.ics oder\nApple icloud\: webcal\://p06-calendarws.icloud.com/ca/subscribe/1/...
-plugins.teamcal.filterDialog.calendarIsVisible.tooltip=Wenn abgewählt, wird der Kalender nicht angezeigt. Hierüber können kurzfristig Kalender aus- und wieder eingeblendet werden.
+plugins.teamcal.externalsubscription.url.tooltip=Unterstützte Urls sind z. B.\nGoogle-Kalender\: https\://www.google.com/calendar/ical/reinhard%40gmail.com/public/basic.ics oder\nApple icloud\: webcal\://p06-calendarws.icloud.com/ca/subscribe/1/...
+plugins.teamcal.filterDialog.calendarIsVisible.tooltip=Wenn abgewählt, wird der Kalender nicht angezeigt. Hierüber können kurzfristig Kalender aus- und wieder eingeblendet werden.
plugins.teamcal.filterDialog.changeFilter=Filter wechseln
plugins.teamcal.fullAccess=Vollzugriff
plugins.teamcal.id=ID
plugins.teamcal.import.ics.error=Fehler beim Importieren
-plugins.teamcal.import.ics.noEventsGiven=Keine Kalendereinträge gefunden.
+plugins.teamcal.import.ics.noEventsGiven=Keine Kalendereinträge gefunden.
plugins.teamcal.import.ics.title=Ereignisse importieren
plugins.teamcal.import.ics.tooltip=Ereignisse im ics-Format importieren.
plugins.teamcal.menu=Team-Kalender
plugins.teamcal.minimalAccess=Minimalzugriff
-plugins.teamcal.minimalAccess.groups.hint=Mitglieder dieser Gruppen können lediglich den Zeitraum eines Eintrags sehen, jedoch keine weiteren Details, wie Ort, Titel etc.
-plugins.teamcal.minimalAccess.users.hint=Diese Benutzer:innen können lediglich den Zeitraum eines Eintrags sehen, jedoch keine weiteren Details, wie Ort, Titel etc.
+plugins.teamcal.minimalAccess.groups.hint=Mitglieder dieser Gruppen können lediglich den Zeitraum eines Eintrags sehen, jedoch keine weiteren Details, wie Ort, Titel etc.
+plugins.teamcal.minimalAccess.users.hint=Diese Benutzer:innen können lediglich den Zeitraum eines Eintrags sehen, jedoch keine weiteren Details, wie Ort, Titel etc.
plugins.teamcal.others=andere
plugins.teamcal.own=eigene
plugins.teamcal.owner=Eigner:in
plugins.teamcal.readonlyAccess=Nur lesend
-plugins.teamcal.selectCalendar=Ausgewählte Kalender zur Anzeige
-plugins.teamcal.selectColor=Farben auswählen
-plugins.teamcal.selectTemplate=Filterschablone auswählen
+plugins.teamcal.selectCalendar=Ausgewählte Kalender zur Anzeige
+plugins.teamcal.selectColor=Farben auswählen
+plugins.teamcal.selectTemplate=Filterschablone auswählen
plugins.teamcal.subscription=Abonnement
-plugins.teamcal.subscription.timesheets=Über diese URL können Sie Ihre Zeitberichte in Ihrem persönlichen Kalender abonnieren (z. B. Apple iCal oder Microsoft Outlook).
-plugins.teamcal.subscription.tooltip=Über diese URL können Sie den Kalender in Ihrem persönlichen Kalender abonnieren (z. B. Apple iCal oder Microsoft Outlook).
+plugins.teamcal.subscription.timesheets=Ãœber diese URL können Sie Ihre Zeitberichte in Ihrem persönlichen Kalender abonnieren (z. B. Apple iCal oder Microsoft Outlook).
+plugins.teamcal.subscription.tooltip=Ãœber diese URL können Sie den Kalender in Ihrem persönlichen Kalender abonnieren (z. B. Apple iCal oder Microsoft Outlook).
plugins.teamcal.switchToTeamEventButton=In Termin umwandeln
plugins.teamcal.switchToTimesheetButton=In Zeitbuchung umwandeln
plugins.teamcal.timeSheetCalendar=Zeitbuchungen
plugins.teamcal.title=Titel
-plugins.teamcal.title.add=Kalender hinzufügen
+plugins.teamcal.title.add=Kalender hinzufügen
plugins.teamcal.title.edit=Team-Kalender bearbeiten
plugins.teamcal.title.heading=Kalender
plugins.teamcal.title.list=Kalenderliste
+
+
+
+
+
+
+
# poll plugin
poll=Umfrage
poll.access=Zugriff
-poll.answer=Antwort
poll.assignment=Zuordnung
poll.attendee=Teilnehmer:in
poll.attendees=Teilnehmer:innen
-poll.button.addQuestion=Eigene Frage hinzufügen
+poll.button.addQuestion=Eigene Frage hinzufügen
poll.button.finish=Umfrage beenden
poll.button.template=Vorlage verwenden
-poll.confirmation.creation=Möchtest du die Umfrage wirklich erstellen? Du kannst die Fragen danach nicht mehr bearbeiten.\
-Stelle ebenfalls sicher, dass du Teilnehmer für deine Umfrage hinzugefügt hast.
-poll.confirmation.deleteAnswer=Möchtest du diese Antwort wirklich löschen?
-poll.confirmation.deleteQuestion=Möchtest du diese Frage wirklich löschen?
+poll.confirmation.creation=Möchtest du die Umfrage wirklich erstellen? Du kannst die Fragen danach nicht mehr bearbeiten.\
+Stelle ebenfalls sicher, dass du Teilnehmer für deine Umfrage hinzugefügt hast.
+poll.confirmation.deleteAnswer=Möchtest du diese Antwort wirklich löschen?
+poll.confirmation.deleteQuestion=Möchtest du diese Frage wirklich löschen?
poll.confirmation.finish=Willst du die Umfrage wirklich beenden?
+
+
+
+
+poll.state=Status
poll.date=Datum
-poll.deadline=Antwortfrist
+poll.deadline=Umfragen Frist
poll.delegationAnswers=Antworten von
poll.description=Beschreibung
+
poll.error.oneQuestionRequired=Mindestens eine Frage ist erforderlich.
poll.exception.noAttendee=Dieser Nutzer ist nicht Teil der Umfrage.
poll.export.response.poll=Ergebnisse exportieren
-poll.finished=Beendet
poll.fullAccessGroups=Gruppen mit Vollzugriff
poll.fullAccessUsers=Benutzer:innen mit Vollzugriff
poll.groupAttendees=Teilnehmergruppen
poll.guide=Anleitung
poll.infopage=Infoseite
poll.location=Ort
-poll.mail.ended.content=Liebe Teilnehmerinnen und Teilnehmer,
\
-wir möchten Sie darüber informieren, dass die Umfrage "{0}", erstellt von {1}, nun abgeschlossen ist. Vielen Dank an alle, die teilgenommen und wertvolles Feedback gegeben haben.
\
-Falls Sie den Einsendeschluss verpasst haben, möchten wir Sie dennoch ermutigen, uns Ihre Gedanken mitzuteilen. Auch wenn wir Ihre Antworten möglicherweise nicht in den offiziellen Ergebnissen berücksichtigen können, ist Ihr Feedback dennoch wertvoll für zukünftige Umfragen und Initiativen.
\
-Nochmals vielen Dank für Ihre Teilnahme.
\
-
\
-Freundliche Grüße,
\
+location=Ort
+owner=Ersteller
+
+
+
+#Umfrage wurde erstellt
+poll.mail.created.subject=Sie wurden zu einer Umfrage eingeladen mit dem Titel "{0}"
+poll.mail.created.content=Liebe Teilnehmerinnen und Teilnehmer,
\
+Wir möchten Ihnen mitteilen, dass eine Umfrage erstellt wurde mit dem Titel "{0}", und Sie wurden herzlichst eingeladen bei dieser Abzustimmen.
\
+Hier kommst du direkt zur Umfrage
\
+Mit Freundlichen Grüßen,
\
{1}
-poll.mail.ended.subject=Umfrage beendet
+
+
+
+#Umfrage wurde Bearbeitet
+poll.mail.update.subject=Umfrage wurde bearbeitet
+poll.mail.update.content=Liebe Teilnehmerinnen und Teilnehmer,
\
+Wir möchten Ihnen mitteilen, dass die Umfrage "{0}" kürzlich bearbeitet wurde.
\
+Falls Sie bereits Ihre Antworten eingereicht haben, sollten Sie überprüfen, ob wesentliche Änderungen vorgenommen wurden.
\
+Nochmals vielen Dank für Ihre Teilnahme.
\
+Mit Freundlichen Grüßen,
\
+{1}
+
+
+#Umfrage endet Bald
+poll.mail.endingSoon.subject=Umfrage endet in {0} Tagen
poll.mail.endingSoon.content=Liebe Teilnehmerinnen und Teilnehmer,
\
-wir möchten Sie daran erinnern, dass die Umfrage "{0}", erstellt von {1}, bald endet, nämlich am {2}. Bitte achten Sie darauf, Ihre Antworten vor dem Ablaufdatum einzureichen.
\
+wir möchten Sie daran erinnern, dass die Umfrage "{0}", erstellt von {1}, bald endet, nämlich am {2}. Bitte achten Sie darauf, Ihre Antworten vor dem Ablaufdatum einzureichen.
\
Falls Sie noch nicht die Gelegenheit hatten, an der Umfrage teilzunehmen, nehmen Sie sich bitte einen Moment Zeit, um dies zu tun, bevor die Umfrage geschlossen wird. Ihre Meinung ist wichtig und wertvoll.
\
{3}
\
-Vielen Dank für Ihre Aufmerksamkeit und einen schönen Tag!
\
+Vielen Dank für Ihre Aufmerksamkeit und einen schönen Tag!
\
\
-Freundliche Grüße,
\
+Mit Freundlichen Grüßen,
\
{1}
-poll.mail.endingSoon.subject=Umfrage endet in {0} Tagen
-poll.mail.update.content=Liebe Teilnehmerinnen und Teilnehmer,
\
-Wir möchten Ihnen mitteilen, dass die Umfrage "{0}" kürzlich bearbeitet wurde.
\
-Falls Sie bereits Ihre Antworten eingereicht haben, sollten Sie überprüfen, ob wesentliche Änderungen vorgenommen wurden.
\
-Nochmals vielen Dank für Ihre Teilnahme.
\
-Freundliche Grüße,
\
+
+
+
+
+#Umfrage beendet
+poll.mail.ended.subject=Die Umfrage mit dem Title "{0}" wurde Beendet
+poll.mail.ended.content=Liebe Teilnehmerinnen und Teilnehmer,
\
+Wir möchten Sie darüber informieren, dass die Umfrage "{0}", erstellt von {1}, nun abgeschlossen ist. Vielen Dank an alle, die Teilgenommen haben.
\
+Ihre Ergebnisse/Antworten können sie weiterhin sehen jedoch können sie selber diese nicht mehr bearbeiten.
\
+Falls Sie aber vergessen haben abzustimmen oder vielleicht noch etwas ändern möchten melden sie sich beim bei einer berechtigten Person oder beim ersteller in diesem Fall "{1}"
\
+
\
+Mit Freundlichen Grüßen,
\
{1}
-poll.mail.update.subject=Umfrage wurde bearbeitet
-poll.manual.multiResponse=Eine Frage, die bei der man eine Antwort auswählen kann. Gut geeignet für eine Datumsumfrage für Verfügbarkeiten.
-poll.manual.questions=Anschließend werden die Fragen der Umfrage angelegt. Die Fragen können aus verschiedenen Typen bestehen.
-poll.manual.singleResponse=Eine Frage, die bei der man eine Antwort auswählen kann. Beispielsweise für eine simple Ja- oder Nein-Frage.
-poll.manual.textQuestion=Eine Frage, die bei der man mit Freitext antworten kann. Gut geeignet für formloses Feedback.
-poll.manual.title=Anleitung, um eine Umfrage zu erstellen | Als Erstes muss man die Hauptinformationen der Umfrage ausfüllen.
+
+#Umfrage abgelaufen
+poll.mail.endedafterdeadline.subject=Die Umfrage mit dem Title "{0}" ist Beendet die Deadline ist abgelaufen
+poll.mail.endedafterdeadline.content=Liebe Teilnehmerinnen und Teilnehmer,
\
+Wir möchten Sie darüber informieren, dass die Umfrage "{0}", erstellt von {1}, nun abgeschlossen ist. Vielen Dank an alle, die Teilgenommen haben.
\
+Falls Sie vergessen haben abzustimmen oder vielleicht noch etwas ändern möchten melden sie sich beim ersteller der Umfrage in diesem fall "{1}"
\
+Falls sie sich nicht mehr sicher sind für was sie Abgestimmt haben oder was sie eingetragen haben im Anhang finden sie eine Excel datei mit allen Eingaben
\
+
\
+Mit Freundlichen Grüßen,
\
+{1}
+
+
+
+poll.manual.multiResponse=Eine Frage, die bei der man eine Antwort auswählen kann. Gut geeignet für eine Datumsumfrage für Verfügbarkeiten.
+poll.manual.questions=Anschließend werden die Fragen der Umfrage angelegt. Die Fragen können aus verschiedenen Typen bestehen.
+poll.manual.singleResponse=Eine Frage, die bei der man eine Antwort auswählen kann. Beispielsweise für eine simple Ja- oder Nein-Frage.
+poll.manual.textQuestion=Eine Frage, die bei der man mit Freitext antworten kann. Gut geeignet für formloses Feedback.
+poll.manual.title=Anleitung, um eine Umfrage zu erstellen | Als Erstes muss man den
poll.other=Andere
-poll.owner=Eigentümer:in
+poll.owner=Ersteller
poll.popup.closed=Umfrage wurde bereits beendet
-poll.question=Frage
-poll.question.textQuestion=Textfrage
-poll.questionType=Fragen Typ
+
+
+poll.question.text=Eingabe
+poll.question.single=Frage
+poll.question.multi=Frage
+
+
+poll.question.texttitle= Text Frage
+poll.question.singletitel= Eine Antwort Frage
+poll.question.multititle= Mehrere Antworten Frage
+
+
+
+#Kalender Monate
+January=Januar
+February=Februar
+March=März
+April=April
+May=Mai
+June=Juni
+July=Juli
+August=August
+September=September
+October=October
+November=November
+December=Dezember
+
+
+
+#Fragen Dropdown menü name
+poll.questionType=Fragetypen
+
+#Frage Typen endung
+poll.question.TextQuestion=Antwort
+poll.question.SingleResponseQuestion=Frage
+poll.question.MultiResponseQuestion=Frage
+
+#Fragen Container Überschrift
+TextQuestion=Frage mit freier text Antwort
+SingleResponseQuestion=Frage mit einer Ankreuzmöglichkeit
+MultiResponseQuestion=Frage mit mehreren Ankrauzmöglichkeiten
+
+#Fragen erstellung überschrift
+Question=Fragestellung
+
+#Eingabefeld überschriften/Auswahl möglichkeiten überschrift
+poll.answer=Auswahl möglichkeit
+
+PollState.RUNNING=Am Laufen
+question.answers.Yes=Ja
+question.answers=Ja
+question.answers.0=Ja
+question.answers.No=Nein
+question.answers.1=Nein
+
+
+
+
+
+
poll.respond=Antworten abschicken
+yes=Ja
+poll.questionType.TextQuestion=Text Frage
+poll.questionType.SingleResponseQuestion=Einzelantwort Frage
+poll.questionType.MultiResponseQuestion=Mehrfachauswahl Frage
+
+
+
+
### not translated: poll.response.mail.update.content=Dear {0},
\
#I wanted to inform you that Person {2} has updated their answer to Poll {1}.
\
#If you were not notified about this,
\
@@ -2145,41 +2258,54 @@ poll.respond=Antworten abschicken
### not translated: poll.response.mail.update.subject=Response was edited by {0}
poll.response.page=Seite zur Umfrageantwort
poll.response.title=Seite zur Umfrageantwort
-poll.running=Aktiv
-poll.selectUser=Nutzer auswählen
-poll.state=Status
+poll.selectUser=Nutzer auswählen
+
+
+
poll.title=Titel
poll.title.add=Neue Umfrage erstellen
poll.title.edit=Umfrage bearbeiten
poll.title.list=Umfragen
-poll.userDelegation=Für andere Nutzer abstimmen
+poll.userDelegation=Für andere Nutzer abstimmen
poll.yourAnswers=Deine Antworten
+
+
+
+
+
+
+
+
+
+
+
+
projectmanagement.personDays=Personentage
projectmanagement.personDays.short=PT
-question.deleteQuestion=Soll das Objekt wirklich unwiderruflich gelöscht werden?
-question.forceDeleteQuestion=ACHTUNG!!! Soll das Object tatsächlich uwiderruflich gelöscht werden? Es werden auch alle Einträge aus der Änderungshistorie zu diesem Object unwiderruflich gelöscht!!!!!!
-question.markAsDeletedQuestion=Soll das Objekt als gelöscht markiert werden?
-question.massUpdateQuestion=Sollen nun alle Objekte geändert werden?
-scripting.download.filename=Ergbnisdatei
-scripting.download.filename.additional=Download nur wenige Minuten verfügbar: bis {0}.
-scripting.download.filename.info=Downloaddatei der letzten Scriptausführung.
+question.deleteQuestion=Soll das Objekt wirklich unwiderruflich gelöscht werden?
+question.forceDeleteQuestion=ACHTUNG!!! Soll das Object tatsächlich unwiderruflich gelöscht werden? Es werden auch alle Einträge aus der Änderungshistorie zu diesem Object unwiderruflich gelöscht!!!!!!
+question.markAsDeletedQuestion=Soll das Objekt als gelöscht markiert werden?
+question.massUpdateQuestion=Sollen nun alle Objekte geändert werden?
+scripting.download.filename=Ergebnisdatei
+scripting.download.filename.additional=Download nur wenige Minuten verfügbar: bis {0}.
+scripting.download.filename.info=Downloaddatei der letzten Scriptausführung.
scripting.myScript.list=Meine Scripte
scripting.script=Script
-scripting.script.availableVariables=Verfügbare Variablen
-scripting.script.description.tooltip=Markdown-Format wird unterstützt.
+scripting.script.availableVariables=Verfügbare Variablen
+scripting.script.description.tooltip=Markdown-Format wird unterstützt.
scripting.script.downloadBackups=Download Backups
scripting.script.downloadEffectiveScript=Download Effektivscript
-scripting.script.downloadEffectiveScript.info=Das Effektivscript ist das Script mit aufgelösten Include-Dateien etc., welches so von der Scripting-Engine so ausgeführt wird.
-scripting.script.editForm.file.tooltip=Die Datei ist im Script über 'script.file' und der Dateiname über 'script.filename' erreichbar. Diese Datei ist aus Abwährtskompatibiltätsgründen noch nutzbar für ältere Scripte.
+scripting.script.downloadEffectiveScript.info=Das Effektivscript ist das Script mit aufgelösten Include-Dateien etc., welches so von der Scripting-Engine so ausgeführt wird.
+scripting.script.editForm.file.tooltip=Die Datei ist im Script über 'script.file' und der Dateiname über 'script.filename' erreichbar. Diese Datei ist aus Abwährtskompatibiltätsgründen noch nutzbar für ältere Scripte.
scripting.script.error.notFound=Script not found.
scripting.script.examples=Beispiele
scripting.script.executableByGroups=Berechtigte Gruppen
-scripting.script.executableByGroups.info=Angehörige dieser Gruppen dürfen dieses Script ausführen (nicht einsehen oder ändern).
+scripting.script.executableByGroups.info=Angehörige dieser Gruppen dürfen dieses Script ausführen (nicht einsehen oder ändern).
scripting.script.executableByUsers=Berechtigte Benutzer:innen
-scripting.script.executableByUsers.info=Diese dürfen dieses Script ausführen (nicht einsehen oder ändern).
-scripting.script.execute=Script ausführen
-scripting.script.executeAsUser=Als andere:r User:in ausführen
-scripting.script.executeAsUser.info=Das Script wird mit ALLEN Rechten dieser oder der Benutzer:in ausgeführt. Bitte vorsichtig verwenden! Im Script selber muss diese Funktion auch aktiviert werden, um Fehlkonfigurationen zu vermeiden.
+scripting.script.executableByUsers.info=Diese dürfen dieses Script ausführen (nicht einsehen oder ändern).
+scripting.script.execute=Script ausführen
+scripting.script.executeAsUser=Als andere:r User:in ausführen
+scripting.script.executeAsUser.info=Das Script wird mit ALLEN Rechten dieser oder der Benutzer:in ausgeführt. Bitte vorsichtig verwenden! Im Script selber muss diese Funktion auch aktiviert werden, um Fehlkonfigurationen zu vermeiden.
scripting.script.includes=Eingebundene Scripts
scripting.script.name=Name
scripting.script.parameter=Parameter
@@ -2209,16 +2335,16 @@ search.lastHour=Letzte Stunde
search.lastHours=Letzte {0} Stunden
search.lastMinute=Letzte Minute
search.lastMinutes=Letzte {0} Minuten
-search.lucene.expression=Modifizierter Ausdruck für Suchmaschine\:
-search.maxRowsExceeded=Die Maximalgröße {0} der Ergebnisliste ist überschritten und das Ergebnis enthält nicht alle gefundenen Elemente.
-search.nextDays=Nächste {0} Tage
+search.lucene.expression=Modifizierter Ausdruck für Suchmaschine\:
+search.maxRowsExceeded=Die Maximalgröße {0} der Ergebnisliste ist überschritten und das Ergebnis enthält nicht alle gefundenen Elemente.
+search.nextDays=Nächste {0} Tage
search.parseError=Fehler beim Vearbeiten des Suchtexts: ''{0}''
-search.periodOfModification=Änderungszeitraum
+search.periodOfModification=Änderungszeitraum
search.search=Suche
search.searchHistory=Historie
-search.searchHistory.additional.tooltip=Wenn gewählt, werden auch alle Änderungshistorieneinträge mit dem Suchausdruck durchsucht.
+search.searchHistory.additional.tooltip=Wenn gewählt, werden auch alle Änderungshistorieneinträge mit dem Suchausdruck durchsucht.
search.sinceYesterday=Seit gestern
-search.string.info=''*'' für Teilausdrücke (automatisch angehängt, wenn nur alphanumerische Ausdrücke angegeben inkl. Leerzeichen und "@._-"), ''-ausdruck'' für Ausschlüsse, ''Feldname\:Ausdruck'' für Teilwortsuche, s. auch Dokumentation (es wird Lucene als Suchmaschine eingesetzt).\nSuche in den Feldern\: {0}.
+search.string.info=''*'' für Teilausdrücke (automatisch angehängt, wenn nur alphanumerische Ausdrücke angegeben inkl. Leerzeichen und "@._-"), ''-ausdruck'' für Ausschlüsse, ''Feldname\:Ausdruck'' für Teilwortsuche, s. auch Dokumentation (es wird Lucene als Suchmaschine eingesetzt).\nSuche in den Feldern\: {0}.
search.string.info.title=Volltextsuche
search.title=Suche
search.today=Heute
@@ -2246,7 +2372,7 @@ space.title.edit=Space bearbeiten
space.title.heading=Spaces
space.title.list=Spaces
system.admin.adminLogViewer.title=Adminprotokoll einsehen
-system.admin.alertMessage.copyAndPaste.text=Achtung\: ProjectForge ist um 13\:00 Uhr für ca. 5 Minuten aufgrund von Wartungsarbeiten nicht erreichbar\! Es wird das neue Release {0} eingespielt.
+system.admin.alertMessage.copyAndPaste.text=Achtung\: ProjectForge ist um 13\:00 Uhr für ca. 5 Minuten aufgrund von Wartungsarbeiten nicht erreichbar\! Es wird das neue Release {0} eingespielt.
### not translated: system.admin.alertMessage.copyAndPaste.title=For copy & paste
### not translated: system.admin.button.checkI18nProperties=Check i18n properties
### not translated: system.admin.button.checkI18nProperties.tooltip=Check i18n properties for detecting missing translations in different languages.
@@ -2308,26 +2434,26 @@ system.admin.logViewer.userAgent=Browser
### not translated: system.pluginAdmin.title=Plugins
### not translated: system.statistics.databasePool=Data base pool
system.statistics.title=Systemstatistiken
-system.statistics.totalNumberOfHistoryEntries=Gesamtzahl aller Historierungseinträge
+system.statistics.totalNumberOfHistoryEntries=Gesamtzahl aller Historierungseinträge
system.statistics.totalNumberOfTasks=Gesamtzahl aller Strukturelemente
system.statistics.totalNumberOfTimesheets=Gesamtzahl der Zeitberichte
system.statistics.totalNumberOfUsers=Gesamtzahl der Benutzer:innen
-system.statistics.totalTimesheetDurations=Gesamtdauer über alle Zeitberichte [Tage]
+system.statistics.totalTimesheetDurations=Gesamtdauer über alle Zeitberichte [Tage]
task.assignedUser=Verantwortliche:r
task.consumption=Verbrauch
-task.deleted=gelöscht
-task.edit.maxHoursIngoredDueToAssignedOrders=Diese Angabe wird ggf. ignoriert. - Zu diesem Strukturelement oder einem Strukturunterelement wurden Aufträge zugeordnet. Die Angabe einer Null verhindert jedoch die Anzeige des Maximalwerts in den Verbrauchsbalken.
-task.error.couldNotDeleteRootTask=Das Wurzelstrukturelement kann nicht gelöscht werden!
-task.error.cyclicReference=Zyklische Strukturhierarchie entdeckt, weil ein Strukturelement sich selbst oder ein Strukturunterelement als übergeordnetes Strukturelement besitzt.
-task.error.duplicateChildTasks=Strukturelemente müssen als Unterelemente unterschiedliche Titel haben.
+task.deleted=gelöscht
+task.edit.maxHoursIngoredDueToAssignedOrders=Diese Angabe wird ggf. ignoriert. - Zu diesem Strukturelement oder einem Strukturunterelement wurden Aufträge zugeordnet. Die Angabe einer Null verhindert jedoch die Anzeige des Maximalwerts in den Verbrauchsbalken.
+task.error.couldNotDeleteRootTask=Das Wurzelstrukturelement kann nicht gelöscht werden!
+task.error.cyclicReference=Zyklische Strukturhierarchie entdeckt, weil ein Strukturelement sich selbst oder ein Strukturunterelement als übergeordnetes Strukturelement besitzt.
+task.error.duplicateChildTasks=Strukturelemente müssen als Unterelemente unterschiedliche Titel haben.
task.error.kost2Readonly=Eine Kost2-Zuordnung kann nur durch die Buchhaltung vorgenommen werden.
-task.error.parentTaskNotFound=Übergeordnetes Strukturelement wird benötigt, konnte aber nicht gefunden werden.
+task.error.parentTaskNotFound=Ãœbergeordnetes Strukturelement wird benötigt, konnte aber nicht gefunden werden.
task.error.parentTaskNotGiven=Ãœbergeordnetes Strukturelement muss angegeben sein.
-task.error.protectionOfPrivacyReadonly=Die Datenschutzoption kann nur durch die Buchhaltung geändert werden.
+task.error.protectionOfPrivacyReadonly=Die Datenschutzoption kann nur durch die Buchhaltung geändert werden.
task.error.protectTimesheetsUntilReadonly=Der Zeitberichtsschutz kann nur durch die Buchhaltung manipuliert werden.
-task.error.timesheetBookingStatus2Readonly=Der Status für Zeitberichtsbuchungen kann nur durch die Buchhaltung oder Projektmanager manipuliert werden.
+task.error.timesheetBookingStatus2Readonly=Der Status für Zeitberichtsbuchungen kann nur durch die Buchhaltung oder Projektmanager manipuliert werden.
task.favorite.new=Neuer Strukturelementfavorit
-task.favorite.new.tooltip=Das aktuell ausgewählte Strukturelement kann hier unter einem Namen als Favorit gespeichert werden.
+task.favorite.new.tooltip=Das aktuell ausgewählte Strukturelement kann hier unter einem Namen als Favorit gespeichert werden.
task.favorites.tooltip=Verwaltung von Strukturelementen als Favoriten
task.gantt.settings=Ganttwerte
task.kost2list.blackList=Negativliste
@@ -2341,17 +2467,17 @@ task.menu.showTimesheets=Zeitberichte anzeigen
task.onlyBillable=nur fakturierbare Elemente
task.parentTask=Ãœbergeordnetes Strukturelement
task.path=Strukturhierarchie
-task.path.pleaseSelectTask=Bitte Strukturelement wählen
+task.path.pleaseSelectTask=Bitte Strukturelement wählen
task.path.rootTask=Toplevel
task.progress=Fortschritt
task.protectionOfPrivacy=Datenschutz
-task.protectionOfPrivacy.tooltip=Wenn diese Option gewählt wird, dann kann nicht auf die Zeitberichte anderer Benutzer:innen unterhalb dieses Tasks zugegriffen werden.
+task.protectionOfPrivacy.tooltip=Wenn diese Option gewählt wird, dann kann nicht auf die Zeitberichte anderer Benutzer:innen unterhalb dieses Tasks zugegriffen werden.
task.protectTimesheetsUntil=Zeitberichtsschutz bis
task.protectTimesheetsUntil.short=Schutz bis
task.recursive=inkl. aller Strukturunterelemente
task.reference=Referenz
task.selectPanel.displayTask.tooltip=Strukturelement anzeigen.
-task.selectPanel.info=Ordnerelement können ausgewählt werden, indem in eine andere Spalte geklickt wird (außer der ersten).
+task.selectPanel.info=Ordnerelement können ausgewählt werden, indem in eine andere Spalte geklickt wird (außer der ersten).
task.selectPanel.noTasksFound=Keine Strukturelemente gefunden.
task.selectPanel.selectAncestorTask.tooltip=Strukturelement durch dieses Strukturoberelement ersetzen.
task.status=Status des Strukturelements
@@ -2362,79 +2488,79 @@ task.tasks=Strukturelemente
task.timesheetBooking=Zeitbuchungen
task.timesheetBooking.inherit=vererbt
task.timesheetBooking.noBooking=keine Buchungen
-task.timesheetBooking.onlyLeafs=nur Strukturelementblätter
-task.timesheetBooking.opened=geöffnet
+task.timesheetBooking.onlyLeafs=nur Strukturelementblätter
+task.timesheetBooking.opened=geöffnet
task.timesheetBooking.treeClosed=komplett geschlossen
task.title=Titel
task.title.add=Neues Strukturelement
task.title.edit=Strukturelement bearbeiten
task.title.heading=Strukturelemente
task.title.list=Strukturelemente
-task.title.list.select=Strukturelement auswählen
+task.title.list.select=Strukturelement auswählen
task.tree.close=Strukturelement zuklappen
task.tree.explore=Alle Strukturelemente auf-/zuklappen
-task.tree.info=Strukturelemente können auf- und zugeklappt werden, indem auf die Ordnersymbole oder Titel des gewünschten Strukturelements geklickt wird. Zur Auswahl eines Strukturelements kann jede andere Stelle innerhalb der Zeile angeklickt werden.
+task.tree.info=Strukturelemente können auf- und zugeklappt werden, indem auf die Ordnersymbole oder Titel des gewünschten Strukturelements geklickt wird. Zur Auswahl eines Strukturelements kann jede andere Stelle innerhalb der Zeile angeklickt werden.
task.tree.open=Strukturelement aufklappen
task.tree.perspective=Baumansicht
task.tree.rootNode=Wurzelstrukturelement
task.tree.title=Strukturbaum
-task.tree.title.select=Strukturelement auswählen
+task.tree.title.select=Strukturelement auswählen
task.wizard.action=Aktion
-task.wizard.action.noactionRequired=Keine Aktion notwendig, da keine Gruppen ausgewählt wurden. Demnach müssen keine Zugriffsrechte angelegt werden.
-task.wizard.action.taskAndgroupsGiven=Die notwendigen Zugriffsrechte für die oben angegebene(n) Gruppe(n) werden angelegt, nachdem der Anlegen-Button gedrückt wird. Diese können Sie jederzeit unter dem Menüpunkt Zugriffsverwaltung einsehen und ändern.
+task.wizard.action.noactionRequired=Keine Aktion notwendig, da keine Gruppen ausgewählt wurden. Demnach müssen keine Zugriffsrechte angelegt werden.
+task.wizard.action.taskAndgroupsGiven=Die notwendigen Zugriffsrechte für die oben angegebene(n) Gruppe(n) werden angelegt, nachdem der Anlegen-Button gedrückt wird. Diese können Sie jederzeit unter dem Menüpunkt Zugriffsverwaltung einsehen und ändern.
task.wizard.button.createGroup=Gruppe anlegen
-task.wizard.button.createGroup.tooltip=Sie können eine existierende Benutzergruppe wählen oder eine neue durch Anklicken dieses Buttons anlegen.
+task.wizard.button.createGroup.tooltip=Sie können eine existierende Benutzergruppe wählen oder eine neue durch Anklicken dieses Buttons anlegen.
task.wizard.button.createTask=Strukturelement anlegen
-task.wizard.button.createTask.tooltip=Sie können ein existierendes Strukturelement wählen oder ein neues durch Anklicken dieses Buttons anlegen.
+task.wizard.button.createTask.tooltip=Sie können ein existierendes Strukturelement wählen oder ein neues durch Anklicken dieses Buttons anlegen.
task.wizard.finish=Fertig stellen
-task.wizard.intro=Benutzen Sie diesen Assistenten, um ein neues Strukturelement anzulegen. Dieses Strukturelement kann ein Projekt o. ä. repräsentieren auf welche Nutzer und Gruppen Zugriff haben sollen (z. B. für Zeitberichtserfassungen).
+task.wizard.intro=Benutzen Sie diesen Assistenten, um ein neues Strukturelement anzulegen. Dieses Strukturelement kann ein Projekt o. ä. repräsentieren auf welche Nutzer und Gruppen Zugriff haben sollen (z. B. für Zeitberichtserfassungen).
task.wizard.managerGroup=Teammanager:in (optional)
task.wizard.managerGroup.groupNameSuffix=Projektmanagement
-task.wizard.managerGroup.intro=Die Teammanager:innen haben mehr Rechte, so dürfen sie beispielsweise die Zeitberichte anderer Nutzer ändern. Wenn sie die Rolle Projektmanagement (Gruppe PF_MANAGER) haben, dürfen sie auch HR-Planungen vornehmen.
+task.wizard.managerGroup.intro=Die Teammanager:innen haben mehr Rechte, so dürfen sie beispielsweise die Zeitberichte anderer Nutzer ändern. Wenn sie die Rolle Projektmanagement (Gruppe PF_MANAGER) haben, dürfen sie auch HR-Planungen vornehmen.
task.wizard.pageTitle=Strukturassistent
-task.wizard.task.intro=Für dieses Strukturelement sollen die Rechte automatisch für die unten angegebenen Gruppen eingerichtet werden. Dabei wird für alle Oberelemente ein minimales Leserecht, so dass aus der Baumansicht dieses Element für die Gruppen eingesehen werden kann. Andere Elemente aus höheren Ebenen bleiben unsichtbar.
+task.wizard.task.intro=Für dieses Strukturelement sollen die Rechte automatisch für die unten angegebenen Gruppen eingerichtet werden. Dabei wird für alle Oberelemente ein minimales Leserecht, so dass aus der Baumansicht dieses Element für die Gruppen eingesehen werden kann. Andere Elemente aus höheren Ebenen bleiben unsichtbar.
task.wizard.team=Team (optional)
-task.wizard.team.intro=Die Teammitglieder haben das Recht, Strukturunterelemente anzulegen oder zu ändern, sowie eigene Zeitberichte zu erfassen.
+task.wizard.team.intro=Die Teammitglieder haben das Recht, Strukturunterelemente anzulegen oder zu ändern, sowie eigene Zeitberichte zu erfassen.
timePeriodPanel.startTimeAfterStopTime=Der Beginn muss vor dem Ende liegen.
timesheet=Zeitbericht
timesheet.break=leer
-timesheet.description=Tätigkeitsbericht
+timesheet.description=Tätigkeitsbericht
timesheet.duration=Dauer
-timesheet.error.copyNoMatchingKost2=Keine Kost2 Id für diese Zeiberichtskopie verfügbar oder keine übereinstimmende mit dem Orginal gefunden. Wahrscheinlich wurde das Strukturelement des Zeitberichts in einen anderen Unterbaum verschoben. Zur Lösung des Problems bitte manuell Kost2 Id wählen.
+timesheet.error.copyNoMatchingKost2=Keine Kost2 Id für diese Zeiberichtskopie verfügbar oder keine übereinstimmende mit dem Orginal gefunden. Wahrscheinlich wurde das Strukturelement des Zeitberichts in einen anderen Unterbaum verschoben. Zur Lösung des Problems bitte manuell Kost2 Id wählen.
timesheet.error.filter.needMore=Zu wenige Filterangaben: Bitte Datum und/oder Strukturelement angeben.
-timesheet.error.invalidKost2=Keine gültige Kost2 Id.
+timesheet.error.invalidKost2=Keine gültige Kost2 Id.
timesheet.error.invalidTaskId=Das Strukturelement wurde leider nicht gefunden.
-timesheet.error.kost2NeededChooseSubTask=Bitte Kost2 auswählen und ggf. Strukturunterelement mit Kost2s bebuchen.
-timesheet.error.kost2Required=Bitte Kost2 auswählen.
-timesheet.error.massupdate.couldnotconvertkost2=Massenänderung für Zeitbericht nicht möglich. Das Ziel-Strukturelement hat mehrere Kost2-Einträge aber es gibt keine passende Kost2-Art.
-timesheet.error.massupdate.kost2notsupported=Massenänderung für Zeitbericht nicht möglich. Das Ziel-Strukturelement unterstützt nicht die gewählte Kost2.
-timesheet.error.massupdate.kost2null=Massenänderung für Zeitbericht nicht möglich. Für das Ziel-Strukturelement wird eine Kost2 benötigt.
-timesheet.error.maximumDurationExceeded=Maximal zugelassene Dauer überschritten.
-timesheet.error.noAccess=Fehlende Berechtigung für die ausgewählte Aktion.
-timesheet.error.overlapping=Die ausgewählte Aktion ist aufgrund einer zeitlichen Überschneidung nicht möglich.
-timesheet.error.taskNotBookable.onlyLeafsAllowedForBooking=Das Strukturelement {0} kann nicht bebucht werden, da nur Strukturblätterelemente (d. h. Strukturelemente ohne Unterelementen) bebucht werden können.
+timesheet.error.kost2NeededChooseSubTask=Bitte Kost2 auswählen und ggf. Strukturunterelement mit Kost2s bebuchen.
+timesheet.error.kost2Required=Bitte Kost2 auswählen.
+timesheet.error.massupdate.couldnotconvertkost2=Massenänderung für Zeitbericht nicht möglich. Das Ziel-Strukturelement hat mehrere Kost2-Einträge aber es gibt keine passende Kost2-Art.
+timesheet.error.massupdate.kost2notsupported=Massenänderung für Zeitbericht nicht möglich. Das Ziel-Strukturelement unterstützt nicht die gewählte Kost2.
+timesheet.error.massupdate.kost2null=Massenänderung für Zeitbericht nicht möglich. Für das Ziel-Strukturelement wird eine Kost2 benötigt.
+timesheet.error.maximumDurationExceeded=Maximal zugelassene Dauer überschritten.
+timesheet.error.noAccess=Fehlende Berechtigung für die ausgewählte Aktion.
+timesheet.error.overlapping=Die ausgewählte Aktion ist aufgrund einer zeitlichen Ãœberschneidung nicht möglich.
+timesheet.error.taskNotBookable.onlyLeafsAllowedForBooking=Das Strukturelement {0} kann nicht bebucht werden, da nur Strukturblätterelemente (d. h. Strukturelemente ohne Unterelementen) bebucht werden können.
timesheet.error.taskNotBookable.orderPositionsFoundInSubTasks=Das Strukturelement {0} kann nicht bebucht werden, da Auftragszuordnungen in Unterelementen existieren.
-timesheet.error.taskNotBookable.taskClosedForBooking=Das Strukturelement {0} kann nicht bebucht werden, da es für Zeitberichtsbuchungen geschlossen ist.
-timesheet.error.taskNotBookable.taskDeleted=Das Strukturelement {0} kann nicht bebucht werden, da es gelöscht ist.
-timesheet.error.taskNotBookable.taskNotOpened=Das Strukturelement {0} kann nicht bebucht werden, da es nicht geöffnet ist.
-timesheet.error.taskNotBookable.treeClosedForBooking=Das Strukturelement {0} kann nicht bebucht werden, da der komplette Strukturbaum für Zeitberichtsbuchungen geschlossen ist.
+timesheet.error.taskNotBookable.taskClosedForBooking=Das Strukturelement {0} kann nicht bebucht werden, da es für Zeitberichtsbuchungen geschlossen ist.
+timesheet.error.taskNotBookable.taskDeleted=Das Strukturelement {0} kann nicht bebucht werden, da es gelöscht ist.
+timesheet.error.taskNotBookable.taskNotOpened=Das Strukturelement {0} kann nicht bebucht werden, da es nicht geöffnet ist.
+timesheet.error.taskNotBookable.treeClosedForBooking=Das Strukturelement {0} kann nicht bebucht werden, da der komplette Strukturbaum für Zeitberichtsbuchungen geschlossen ist.
timesheet.error.timeperiodOverlapDetection=Der Zeitbericht kollidiert mit dem Zeitbericht #{0} (gleiche:r Benutzer:in) von {1} bis {2}.
-timesheet.error.timesheetProtectionVioloation=Der Zeitbericht verletzt den Zeitberichtsschutz des Strukturelements ''{0}'', welcher bis einschließlich {1} gesetzt ist. Bitte Rücksprache mit der Buchhaltung nehmen.
+timesheet.error.timesheetProtectionVioloation=Der Zeitbericht verletzt den Zeitberichtsschutz des Strukturelements ''{0}'', welcher bis einschließlich {1} gesetzt ist. Bitte Rücksprache mit der Buchhaltung nehmen.
timesheet.error.zeroDuration=Der Zeitbericht hat keine Dauer.
timesheet.filter.withTimeperiodCollision=Nur kollidierte
-timesheet.filter.withTimeperiodCollision.tooltip=Es werden nur Zeitberichte angezeigt, die mit anderen Zeitberichten (gleiche:r Nutzer:in) kollidieren (sich überlappen).
-timesheet.iCalSubscription=Zeitberichte im iCal-Format für den/die angemeldete:n Benutzer:in exportieren (*.ics).
+timesheet.filter.withTimeperiodCollision.tooltip=Es werden nur Zeitberichte angezeigt, die mit anderen Zeitberichten (gleiche:r Nutzer:in) kollidieren (sich überlappen).
+timesheet.iCalSubscription=Zeitberichte im iCal-Format für den/die angemeldete:n Benutzer:in exportieren (*.ics).
timesheet.icsExport=ics-Export
timesheet.location=Ort
-timesheet.location.tooltip=Einträge aus der Vorschlagsliste können entfernt werden, indem einfach das Entfernen-Symbol (Kreuz) am Ende der Zeile des zu löschenden Orts geklickt wird. Entfernte Orte können wieder aufgenommen werden, indem sie einfach wieder erneut verwendet werden.
-timesheet.massupdate.kost.info=Wenn Zeitberichte eines Projekts zu einem anderen transferiert werden, wird der Kostenträger automatisch migriert, falls möglich, d. h. die Kostenart (letzte beiden Ziffern) bleibt erhalten.
-timesheet.massupdate.updateTask=Strukturelement für alle Zeitberichte ändern
+timesheet.location.tooltip=Einträge aus der Vorschlagsliste können entfernt werden, indem einfach das Entfernen-Symbol (Kreuz) am Ende der Zeile des zu löschenden Orts geklickt wird. Entfernte Orte können wieder aufgenommen werden, indem sie einfach wieder erneut verwendet werden.
+timesheet.massupdate.kost.info=Wenn Zeitberichte eines Projekts zu einem anderen transferiert werden, wird der Kostenträger automatisch migriert, falls möglich, d. h. die Kostenart (letzte beiden Ziffern) bleibt erhalten.
+timesheet.massupdate.updateTask=Strukturelement für alle Zeitberichte ändern
timesheet.multiselected.title=Mehrfachauswahl Zeitberichte
timesheet.recent=Zuletzt verwendet
timesheet.recent.select=Zuletzt bearbeitete Berichte zur Auswahl
timesheet.recenttasks.select=--- Zuletzt verwendete Strukturelemente ---
timesheet.reference=Referenz
-timesheet.reference.info=Referenzen können zur Gruppierung von Zeitberichten genutzt werden. Bereits benutzte Referenzen in Zeitberichten in der Hierarchie des Strukturelements (auch von anderen Usern) können per Autovervollständigung genutzt werden.
+timesheet.reference.info=Referenzen können zur Gruppierung von Zeitberichten genutzt werden. Bereits benutzte Referenzen in Zeitberichten in der Hierarchie des Strukturelements (auch von anderen Usern) können per Autovervollständigung genutzt werden.
timesheet.signatureEmployee=Unterschrift Mitarbeiter:in
timesheet.signatureProjectLeader=Unterschrift Projektmanagement
timesheet.startTime=Beginn
@@ -2443,10 +2569,10 @@ timesheet.tag=Etikett
timesheet.taskReference=Elementreferenz
timesheet.templates=Vorlagen
timesheet.templates.migrationOfLegacy.button=Alte Vorlagen
-timesheet.templates.migrationOfLegacy.confirmationMessage=Sollen alte Vorlagen jetzt übernommen werden? Vorhandene Vorlagen werden nicht überschrieben.
+timesheet.templates.migrationOfLegacy.confirmationMessage=Sollen alte Vorlagen jetzt übernommen werden? Vorhandene Vorlagen werden nicht überschrieben.
timesheet.templates.migrationOfLegacy.tooltip=Ãœbernehmen alter Vorlagen der klassischen Version.
timesheet.templates.new=Neue Vorlage
-timesheet.templates.new.tooltip=Du kannst dieses Formular ausfüllen und anschließend als Vorlage definieren, indem du hier einen Namen vergibst.
+timesheet.templates.new.tooltip=Du kannst dieses Formular ausfüllen und anschließend als Vorlage definieren, indem du hier einen Namen vergibst.
timesheet.timesheets=Zeitberichte
timesheet.title.add=Neuer Zeitbericht
timesheet.title.edit=Zeitbericht bearbeiten
@@ -2454,43 +2580,43 @@ timesheet.title.heading=Zeitberichte
timesheet.title.list=Zeitberichte
timesheet.totalDuration=Gesamtdauer
timesheet.user=Mitarbeiter:in
-tooltip.accesskey.addEntry=Je nach Browser\: STRG-N, ALT-N, ALT-Shift-N etc. drücken
-tooltip.accesskey.addEntry.title=Tastaturkürzel N
-tooltip.assign=Selektierte Einträge zuweisen
+tooltip.accesskey.addEntry=Je nach Browser\: STRG-N, ALT-N, ALT-Shift-N etc. drücken
+tooltip.accesskey.addEntry.title=Tastaturkürzel N
+tooltip.assign=Selektierte Einträge zuweisen
tooltip.autocomplete.language=Ãœber einen Doppelklick auf das Feld werden auch alle von allen Benutzer:innen bisher verwendeten Sprachen angezeigt.
-tooltip.autocomplete.recentSearchTerms=Über einen Doppelklick auf das Feld werden die zuletzt verwendeten Suchausdrücke zur Auswahl angezeigt.
+tooltip.autocomplete.recentSearchTerms=Ãœber einen Doppelklick auf das Feld werden die zuletzt verwendeten Suchausdrücke zur Auswahl angezeigt.
tooltip.autocomplete.timeZone=Ãœber einen Doppelklick auf das Feld werden auch alle von allen Benutzer:innen bisher verwendeten Zeitzonen angezeigt.
tooltip.autocomplete.withDblClickFunction=Ãœber einen Doppelklick auf das Feld werden die Favoriten zur Auswahl angezeigt.
-tooltip.autocompletion.title=Autovervollständigung
+tooltip.autocompletion.title=Autovervollständigung
tooltip.cancel=Abbrechen
-tooltip.entry.delete=Eintrag löschen
-tooltip.entry.markAsDeleted=Eintrag als gelöscht markieren
+tooltip.entry.delete=Eintrag löschen
+tooltip.entry.markAsDeleted=Eintrag als gelöscht markieren
tooltip.entry.undelete=Eintrag wiederherstellen
tooltip.export.excel=Export im Excelformat
tooltip.export.pdf=Export als pdf
tooltip.hideBirthdays=Geburtstage ausblenden
-tooltip.jiraSupport.field.content=Es werden JIRA-Issues von diesem Feld unterstützt, d. h. JIRA-Issues der Form PROJECTFORGE-123 werden als JIRA-Link angezeigt.
+tooltip.jiraSupport.field.content=Es werden JIRA-Issues von diesem Feld unterstützt, d. h. JIRA-Issues der Form PROJECTFORGE-123 werden als JIRA-Link angezeigt.
tooltip.jiraSupport.field.title=JIRA-Support
tooltip.lucene.link=Link zur Lucene-Abfrage-Syntax.
-tooltip.popups.mustBeAllowed=Bitte beachten: Für diese Funktion müssen Popups in Ihrem Browser erlaubt sein.
+tooltip.popups.mustBeAllowed=Bitte beachten: Für diese Funktion müssen Popups in Ihrem Browser erlaubt sein.
tooltip.reload=Neu laden
-tooltip.selectBirthday=Geburtstag wählen
-tooltip.selectDate=Datum wählen
-tooltip.selectDateOrPeriod=Datum oder Zeitraum wählen
-tooltip.selectGroup=Gruppe wählen
+tooltip.selectBirthday=Geburtstag wählen
+tooltip.selectDate=Datum wählen
+tooltip.selectDateOrPeriod=Datum oder Zeitraum wählen
+tooltip.selectGroup=Gruppe wählen
tooltip.selectMe=You are great!
-tooltip.selectTask=Strukturelement wählen
-tooltip.selectUser=Benutzer:in wählen
-tooltip.unassign=Zuweisung für selektierte Einträge aufheben
+tooltip.selectTask=Strukturelement wählen
+tooltip.selectUser=Benutzer:in wählen
+tooltip.unassign=Zuweisung für selektierte Einträge aufheben
tooltip.unselect=Auswahl aufheben
-tooltip.unselectBirthday=Geburtstag löschen
+tooltip.unselectBirthday=Geburtstag löschen
tooltip.unselectDate=Datumswahl aufheben
tooltip.unselectGroup=Gruppenauswahl aufheben
tooltip.unselectTask=Strukturelementwahl aufheben
tooltip.unselectUser=Benutzer:innenwahl aufheben
-tutorial.expectedGroupNotFound=Die benötigte Gruppe ''{0}'' ist noch nicht angelegt. Die Tutorialanfrage kann deshalb nicht bearbeitet werden.
-tutorial.expectedTaskNotFound=Das benötigte Strukturelement ''{0}'' ist noch nicht angelegt. Die Tutorialanfrage kann deshalb nicht bearbeitet werden.
-tutorial.expectedUserNotFound=Der benötigte Benutzer ''{0}'' ist noch nicht angelegt. Die Tutorialanfrage kann deshalb nicht bearbeitet werden.
+tutorial.expectedGroupNotFound=Die benötigte Gruppe ''{0}'' ist noch nicht angelegt. Die Tutorialanfrage kann deshalb nicht bearbeitet werden.
+tutorial.expectedTaskNotFound=Das benötigte Strukturelement ''{0}'' ist noch nicht angelegt. Die Tutorialanfrage kann deshalb nicht bearbeitet werden.
+tutorial.expectedUserNotFound=Der benötigte Benutzer ''{0}'' ist noch nicht angelegt. Die Tutorialanfrage kann deshalb nicht bearbeitet werden.
tutorial.objectAlreadyCreated=Die Tutorialanfrage kann nicht bearbeitet werden, da das angefragte Objekt bereits existiert.
tutorial.unknown=Die Tutorialanfrage kann nicht bearbeitet werden.
user.activated=Aktiviert
@@ -2499,46 +2625,46 @@ user.add.optionalPassword=Hier kann optional ein Erstpasswort vergeben werden.
user.adminUsers=Administrator:innen
user.adminUsers.none=Nichtadministrator:innen
user.assignedGroups=Assoziierte Gruppen
-user.authenticationToken.authenticator_key=Schlüssel für Zweifaktor-Authentifizierung
-user.authenticationToken.authenticator_key.tooltip=Dieser Schlüssel kann für die Zweifaktor-Authentifizierung z. B. über die Apps Microsoft-, Google Authenticator oder Fortitoken benutzt werden.
+user.authenticationToken.authenticator_key=Schlüssel für Zweifaktor-Authentifizierung
+user.authenticationToken.authenticator_key.tooltip=Dieser Schlüssel kann für die Zweifaktor-Authentifizierung z. B. über die Apps Microsoft-, Google Authenticator oder Fortitoken benutzt werden.
user.authenticationToken.button.showUsage=Info
-user.authenticationToken.button.showUsage.tooltip=Benutzung dieses Schüssels
-user.authenticationToken.calendar_rest=Schlüssel für Kalenderexport
-user.authenticationToken.calendar_rest.tooltip=Dieser persönliche Schlüssel kann zum Export/Abonnement von Kalendern oder Zeitberichten verwendet werden.
-user.authenticationToken.dav_token=Schlüssel für CalDav/CardDAV
-user.authenticationToken.dav_token.tooltip=Dieser persönliche Schlüssel kann zur Benutzung der CardDAV/CalDAV-Funktion verwendet werden.
+user.authenticationToken.button.showUsage.tooltip=Benutzung dieses Schüssels
+user.authenticationToken.calendar_rest=Schlüssel für Kalenderexport
+user.authenticationToken.calendar_rest.tooltip=Dieser persönliche Schlüssel kann zum Export/Abonnement von Kalendern oder Zeitberichten verwendet werden.
+user.authenticationToken.dav_token=Schlüssel für CalDav/CardDAV
+user.authenticationToken.dav_token.tooltip=Dieser persönliche Schlüssel kann zur Benutzung der CardDAV/CalDAV-Funktion verwendet werden.
user.authenticationToken.renew=Erneuern
-user.authenticationToken.renew.securityQuestion=Soll der Schlüssel wirklich unwiderrufbar erneuert werden?
-user.authenticationToken.renew.successful=Der Schlüssel wurde erneuert und ist ab sofort gültig.
-user.authenticationToken.renew.tooltip=Der Schlüssel kann erneuert werden, wenn der Verdacht auf einen möglichen Missbrauch vorliegt. Nach der Erneuerung sind vorher benutzte Schlüssel ungültig. Bitte beachten: Diese Operation ist unwiderruflich!
-user.authenticationToken.rest_client=Schlüssel für Rest-Clients
-user.authenticationToken.rest_client.tooltip=Dieser persönliche Schlüssel kann zur Benutzung in Rest-Clients verwendet werden, wenn das ProjectForge-Passwort dort nicht verwendet werden soll.
-user.authenticationToken.stay_logged_in_key=Schlüssel für Angemeldet-Bleiben-Funktion
-user.authenticationToken.stay_logged_in_key.tooltip=Dieser persönliche Schlüssel wird für die Angemeldet-Bleiben-Funktion im Browser verwendet und als Cookie im Browser gespeichert. Durch Erneuern können alle Browsersitzungen beendet werden.
+user.authenticationToken.renew.securityQuestion=Soll der Schlüssel wirklich unwiderrufbar erneuert werden?
+user.authenticationToken.renew.successful=Der Schlüssel wurde erneuert und ist ab sofort gültig.
+user.authenticationToken.renew.tooltip=Der Schlüssel kann erneuert werden, wenn der Verdacht auf einen möglichen Missbrauch vorliegt. Nach der Erneuerung sind vorher benutzte Schlüssel ungültig. Bitte beachten: Diese Operation ist unwiderruflich!
+user.authenticationToken.rest_client=Schlüssel für Rest-Clients
+user.authenticationToken.rest_client.tooltip=Dieser persönliche Schlüssel kann zur Benutzung in Rest-Clients verwendet werden, wenn das ProjectForge-Passwort dort nicht verwendet werden soll.
+user.authenticationToken.stay_logged_in_key=Schlüssel für Angemeldet-Bleiben-Funktion
+user.authenticationToken.stay_logged_in_key.tooltip=Dieser persönliche Schlüssel wird für die Angemeldet-Bleiben-Funktion im Browser verwendet und als Cookie im Browser gespeichert. Durch Erneuern können alle Browsersitzungen beendet werden.
user.changePassword.error.noCharacter=Passwort muss mindestens einen Buchstaben haben.
user.changePassword.error.noNonCharacter=Passwort muss mindestens einen Nicht-Buchstaben haben.
user.changePassword.error.notMinLength=Passwort muss mindestens {0} Zeichen haben.
user.changePassword.error.oldPasswdEqualsNew=Neues Passwort darf nicht dem alten entsprechen.
user.changePassword.error.oldPasswordWrong=Das alte Passwort wurde nicht korrekt eingegeben.
user.changePassword.error.passwordQualityCheck=Passwort muss mindestens {0} Zeichen und sowohl mindestens einen Buchstaben als auch einen Nicht-Buchstaben enthalten.
-user.changePassword.msg.passwordSuccessfullyChanged=Passwort wurde erfolgreich geändert.
+user.changePassword.msg.passwordSuccessfullyChanged=Passwort wurde erfolgreich geändert.
user.changePassword.newPassword=Neues Passwort
-user.changePassword.notSupported=Die Passwortänderung wird nicht unterstützt. Kontaktieren Sie Ihre:n Administrator:in.
+user.changePassword.notSupported=Die Passwortänderung wird nicht unterstützt. Kontaktieren Sie Ihre:n Administrator:in.
user.changePassword.oldPassword=Altes Passwort
-user.changePassword.password.lastChange=Letzte Passwortänderung
-user.changePassword.title=Eigenes Passwort ändern
+user.changePassword.password.lastChange=Letzte Passwortänderung
+user.changePassword.title=Eigenes Passwort ändern
user.changeWlanPassword.error.loginPasswordWrong=Das Login-Passwort wurde nicht korrekt eingegeben.
-user.changeWlanPassword.lastChange=Letzte WLAN/Samba-Passwortänderung
+user.changeWlanPassword.lastChange=Letzte WLAN/Samba-Passwortänderung
user.changeWlanPassword.loginPassword=Login-Passwort
user.changeWlanPassword.newPassword=Neues WLAN-Passwort
-user.changeWlanPassword.title=WLAN/Samba Passwort ändern
+user.changeWlanPassword.title=WLAN/Samba Passwort ändern
user.deactivated=Deaktiviert
user.defaultLocale=Default (Browser)
-user.error.passwordAndRepeatDoesNotMatch=Passwort und Passwortwiederholung stimmen nicht überein.
+user.error.passwordAndRepeatDoesNotMatch=Passwort und Passwortwiederholung stimmen nicht überein.
user.error.usernameAlreadyExists=Benutzer:inname ist bereits vergeben.
user.filter.hrPlanning=Personalplanung
user.filter.privileged=Privilegierte Benutzer:innen
-user.filter.restricted=Eingeschränkte Benutzer:innen
+user.filter.restricted=Eingeschränkte Benutzer:innen
user.filter.status=Status
user.filter.syncStatus=Synchronisationsstatus
user.filter.type=Typ
@@ -2547,119 +2673,119 @@ user.hrPlanningEnabled=Personalplanung
user.hrPlanningEnabled.not=keine Personalplanung
user.hrPlanningEnabled.tooltip=Soll der oder die Benutzer:in in der Personalplanung sichtbar sein?
user.jiraUsername=JIRA Benutzer:inname
-user.jiraUsername.tooltip=Wird nur gebraucht, wenn dieser von dem ProjectForge-Benutzer:innamen abweicht und der oder die Benutzer:in aus ProjectForge heraus mit JIRA arbeiten möchte.
+user.jiraUsername.tooltip=Wird nur gebraucht, wenn dieser von dem ProjectForge-Benutzer:innamen abweicht und der oder die Benutzer:in aus ProjectForge heraus mit JIRA arbeiten möchte.
user.ldapValues=LDAP
-user.list.select.title=Benutzer:in auswählen
+user.list.select.title=Benutzer:in auswählen
user.locale=Sprache
user.localUser=Lokale:r Benutzer:in
user.localUser.not=Allgemeine:r Benutzer:in
user.localUser.tooltip=Lokale Benutzer:innen werden nicht mit einem externen Benutzer:innensystem synchronisiert (z. B. LDAP).
user.menu.editRights=Benutzer:innenrechte
user.mobilePhone=Mobilnummer
-user.mobilePhone.info=Die Nummer kann als 2. Faktor benutzt werden, um z. B. das Passwort zurückzusetzen oder andere sicherheitsrelevante Bereiche zu nutzen. Die Nummer kann im Bereich Zwei-Faktor-Authentifizierung geändert werden.
-user.mobilePhone.invalidFormat=Es sind nur Zahlen sowie '+' am Anfang, '-', '/' und Leerzeichen erlaubt. Die führende Ländervorwahl ist optional. Beispiel\: +49 561 316793-0 oder 0561 316793-0
-user.My2FA.expired=Für die angeforderte Aktion ist eine (erneute) Zwei-Faktor-Authentifizierung erforderlich, die nicht älter als {0} ist.
+user.mobilePhone.info=Die Nummer kann als 2. Faktor benutzt werden, um z. B. das Passwort zurückzusetzen oder andere sicherheitsrelevante Bereiche zu nutzen. Die Nummer kann im Bereich Zwei-Faktor-Authentifizierung geändert werden.
+user.mobilePhone.invalidFormat=Es sind nur Zahlen sowie '+' am Anfang, '-', '/' und Leerzeichen erlaubt. Die führende Ländervorwahl ist optional. Beispiel\: +49 561 316793-0 oder 0561 316793-0
+user.My2FA.expired=Für die angeforderte Aktion ist eine (erneute) Zwei-Faktor-Authentifizierung erforderlich, die nicht älter als {0} ist.
user.My2FA.required=Eine (erneute) Zwei-Faktor-Authentifizierung ist erforderlich.
-user.My2FA.required.extended=Eine (erneute) Zwei-Faktor-Authentifizierung ist aus Sicherheitsgründen erforderlich. Du kannst hierzu einen Code anfordern (s. Link unterhalb des Code-Feldes) oder, falls konfiguriert, deine Authenticator-App benutzen.
+user.My2FA.required.extended=Eine (erneute) Zwei-Faktor-Authentifizierung ist aus Sicherheitsgründen erforderlich. Du kannst hierzu einen Code anfordern (s. Link unterhalb des Code-Feldes) oder, falls konfiguriert, deine Authenticator-App benutzen.
user.My2FA.setup.authenticator.info=Smartphone einrichten\n\n\
1. Einfach den Barcode in der Authenticator-App scannen.\n\
2. Fertig.\n\n\
Jedesmal, wenn ProjectForge nach einem Code fragt, einfach den in der Authenticator-App eingeblendeten Code verwenden.\n\n\
-Es können mehrere Authenticator-Apps gleichzeitig (auch als Backup) genutzt werden.\n\n\
-Codes aus der Authenticator-App sind noch für ca. 30 Sekunden gültig, nachdem sie in der App erneuert wurden.\n\n\
-Diese Barcode-Ansicht ist für ca. 10 Minuten einsehbar. Anschließend wird für die erneute Anzeige eine 2FA-Authentifizierung benötigt.
-user.My2FA.setup.authenticator.intro=Für die Zwei-Faktor-Authentifzierung sollte eine Authenticator-App eingerichtet werden (z. B. Microsoft-, Google-Authenticator oder Fortitoken).
+Es können mehrere Authenticator-Apps gleichzeitig (auch als Backup) genutzt werden.\n\n\
+Codes aus der Authenticator-App sind noch für ca. 30 Sekunden gültig, nachdem sie in der App erneuert wurden.\n\n\
+Diese Barcode-Ansicht ist für ca. 10 Minuten einsehbar. Anschließend wird für die erneute Anzeige eine 2FA-Authentifizierung benötigt.
+user.My2FA.setup.authenticator.intro=Für die Zwei-Faktor-Authentifzierung sollte eine Authenticator-App eingerichtet werden (z. B. Microsoft-, Google-Authenticator oder Fortitoken).
user.My2FA.setup.authenticator.title=Authenticator-Apps
-user.My2FA.setup.authenticatorKey=Authenticator-Schlüssel
-user.My2FA.setup.check.fail=Code-Prüfung fehlgeschlagen.
-user.My2FA.setup.check.success=Code-Prüfung erfolgreich.
+user.My2FA.setup.authenticatorKey=Authenticator-Schlüssel
+user.My2FA.setup.check.fail=Code-Prüfung fehlgeschlagen.
+user.My2FA.setup.check.success=Code-Prüfung erfolgreich.
user.My2FA.setup.disableAuthenticatorApp=Authenticator-App entfernen
-user.My2FA.setup.disableAuthenticatorApp.confirmMessage=Soll die Authentificator-App nun entfernt bzw. erneuert werden? Alle bisherhigen Authentificator-Apps werden dann ungültig.
-user.My2FA.setup.disableAuthenticatorApp.info=Diesen Knopf klicken, um die Authentificator-App zu entfernen oder zu erneuern. Für diese Funktion wird selber ein 2. FAktor benötigt, der nicht älter ist als 2 Minuten.
+user.My2FA.setup.disableAuthenticatorApp.confirmMessage=Soll die Authentificator-App nun entfernt bzw. erneuert werden? Alle bisherhigen Authentificator-Apps werden dann ungültig.
+user.My2FA.setup.disableAuthenticatorApp.info=Diesen Knopf klicken, um die Authentificator-App zu entfernen oder zu erneuern. Für diese Funktion wird selber ein 2. FAktor benötigt, der nicht älter ist als 2 Minuten.
user.My2FA.setup.enableAuthenticatorApp=Authentificator-Apps einrichten
-user.My2FA.setup.enableAuthenticatorApp.confirmMessage=Soll eine Authenticator-App nun eingerichtet werden? Anschließend wird für eine Anmeldung ein 2. Faktor benötigt. Diese Operation kann rückgängig gemacht werden.
-user.My2FA.setup.enableAuthenticatorApp.info=Hierüber kann eine Authenticator-App eingerichtet werden.
+user.My2FA.setup.enableAuthenticatorApp.confirmMessage=Soll eine Authenticator-App nun eingerichtet werden? Anschließend wird für eine Anmeldung ein 2. Faktor benötigt. Diese Operation kann rückgängig gemacht werden.
+user.My2FA.setup.enableAuthenticatorApp.info=Hierüber kann eine Authenticator-App eingerichtet werden.
user.My2FA.setup.info.1=### Zwei-Faktor-Authentifizierung (2FA)\n\n\
-* ProjectForge unterstützt 2FA für eine erhöhte Sicherheit. Authenticator-Apps, SMS (wenn konfiguriert) und/oder E-Mails werden als 2. Faktor unterstützt.\n\
+* ProjectForge unterstützt 2FA für eine erhöhte Sicherheit. Authenticator-Apps, SMS (wenn konfiguriert) und/oder E-Mails werden als 2. Faktor unterstützt.\n\
* Immer, wenn ProjectForge einen Code anfordert, kann ein Code aus der Authenticator-App eingegeben werden oder ein Einmalpasswort per E-Mail oder als SMS angefordert werden.\n\n\
-Wenn die Angemeldet-Bleiben-Funktion bei der Anmeldung verwendet wird, kann eine unnötig häufige Code-Abfrage vermieden werden!
-user.My2FA.setup.info.2=Es wird dringend empfohlen, einen zweiten Faktor über eine Authenticator-App und/oder WebAuthn (z. B. Fidu2) und, falls verfügbar, auch eine Mobilfunknummer zum Anfordern von Codes per SMS zu konfiguieren.\n\n\
-Einige Sicherheitsfunktionen, wie z. B. ein Passwort-Reset, steht nur zur Verfügung, wenn mindestens ein 2. Faktor (Authenticator-App, SMS oder WebAuthn) konfiguriert ist.
-user.My2FA.setup.info.3=Hier können 2FA-Codes getestet werden. Außerdem benötigen Änderungen auf dieser Seite eine aktuelle 2FA-Prüfung.
+Wenn die Angemeldet-Bleiben-Funktion bei der Anmeldung verwendet wird, kann eine unnötig häufige Code-Abfrage vermieden werden!
+user.My2FA.setup.info.2=Es wird dringend empfohlen, einen zweiten Faktor über eine Authenticator-App und/oder WebAuthn (z. B. Fidu2) und, falls verfügbar, auch eine Mobilfunknummer zum Anfordern von Codes per SMS zu konfiguieren.\n\n\
+Einige Sicherheitsfunktionen, wie z. B. ein Passwort-Reset, steht nur zur Verfügung, wenn mindestens ein 2. Faktor (Authenticator-App, SMS oder WebAuthn) konfiguriert ist.
+user.My2FA.setup.info.3=Hier können 2FA-Codes getestet werden. Außerdem benötigen Änderungen auf dieser Seite eine aktuelle 2FA-Prüfung.
user.My2FA.setup.info.title=Zweifaktorauthentifizierung
user.My2FA.setup.showAuthenticatorKey=Authenticator-Zugang anzeigen
user.My2FA.setup.sms.info=Hier kann eine Mobilfunknummer hinterlegt werden, um einen 2. Faktor per SMS anzufordern.
user.My2FA.setup.sms.info.title=SMS-Konfiguration
user.My2FA.setup.sms.mobileNumberRecommended=Es wird dringend empfohlen, hier die eigene Mobilfunknummer anzugeben.\n\n\
Ãœber das Mobiltelefon kann ein zweiter Faktor als SMS alternativ angefordert werden.\n\n\
-Wenn die Mobilfunknummer geändert werden soll, wird eine (neue) Zweifaktorauthentifizierung benötigt (siehe oben).
+Wenn die Mobilfunknummer geändert werden soll, wird eine (neue) Zweifaktorauthentifizierung benötigt (siehe oben).
user.My2FA.setup.title=Zwei-Faktor-Authentifizierung (2FA) einrichten
-user.My2FACode.authentification.info=Ein zweiter Faktor ist nun erforderlich. Hier kann ein 2. Faktor (z. B. OTP-Einmalpasswort) eingegeben werden: Aus einer Authenticator-App, ein angeforderter Code per SMS oder E-Mail oder über einen registrierten WebAuthn-Token.
+user.My2FACode.authentification.info=Ein zweiter Faktor ist nun erforderlich. Hier kann ein 2. Faktor (z. B. OTP-Einmalpasswort) eingegeben werden: Aus einer Authenticator-App, ein angeforderter Code per SMS oder E-Mail oder über einen registrierten WebAuthn-Token.
user.My2FACode.code=Code
user.My2FACode.code.info=Code aus der Authenticator-App oder der Code (Einmalpasswort), welches per E-Mail oder SMS versendet wurde.
-user.My2FACode.code.validate=Prüfen
-user.My2FACode.error.timePenalty.message=Die Funktion ist aus Sicherheitsgründen blockiert bis {0} ({1}) nach {2} Fehlversuchen. Bitte beachten, dass dieser Account nach {3} Fehlversuchen gesperrt wird.
-user.My2FACode.error.validation=Code nicht gültig oder die Zweifaktor-Authentifizierung ist noch nicht eingerichtet.
+user.My2FACode.code.validate=Prüfen
+user.My2FACode.error.timePenalty.message=Die Funktion ist aus Sicherheitsgründen blockiert bis {0} ({1}) nach {2} Fehlversuchen. Bitte beachten, dass dieser Account nach {3} Fehlversuchen gesperrt wird.
+user.My2FACode.error.validation=Code nicht gültig oder die Zweifaktor-Authentifizierung ist noch nicht eingerichtet.
user.My2FACode.lastSuccessful2FA=Letzte erfolgreiche 2. Faktorauthentifizierung
-user.My2FACode.password.info=Das Password wird nur beim Versenden des Einmalpassworts per E-Mail aus Sicherheitsgründen verlangt.
-user.My2FACode.password.wrong=Passwortprüfung fehlgeschlagen.
+user.My2FACode.password.info=Das Password wird nur beim Versenden des Einmalpassworts per E-Mail aus Sicherheitsgründen verlangt.
+user.My2FACode.password.wrong=Passwortprüfung fehlgeschlagen.
user.My2FACode.sendCode.mail=E-Mail-Code anfordern
-user.My2FACode.sendCode.mail.info=Code per E-Mail anfordern. Dieser Code ist bis zu 2 Minuten gültig.
+user.My2FACode.sendCode.mail.info=Code per E-Mail anfordern. Dieser Code ist bis zu 2 Minuten gültig.
user.My2FACode.sendCode.mail.message=Der Code lautet: {0}
user.My2FACode.sendCode.mail.sentSuccessfully=Der 2. Faktor wurde erfolgreich per E-Mail versendet um {0}
user.My2FACode.sendCode.mail.title=Nachricht von ProjectForge
user.My2FACode.sendCode.sms=SMS-Code anfordern
-user.My2FACode.sendCode.sms.info=Coder per SMS anfordern. Dieser Code ist bis zu 2 Minuten gültig.
+user.My2FACode.sendCode.sms.info=Coder per SMS anfordern. Dieser Code ist bis zu 2 Minuten gültig.
user.My2FACode.sendCode.sms.sentSuccessfully=Der 2. Faktor wurde erfolgreich per SMS versendet um {0}.
user.My2FACode.title=Zweifaktor-Authentifizierung
-user.myAccount.teamcalwhitelist=Kalender Whitelist für Kalendersoftware
+user.myAccount.teamcalwhitelist=Kalender Whitelist für Kalendersoftware
user.myAccount.title.edit=Mein Zugang
user.panel.error.usernameNotFound=Benutzer:inname nicht existent.
user.personalPhoneIdentifiers=Telefonkennungen
-user.personalPhoneIdentifiers.pleaseDefine=Anschlüsse festlegen unter 'Mein Zugang'
-user.personalPhoneIdentifiers.tooltip.content=Hier können benutzerspezifische Telefon-Ids (\= interne Rufnummer) als kommaseparierte Werte angegeben werden. In der Adressenliste kann somit eine Direktwahl von diesen Telefonen durch Klicken auf die gewünschte Rufnummer initiiert werden.
+user.personalPhoneIdentifiers.pleaseDefine=Anschlüsse festlegen unter 'Mein Zugang'
+user.personalPhoneIdentifiers.tooltip.content=Hier können benutzerspezifische Telefon-Ids (\= interne Rufnummer) als kommaseparierte Werte angegeben werden. In der Adressenliste kann somit eine Direktwahl von diesen Telefonen durch Klicken auf die gewünschte Rufnummer initiiert werden.
user.personalPhoneIdentifiers.tooltip.title=Direktwahl
-user.restricted=eingeschränkt
-user.restricted.not=nicht eingeschränkt
-user.restrictedUser=Eingeschränkte:r Nutzer:in
-user.restrictedUser.tooltip=Ein eingeschränkte:r (restricted) Nutzer:in darf sich lediglich anmelden und sein Passwort ändern. Der oder die Nutzer:in wird mit einem externen Usermanagementsystem synchronisiert.
+user.restricted=eingeschränkt
+user.restricted.not=nicht eingeschränkt
+user.restrictedUser=Eingeschränkte:r Nutzer:in
+user.restrictedUser.tooltip=Ein eingeschränkte:r (restricted) Nutzer:in darf sich lediglich anmelden und sein Passwort ändern. Der oder die Nutzer:in wird mit einem externen Usermanagementsystem synchronisiert.
user.rights.title.edit=Benutzer:innenrechte bearbeiten
user.sshPublicKey=SSH public key
user.title.add=Neue:r Benutzer:in
user.title.edit=Benutzer:in bearbeiten
user.title.heading=Benutzer:in
user.title.list=Benutzer:in
-user.title.list.select=Benutzer:in auswählen
+user.title.list.select=Benutzer:in auswählen
user.unassignedGroups=Nicht assoziierte Gruppen
user.username=Benutzer:inname
user.users=Benutzer:in
userPref.area=Bereich
userPref.area.jira.project=JIRA Projekt
userPref.area.jira.project.pid=Projekt ID (PID)
-userPref.area.jira.project.pid.tooltip=Kann im JIRA-Dashboard z. B. aus einigen Links abgelesen werden (projectID oder pid in der referenzierten URL). Wird für die Kommunikation mit JIRA benötigt.
+userPref.area.jira.project.pid.tooltip=Kann im JIRA-Dashboard z. B. aus einigen Links abgelesen werden (projectID oder pid in der referenzierten URL). Wird für die Kommunikation mit JIRA benötigt.
userPref.area.kunde.favorite=Kundenfavorit
userPref.area.projekt.favorite=Projektfavorit
userPref.area.task.favorite=Strukturelementfavorit
userPref.area.timesheet.template=Zeitberichtsvorlage
userPref.area.user.favorite=Benutzerfavorit (unbenutzt)
userPref.error.nameDoesAlreadyExist=Es existiert bereits ein Eintrag unter diesem Namen.
-userPref.error.userIsNotOwner=Benutzer:in ist nicht Eigner:in dieser persönlichen Einstellung.
+userPref.error.userIsNotOwner=Benutzer:in ist nicht Eigner:in dieser persönlichen Einstellung.
userPref.favorite.create=--- anlegen ---
userPref.favorite.select=--- Favoriten ---
userPref.name=Name
userPref.saveAsTemplate=Als Vorlage speichern
userPref.template.create=--- anlegen ---
userPref.template.select=--- Vorlagen ---
-userPref.title.add=Neue persönliche Einstellung
-userPref.title.edit=Persönliche Einstellung bearbeiten
-userPref.title.heading=Persönliche Einstellungen
-userPref.title.list=Liste der persönlichen Einstellungen
+userPref.title.add=Neue persönliche Einstellung
+userPref.title.edit=Persönliche Einstellung bearbeiten
+userPref.title.heading=Persönliche Einstellungen
+userPref.title.list=Liste der persönlichen Einstellungen
vacation=Urlaub
-vacation.annualleave=Anzahl Urlaubstage für Kalenderjahr
-vacation.availabledays=Verfügbare Urlaubstage
-vacation.availablevacation=Noch verfügbarer Urlaub
+vacation.annualleave=Anzahl Urlaubstage für Kalenderjahr
+vacation.availabledays=Verfügbare Urlaubstage
+vacation.availablevacation=Noch verfügbarer Urlaub
vacation.calendar=Kalender
-vacation.conflict.info=Es besteht ein Konflikt mit den Abwesenheiten der Vertreter:innen. An mindestens einem Tag steht kein:e Vertreter:in zur Verfügung. Bitte andere oder weitere Vertretungen auswählen.
+vacation.conflict.info=Es besteht ein Konflikt mit den Abwesenheiten der Vertreter:innen. An mindestens einem Tag steht kein:e Vertreter:in zur Verfügung. Bitte andere oder weitere Vertretungen auswählen.
vacation.conflicts=Konflikte
vacation.countPerDay=Urlaubsstunden pro Urlaubstag
vacation.Days=Urlaubstage
@@ -2683,21 +2809,21 @@ vacation.leaveOfYear=Urlaubskonto im Jahr {0}
vacation.mail.action=Der Urlaubseintrag von {0} am {1} wurde {2} durch {3}.
vacation.mail.action.short=Urlaubseintrag von {0} am {1} wurde {2}
vacation.mail.link=Zum Urlaubseintrag
-vacation.mail.modType.delete=gelöscht
+vacation.mail.modType.delete=gelöscht
vacation.mail.modType.insert=angelegt
vacation.mail.modType.undelete=wiederhergestellt
-vacation.mail.modType.update=geändert
+vacation.mail.modType.update=geändert
vacation.mail.period={0}-{1} ({2} Tage)
-vacation.mail.reason.hr=Du erhählst diesen Urlaubseintrag von {0}, weil es ein Spezialurlaub ist, der die Freigabe von HR benötigt.
-vacation.mail.reason.manager=Du wurdest zur Abstimmung ausgewählt. Bitte bearbeite diesen Urlaubseintrag in ProjectForge bzw. nimm bitte Kontakt zu {0} auf.
-vacation.mail.reason.other=Du erhählst diesen Urlaubseintrag von {0} zur Information.
+vacation.mail.reason.hr=Du erhählst diesen Urlaubseintrag von {0}, weil es ein Spezialurlaub ist, der die Freigabe von HR benötigt.
+vacation.mail.reason.manager=Du wurdest zur Abstimmung ausgewählt. Bitte bearbeite diesen Urlaubseintrag in ProjectForge bzw. nimm bitte Kontakt zu {0} auf.
+vacation.mail.reason.other=Du erhählst diesen Urlaubseintrag von {0} zur Information.
vacation.mail.reason.own=Es ist dein Urlaubseintrag.
-vacation.mail.reason.replacement=Du wurdest als Vertretung ausgewählt. Bitte bearbeite diesen Eintrag oder nimm Kontakt zu {0} auf.
+vacation.mail.reason.replacement=Du wurdest als Vertretung ausgewählt. Bitte bearbeite diesen Eintrag oder nimm Kontakt zu {0} auf.
vacation.manager=Abstimmung
-vacation.neededdays=Benötigte Urlaubstage
+vacation.neededdays=Benötigte Urlaubstage
vacation.other=Anderer
vacation.own=Eigner:in
-vacation.plandannualleave=Anzahl geplanter Urlaubstage für restliches Kalenderjahr
+vacation.plandannualleave=Anzahl geplanter Urlaubstage für restliches Kalenderjahr
vacation.previousyearleave=Resturlaub aus dem Vorjahr
vacation.previousyearleaveunused=Ungenutzer Resturlaub zum {0}
vacation.previousyearleaveused=Genutzter Resturlaub aus dem Vorjahr
@@ -2706,9 +2832,9 @@ vacation.remainingLeaveFromYear=Resturlaub aus dem Jahr {0}
vacation.remainingLeaveFromYearUnused=Ungenutzer Resturlaub aus dem Jahr {0}
vacation.replacement=Vertretung
vacation.replacement.others=Weitere Vertretungen
-vacation.setStartAndEndFirst=
+vacation.setStartAndEndFirst=
vacation.special=Sonderurlaub
-vacation.special.tooltip=Sonderurlaub wird im Urlaubskonto nicht berücksichtigt.
+vacation.special.tooltip=Sonderurlaub wird im Urlaubskonto nicht berücksichtigt.
vacation.specialApproved=Abgestimmter Sonderurlaub
vacation.specialInProgress=Sonderurlaub in Abstimmung
vacation.specialVacationInYearApproved=Abgestimmter Sonderurlaub in {0}
@@ -2719,12 +2845,12 @@ vacation.status=Status
vacation.status.approved=Abgestimmt
vacation.status.inProgress=In Abstimmung
vacation.status.rejected=Abgelehnt
-vacation.subscription=Abonnieren von Urlaubseinträgen
-vacation.subscription.info=Urlaubseinträge können in der Kalendersicht eingesehen werden, aber auch als Kalender (s. Kalenderliste) für bestimmte Benutzer:innen oder Gruppen angelegt und auch abonniert werden. Sie können insbesondere die eigenen Urlaube und die von Kollegen oder Kolleginnen/Teams in die eigene Kalendersoftware integriert werden.
+vacation.subscription=Abonnieren von Urlaubseinträgen
+vacation.subscription.info=Urlaubseinträge können in der Kalendersicht eingesehen werden, aber auch als Kalender (s. Kalenderliste) für bestimmte Benutzer:innen oder Gruppen angelegt und auch abonniert werden. Sie können insbesondere die eigenen Urlaube und die von Kollegen oder Kolleginnen/Teams in die eigene Kalendersoftware integriert werden.
vacation.subtotal=Zwischensumme
vacation.title.add=Urlaubseintrag erstellen
-vacation.title.edit=Urlaubseintrag ändern
-vacation.title.heading=Urlaubseinträge
+vacation.title.edit=Urlaubseintrag ändern
+vacation.title.heading=Urlaubseinträge
vacation.title.list=Urlaubseintragsliste
vacation.usedvacation=Bereits verwendeter Urlaub
vacation.vacationApproved=Abgestimmter Urlaub
@@ -2733,27 +2859,27 @@ vacation.vacationInProgress=Urlaub in Abstimmung
vacation.vacationInYearApproved=Abgestimmter Urlaub in {0}
vacation.vacationmode=Zuordnung
vacation.vacationsOfReplacements=Urlaube der Vertretungen
-vacation.validate.datenotset=Das Start- und das Enddatum müssen angegeben sein.
+vacation.validate.datenotset=Das Start- und das Enddatum müssen angegeben sein.
vacation.validate.daysarenull=Urlaubseintrag mit 0 Arbeitstagen
-vacation.validate.endbeforestart=Das gewählte Enddatum liegt vor dem Startdatum
-vacation.validate.leaveapplicationexists=Für den ausgewählten Zeitraum existiert bereits ein Urlaubseintrag
-vacation.validate.noCalender=Der Firmenurlaubskalender {0} muss ausgewählt werden
-vacation.validate.notAllowedToSelfApprove=Sie können diesen Eintrag nicht als abgestimmt markieren.
-vacation.validate.notEnoughVacationDaysLeft=Es stehen nicht mehr genügend Urlaubstage zur Verfügung
-vacation.validate.startDateBeforeNow=Das gewählte Startdatum liegt vor dem aktuellen Datum. Nur HR-Mitarbeiter:innen können Daten in der Vergangenheit anlegen.
-vacation.validate.usedBiggerThanPreviousYear=Die Anzahl der verbrauchten Tage aus dem Urlaub vom Vorjahr ist größer als die tatsächliche Anzahl der Urlaubstage aus dem Vorjahr.
-vacation.validate.usedButNoPreviousYear=Es wurden nur die verbrauchten Tage des Urlaubs aus dem Vorjahr angegeben, aber nicht die tatsächlichen.
+vacation.validate.endbeforestart=Das gewählte Enddatum liegt vor dem Startdatum
+vacation.validate.leaveapplicationexists=Für den ausgewählten Zeitraum existiert bereits ein Urlaubseintrag
+vacation.validate.noCalender=Der Firmenurlaubskalender {0} muss ausgewählt werden
+vacation.validate.notAllowedToSelfApprove=Sie können diesen Eintrag nicht als abgestimmt markieren.
+vacation.validate.notEnoughVacationDaysLeft=Es stehen nicht mehr genügend Urlaubstage zur Verfügung
+vacation.validate.startDateBeforeNow=Das gewählte Startdatum liegt vor dem aktuellen Datum. Nur HR-Mitarbeiter:innen können Daten in der Vergangenheit anlegen.
+vacation.validate.usedBiggerThanPreviousYear=Die Anzahl der verbrauchten Tage aus dem Urlaub vom Vorjahr ist größer als die tatsächliche Anzahl der Urlaubstage aus dem Vorjahr.
+vacation.validate.usedButNoPreviousYear=Es wurden nur die verbrauchten Tage des Urlaubs aus dem Vorjahr angegeben, aber nicht die tatsächlichen.
vacation.validate.vacationBeforeJoinDate=Der Urlaub darf nicht vor dem Eintrittsdatum des Mitarbeiters liegen.
vacation.workingdays=Anzahl Urlaubstage
webauthn.entry.displayName=Anzeigename
-webauthn.entry.displayName.info=Hier kannst du einen beliebigen Namen eingeben, um deinen Token leichter zuordnen zu können.
-webauthn.entry.edit=WebAuthn-Eintrag ändern
-webauthn.entry.signCount=Signaturzähler
-webauthn.entry.signCount.info=Zähler für Authentifizierungen (wird nach jeder Benutzung hochgezählt)
+webauthn.entry.displayName.info=Hier kannst du einen beliebigen Namen eingeben, um deinen Token leichter zuordnen zu können.
+webauthn.entry.edit=WebAuthn-Eintrag ändern
+webauthn.entry.signCount=Signaturzähler
+webauthn.entry.signCount.info=Zähler für Authentifizierungen (wird nach jeder Benutzung hochgezählt)
webauthn.error.process=Fehler im Authentifizierungsprozess.
-webauthn.error.userNotOwnerOrEntryDoesnotExist=Der/die Benutzer:in hat nicht das Recht, auf fremde WebAuthn-Einträge zuzugreifen oder der gesuchte Eintrag existiert nicht.
+webauthn.error.userNotOwnerOrEntryDoesnotExist=Der/die Benutzer:in hat nicht das Recht, auf fremde WebAuthn-Einträge zuzugreifen oder der gesuchte Eintrag existiert nicht.
webauthn.error.validate=Fehler bei der Validierung der Authentifizierungsdaten.
-webauthn.info=WebAuthn ist ein moderner und sicherer Standard, um eine hardwarebasierte Zweifaktorauthentifizierung zu ermöglichen. Hier kannst du einen oder mehrere deiner Token registrieren, um eine bequeme und sichere 2FA zu nutzen.
+webauthn.info=WebAuthn ist ein moderner und sicherer Standard, um eine hardwarebasierte Zweifaktorauthentifizierung zu ermöglichen. Hier kannst du einen oder mehrere deiner Token registrieren, um eine bequeme und sichere 2FA zu nutzen.
webauthn.registration.2FARequired.info=Bitte de 2FA erneuern, bevor ein WebAuthn-Token registriert werden kann.
webauthn.registration.button.authenticate=WebAuthn
webauthn.registration.button.authenticate.info=Du kannst hier registrierte WebAuthn-Token benutzen (z. B. Yubikey).
@@ -2761,21 +2887,21 @@ webauthn.registration.button.register=Registrieren
webauthn.title=WebAuthn (Fido2 etc.)
# (timeable) attributes
-attr.deletemodal.heading=Soll dieser Eintrag wirklich gelöscht werden?
-attr.deletemodal.question=Ja: Der Eintrag wird gelöscht und alle Änderungen auf dieser Seite werden gespeichert.
Abbrechen: Der Eintrag wird nicht gelöscht und Sie bleiben auf dieser Seite.
+attr.deletemodal.heading=Soll dieser Eintrag wirklich gelöscht werden?
+attr.deletemodal.question=Ja: Der Eintrag wird gelöscht und alle Änderungen auf dieser Seite werden gespeichert.
Abbrechen: Der Eintrag wird nicht gelöscht und Sie bleiben auf dieser Seite.
attr.instantOfTime=Zeitpunkt
-attr.savemodal.heading=Soll die Änderungen gespeichert werden?
-attr.savemodal.question=Ja: Alle Änderungen auf dieser Seite werden gespeichert.
Abbrechen: Die Änderungen werden nicht gespeichert aber auch nicht verworfen und Sie bleiben auf dieser Seite.
+attr.savemodal.heading=Soll die Änderungen gespeichert werden?
+attr.savemodal.question=Ja: Alle Änderungen auf dieser Seite werden gespeichert.
Abbrechen: Die Änderungen werden nicht gespeichert aber auch nicht verworfen und Sie bleiben auf dieser Seite.
attr.starttime.alreadyexists.day=Es existiert bereits ein Eintrag mit gleichem Datum (Tag).
attr.starttime.alreadyexists.month=Es existiert bereits ein Eintrag mit gleichem Datum (Monat).
-attr.validFrom=Gültig ab
+attr.validFrom=Gültig ab
birthdayButler.email.content=Im Monat {0} haben {1} Mitarbeiter Geburtstag. Im Anhang findest du die Liste der Geburtstage.
-birthdayButler.email.content.noBirthdaysFound=Im Monat {0} wurden keine Geburtstagseinträge gefunden.
+birthdayButler.email.content.noBirthdaysFound=Im Monat {0} wurden keine Geburtstagseinträge gefunden.
birthdayButler.email.opening=Ein neuer Monat, eine neue Geburtstagsliste!
-birthdayButler.email.subject=Geburtstagsliste für
-birthdayButler.month.response.noEntry=Es gibt keine Geburtstagseinträge für diesen Monat.
-birthdayButler.month.response.nothingSelected=Der Monat muss ausgewählt sein.
+birthdayButler.email.subject=Geburtstagsliste für
+birthdayButler.month.response.noEntry=Es gibt keine Geburtstagseinträge für diesen Monat.
+birthdayButler.month.response.nothingSelected=Der Monat muss ausgewählt sein.
birthdayButler.organization.noMatchingUser=Es gibt keine Benutzer:innen, die der in projectforge.properties gesetzten Organisation zugeordnet sind.
birthdayButler.organization.notSet=Es ist keine Organisation in den application.properties definiert. -> projectforge.birthdayTool.organization=Your Organization
birthdayButler.wordDocument.error=Es ist ein Fehler beim Erstellen des Word-Dokuments aufgetreten.
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
index 6baebc75ee..2bff5443d4 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
@@ -287,13 +287,15 @@ class AddressViewPageRest : AbstractDynamicPageRest() {
if (email.isNullOrBlank()) {
return
}
+ val emailObject = EMail(email)
col.add(
UIRow()
.add(UICol(6).add(UILabel(title)))
- .add(UICol(6).add(UICustomized("email", mutableMapOf("data" to EMail(email)))))
+ .add(UICol(6).add(UICustomized("email", mutableMapOf("email" to emailObject))))
)
}
+
private fun createAddressCol(
row: UIRow,
numberOfAddresses: Int,
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/dto/User.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/dto/User.kt
index 5b073ab174..7d426012eb 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/dto/User.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/dto/User.kt
@@ -238,6 +238,10 @@ class User(
users?.forEach { it.displayName = userService.getUser(it.id)?.displayName }
}
+ fun restoreEmails(users: List?, userService: UserService) {
+ users?.forEach { it.email = userService.getUser(it.id)?.email }
+ }
+
/**
* Converts csv of user ids to list of user.
*/
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt
index b4ff3534ae..bbccaf7806 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt
@@ -31,7 +31,6 @@ import org.projectforge.rest.config.JacksonConfiguration
import org.projectforge.rest.config.Rest
import org.projectforge.rest.core.AbstractDTOPagesRest
import org.projectforge.rest.dto.Customer
-import org.projectforge.rest.dto.Konto
import org.projectforge.ui.*
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt
index ba888290a3..d4689e210d 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt
@@ -26,8 +26,10 @@ package org.projectforge.rest.poll
import org.projectforge.business.poll.PollDO
import org.projectforge.business.poll.PollDao
import org.projectforge.business.poll.PollResponseDao
+import org.projectforge.business.user.service.UserService
import org.projectforge.framework.i18n.translateMsg
import org.projectforge.mail.MailAttachment
+import org.projectforge.rest.dto.PostData
import org.projectforge.rest.poll.excel.ExcelExport
import org.slf4j.Logger
import org.slf4j.LoggerFactory
@@ -54,6 +56,9 @@ class PollCronJobs {
@Autowired
private lateinit var exporter: ExcelExport
+ @Autowired
+ private lateinit var userService: UserService
+
private val log: Logger = LoggerFactory.getLogger(PollCronJobs::class.java)
/**
@@ -94,12 +99,12 @@ class PollCronJobs {
return excel
}
}
- // add all attendees mails
+ val owner = userService.getUser(poll.owner?.id)
val mailTo: ArrayList =
ArrayList(poll.attendees?.map { it.email }?.mapNotNull { it } ?: emptyList())
val mailFrom = pollDO.owner?.email.toString()
- val mailSubject = translateMsg("poll.mail.ended.subject")
- val mailContent = translateMsg("poll.mail.ended.content", pollDO.title, pollDO.owner?.displayName)
+ val mailSubject = translateMsg("poll.mail.endedafterdeadline.subject", poll.title)
+ val mailContent = translateMsg("poll.mail.endedafterdeadline.content", pollDO.title, owner?.displayName, )
pollDao.internalSaveOrUpdate(pollDO)
log.info("Set state of poll (${pollDO.id}) ${pollDO.title} to FINISHED")
@@ -153,4 +158,4 @@ class PollCronJobs {
pollDao.internalMarkAsDeleted(poll)
}
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt
index 0a05b79f55..e5e58afd71 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt
@@ -79,36 +79,36 @@ class PollInfoPageRest : AbstractDynamicPageRest() {
layout.add(field)
layout.add(
- UIFieldset().add(UILabel("Single Response " + translate("poll.question"))).add(
+ UIFieldset().add(UILabel(translate("poll.question.singletitel"))).add(
UICol()
.add(
UIReadOnlyField(
"question",
- label = "poll.question",
+ label = "poll.question.single",
value = translate("poll.manual.singleResponse")
)
)
)
)
layout.add(
- UIFieldset().add(UILabel("Multiple Response " + translate("poll.question"))).add(
+ UIFieldset().add(UILabel(translate("poll.question.multititle"))).add(
UICol()
.add(
UIReadOnlyField(
"question",
- label = "poll.question",
+ label = "poll.question.multi",
value = translate("poll.manual.multiResponse")
)
)
)
)
layout.add(
- UIFieldset().add(UILabel("Text " + translate("poll.question"))).add(
+ UIFieldset().add(UILabel(translate("poll.question.texttitle"))).add(
UICol()
.add(
UIReadOnlyField(
"question",
- label = "poll.question",
+ label = "poll.question.text",
value = translate("poll.manual.textQuestion")
)
)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
index 705f8dc813..44c998c444 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
@@ -71,7 +71,6 @@ class PollMailService {
} catch (e: Exception) {
log.error(e.message, e)
}
-
}
fun getAllMails(poll: Poll): List {
@@ -81,24 +80,35 @@ class PollMailService {
val accessUserIds = UserService().getUserIds(groupService.getGroupUsers(accessGroupIds))
val accessUsers = User.toUserList(accessUserIds)
+ var userList = fullAccessUser
accessUsers?.forEach { user ->
if (fullAccessUser.none { it.id == user.id }) {
- fullAccessUser.add(user)
+ userList.add(user)
}
}
var owner = User.getUser(poll.owner?.id, false)
if (owner != null) {
- fullAccessUser.add(owner)
+ userList.add(owner)
}
attendees?.forEach {
if (!fullAccessUser.contains(it)) {
- fullAccessUser.add(it)
+ userList.add(it)
}
}
- User.restoreDisplayNames(fullAccessUser, userService)
- return fullAccessUser.mapNotNull { it.email }
+ User.restoreDisplayNames(userList, userService)
+ User.restoreEmails(userList, userService)
+ return userList.mapNotNull { it.email }
}
+ fun getAllFullAccessEmails(poll: Poll): List {
+ val fullAccessUser = poll.fullAccessUsers?.toMutableList() ?: mutableListOf()
+ val accessGroupIds = poll.fullAccessGroups?.filter { it.id != null }?.map { it.id!! }?.toIntArray()
+
+ var userList = fullAccessUser
+
+ User.restoreEmails(userList, userService)
+ return userList.mapNotNull { it.email }
+ }
}
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
index dee4844a7c..7ce8a1d70d 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
@@ -67,6 +67,8 @@ import javax.servlet.http.HttpServletRequest
@RequestMapping("${Rest.URL}/poll")
class PollPageRest : AbstractDTOPagesRest(PollDao::class.java, "poll.title") {
+ private var emailSent: Boolean = false
+
private val log: Logger = LoggerFactory.getLogger(PollPageRest::class.java)
@Autowired
@@ -221,7 +223,8 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
.add(
UISelect(
"questionType",
- values = BaseType.values().map { UISelectValue(it, it.name) },
+ values = BaseType.values()
+ .map { UISelectValue(it, translateMsg("poll.questionType." + it.name)) },
label = "poll.questionType"
)
)
@@ -250,6 +253,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
.add(
UICol(UILength(xs = 3, sm = 3, md = 3, lg = 3))
.add(
+ //Sollte zu UISelect geändert werden um mehrere Vorlagen erstellen zu können ohne mehrer Buttons zu haben
UIButton.createDefaultButton(
id = "template-button",
responseAction = ResponseAction(
@@ -298,12 +302,26 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
@PutMapping("/finish")
fun changeStateToFinish(
- request: HttpServletRequest,
+ request: HttpServletRequest, obj: PollDO,
@RequestBody postData: PostData
): ResponseEntity {
postData.data.state = PollDO.State.FINISHED
postData.data.deadline = LocalDate.now()
- return super.saveOrUpdate(request, postData)
+ val responseEntity = super.saveOrUpdate(request, postData)
+
+ if (postData.data.state == PollDO.State.FINISHED) {
+
+ val owner = userService.getUser(postData.data.owner?.id)
+ val mailFrom = owner?.email.toString()
+ val mailTo = pollMailService.getAllMails(postData.data)
+ val mailSubject = translateMsg("poll.mail.ended.subject", postData.data.title)
+ val mailContent = translateMsg("poll.mail.ended.content", postData.data.title, owner?.displayName)
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+ emailSent = true
+
+ }
+
+ return responseEntity
}
@@ -317,26 +335,39 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
override fun onAfterSaveOrUpdate(request: HttpServletRequest, obj: PollDO, postData: PostData) {
- // add all attendees mails
- var mailTo = pollMailService.getAllMails(postData.data)
-
- val owner = userService.getUser(obj.owner?.id)
- val mailFrom = owner?.email.toString()
- val mailSubject: String
- val mailContent: String
-
- if (postData.data.isAlreadyCreated()) {
- mailSubject = translateMsg("poll.mail.update.subject")
- mailContent = translateMsg(
- "poll.mail.update.content", obj.title, owner?.displayName
- )
- } else {
- mailSubject = translateMsg("poll.mail.created.subject")
- mailContent = translateMsg(
- "poll.mail.created.content", obj.title, owner?.displayName
- )
+ if (postData.data.state != PollDO.State.FINISHED) {
+
+ var mailTo = pollMailService.getAllMails(postData.data)
+
+ val owner = userService.getUser(obj.owner?.id)
+ val mailFrom = owner?.email.toString()
+ val mailSubject: String
+ val mailContent: String
+
+ if (postData.data.isAlreadyCreated()) {
+
+ var mailTo = pollMailService.getAllFullAccessEmails(postData.data)
+
+ mailSubject = translateMsg("poll.mail.update.subject")
+ mailContent = translateMsg("poll.mail.update.content", obj.title, owner?.displayName
+ )
+
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+
+
+ } else {
+ mailSubject = translateMsg("poll.mail.created.subject", obj.title)
+ mailContent = translateMsg(
+ "poll.mail.created.content",
+ obj.title,
+ owner?.displayName,
+ "http://localhost:8080/react/pollResponse/dynamic/?pollId=${obj.id}"
+ )
+
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+ }
+
}
- pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
super.onAfterSaveOrUpdate(request, obj, postData)
}
@@ -367,10 +398,10 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
): ResponseEntity {
val dto = postData.data
- val type = dto.questionType?.let { BaseType.valueOf(it) } ?: BaseType.TextQuestion
+ val type = dto.questionType?.let { BaseType.valueOf(it) } ?: BaseType.TextQuestion;
val question = Question(uid = UUID.randomUUID().toString(), type = type)
if (type == BaseType.SingleResponseQuestion) {
- question.answers = mutableListOf("yes", "no")
+ question.answers = mutableListOf("", "")
}
dto.inputFields?.add(question)
@@ -613,7 +644,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
dataType: UIDataType = UIDataType.STRING
): UIElement {
return if (isReadOnly)
- UIReadOnlyField(id, label = label, dataType = dataType)
+ UIInput(id, label = label, dataType = dataType)
else
UIInput(id, label = label, dataType = dataType)
}
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
index 55dc3f8f4d..c7bf53815f 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
@@ -183,7 +183,7 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
PollPageRest.getUiElement(
pollDto.isFinished(),
"responses[$index].answers[0]",
- "poll.question.textQuestion",
+ "poll.question.TextQuestion",
UIDataType.STRING
)
)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
index b36117c030..987d2b836c 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
@@ -47,7 +47,7 @@ val PREMADE_QUESTIONS = mapOf(
),
"CAN_HAVE_CHILDREN" to Question(
uid = UUID.randomUUID().toString(),
- question = "Nimmst du ein Kind mit? (Name der Begleitung)",
+ question = "Nimmst du ein Kind mit? (Name des Kindes)",
type = BaseType.TextQuestion,
answers = mutableListOf("")
),
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
index 006d3188a4..f69e487753 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
@@ -47,3 +47,4 @@ class Question(
enum class BaseType {
TextQuestion, SingleResponseQuestion, MultiResponseQuestion,
}
+
From c2144ae16471616a6b5d67386365106c2e2d2543 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Tue, 12 Mar 2024 09:36:04 +0100
Subject: [PATCH 02/16] Excel Export with Email, Excel Fix, Attende Condition,
PremadeQuestion Dropdown,
---
.../org/projectforge/business/poll/PollDO.kt | 2 +
.../main/resources/I18nResources.properties | 4 +
.../resources/I18nResources_de.properties | 26 +-
.../kotlin/org/projectforge/rest/poll/Poll.kt | 1 +
.../projectforge/rest/poll/PollMailService.kt | 18 ++
.../projectforge/rest/poll/PollPageRest.kt | 235 ++++++++++++------
.../rest/poll/PollResponsePageRest.kt | 30 ++-
.../projectforge/rest/poll/types/PQuestion.kt | 25 ++
.../rest/poll/types/PremadeQuestions.kt | 63 ++++-
.../projectforge/rest/poll/types/Question.kt | 2 +-
10 files changed, 312 insertions(+), 94 deletions(-)
create mode 100644 projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
diff --git a/projectforge-business/src/main/kotlin/org/projectforge/business/poll/PollDO.kt b/projectforge-business/src/main/kotlin/org/projectforge/business/poll/PollDO.kt
index 3dd2559ca4..cf1e60e418 100644
--- a/projectforge-business/src/main/kotlin/org/projectforge/business/poll/PollDO.kt
+++ b/projectforge-business/src/main/kotlin/org/projectforge/business/poll/PollDO.kt
@@ -28,6 +28,8 @@ import org.projectforge.business.poll.filter.PollAssignment
import org.projectforge.business.poll.filter.PollState
import org.projectforge.common.StringHelper
import org.projectforge.common.anots.PropertyInfo
+import org.projectforge.framework.i18n.translate
+import org.projectforge.framework.i18n.translateMsg
import org.projectforge.framework.persistence.api.AUserRightId
import org.projectforge.framework.persistence.entities.DefaultBaseDO
import org.projectforge.framework.persistence.user.api.ThreadLocalUserContext
diff --git a/projectforge-business/src/main/resources/I18nResources.properties b/projectforge-business/src/main/resources/I18nResources.properties
index d52c25cf05..e328ad239d 100644
--- a/projectforge-business/src/main/resources/I18nResources.properties
+++ b/projectforge-business/src/main/resources/I18nResources.properties
@@ -2065,6 +2065,10 @@ poll.question.text=Question
poll.question.single=Question
poll.question.multi=Question
+poll.question.TextQuestion=Answer
+poll.question.SingleResponseQuestion=Question
+poll.question.MultiResponseQuestion=Question
+
diff --git a/projectforge-business/src/main/resources/I18nResources_de.properties b/projectforge-business/src/main/resources/I18nResources_de.properties
index 4ce0303f60..10afc1604c 100644
--- a/projectforge-business/src/main/resources/I18nResources_de.properties
+++ b/projectforge-business/src/main/resources/I18nResources_de.properties
@@ -174,7 +174,7 @@ redraw=Neu zeichnen
refresh=Neu laden
reload=Neu laden
rename=Umbenennen
-reset=Rücksetzen
+reset=Zurücksetzten
save=Speichern
search=Suchen
select=Auswählen
@@ -195,6 +195,10 @@ upload=Hochladen
uptodate=aktuell
wizard=Assistent
+
+State.running=Laufend
+poll.state.running
+running=Laufend
# Common
akquise=Akquise
changes=Änderungen
@@ -2113,6 +2117,11 @@ poll.location=Ort
location=Ort
owner=Ersteller
+poll.premade.template=Vorlage hinzufügen
+poll.questionTemplate=Vorlagen
+poll.templateTypeNeujahrsfeier=Neujahrsfeier
+poll.templateTypeSommerfest=Sommerfest
+poll.templateTypeTeamessen=Teamessen
#Umfrage wurde erstellt
@@ -2159,6 +2168,11 @@ poll.mail.ended.content=Liebe Teilnehmerinnen und Teilnehmer,
\
Mit Freundlichen Grüßen,
\
{1}
+poll.mail.ended.fullAccess.subject=Die Umfrage mit dem Title "{0}" wurde Beendet
+poll.mail.ended.fullAccess.content=Den Text nochmal ändern damit die Full Access\
+\User bescheid wissen das diese Email nur die Excel enthält
+
+
#Umfrage abgelaufen
poll.mail.endedafterdeadline.subject=Die Umfrage mit dem Title "{0}" ist Beendet die Deadline ist abgelaufen
poll.mail.endedafterdeadline.content=Liebe Teilnehmerinnen und Teilnehmer,
\
@@ -2170,12 +2184,11 @@ poll.mail.endedafterdeadline.content=Liebe Teilnehmerinnen und Teilnehmer,
{1}
-
-poll.manual.multiResponse=Eine Frage, die bei der man eine Antwort auswählen kann. Gut geeignet für eine Datumsumfrage für Verfügbarkeiten.
-poll.manual.questions=Anschließend werden die Fragen der Umfrage angelegt. Die Fragen können aus verschiedenen Typen bestehen.
-poll.manual.singleResponse=Eine Frage, die bei der man eine Antwort auswählen kann. Beispielsweise für eine simple Ja- oder Nein-Frage.
-poll.manual.textQuestion=Eine Frage, die bei der man mit Freitext antworten kann. Gut geeignet für formloses Feedback.
poll.manual.title=Anleitung, um eine Umfrage zu erstellen | Als Erstes muss man den
+poll.manual.questions=Anlegen. Anschließend werden die Fragen der Umfrage angelegt. Die Fragen können aus verschiedenen Typen bestehen.
+poll.manual.singleResponse=Eine Frage, bei der man eine Antwort auswählen kann. Beispielsweise für eine simple Ja- oder Nein-Frage.
+poll.manual.multiResponse=Eine Frage, bei der man mehrere Antworten auswählen kann. Gut geeignet für eine Terminabfragen oder Essenabfrage.
+poll.manual.textQuestion=Eine Frage, bei der man mit Freitext antworten kann. Gut geeignet für formloses Feedback.
poll.other=Andere
poll.owner=Ersteller
poll.popup.closed=Umfrage wurde bereits beendet
@@ -2215,6 +2228,7 @@ poll.questionType=Fragetypen
poll.question.TextQuestion=Antwort
poll.question.SingleResponseQuestion=Frage
poll.question.MultiResponseQuestion=Frage
+poll.question.AnnotationField=Anmerkungen:
#Fragen Container Überschrift
TextQuestion=Frage mit freier text Antwort
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt
index f14ac0196f..d5566b51e8 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt
@@ -40,6 +40,7 @@ class Poll(
var deadline: LocalDate? = null,
var state: PollDO.State? = PollDO.State.RUNNING,
var questionType: String? = null,
+ var prequestionType: String? = null,
var inputFields: MutableList? = mutableListOf(),
var fullAccessGroups: List? = null,
var fullAccessUsers: List? = null,
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
index 44c998c444..8038cb993d 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
@@ -24,6 +24,9 @@
package org.projectforge.rest.poll
import org.projectforge.business.group.service.GroupService
+import org.projectforge.business.poll.PollDO
+import org.projectforge.business.poll.PollDao
+import org.projectforge.business.poll.PollResponseDao
import org.projectforge.business.user.service.UserService
import org.projectforge.mail.Mail
import org.projectforge.mail.MailAttachment
@@ -46,6 +49,12 @@ class PollMailService {
@Autowired
private lateinit var userService: UserService
+ @Autowired
+ private lateinit var pollDao: PollDao
+
+ @Autowired
+ private lateinit var pollResponseDao: PollResponseDao
+
private val log: Logger = LoggerFactory.getLogger(PollMailService::class.java)
fun sendMail(
@@ -111,4 +120,13 @@ class PollMailService {
User.restoreEmails(userList, userService)
return userList.mapNotNull { it.email }
}
+
+ fun getAllAttendesEmails(poll: Poll): List {
+ val attendees = poll.attendees
+
+ var userList = attendees
+
+ User.restoreEmails(userList, userService)
+ return userList!!.mapNotNull { it.email }
+ }
}
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
index 7ce8a1d70d..38de4a0bea 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
@@ -40,16 +40,19 @@ import org.projectforge.framework.persistence.api.MagicFilter
import org.projectforge.framework.persistence.api.QueryFilter
import org.projectforge.framework.persistence.api.impl.CustomResultFilter
import org.projectforge.framework.persistence.user.api.ThreadLocalUserContext
+import org.projectforge.mail.MailAttachment
import org.projectforge.menu.MenuItem
import org.projectforge.menu.MenuItemTargetType
import org.projectforge.rest.config.Rest
import org.projectforge.rest.config.RestUtils
-import org.projectforge.rest.core.*
-import org.projectforge.rest.dto.*
+import org.projectforge.rest.core.AbstractDTOPagesRest
+import org.projectforge.rest.core.PagesResolver
+import org.projectforge.rest.core.RestResolver
+import org.projectforge.rest.dto.Group
+import org.projectforge.rest.dto.PostData
+import org.projectforge.rest.dto.User
import org.projectforge.rest.poll.excel.ExcelExport
-import org.projectforge.rest.poll.types.BaseType
-import org.projectforge.rest.poll.types.PREMADE_QUESTIONS
-import org.projectforge.rest.poll.types.Question
+import org.projectforge.rest.poll.types.*
import org.projectforge.ui.*
import org.projectforge.ui.filter.UIFilterListElement
import org.slf4j.Logger
@@ -63,12 +66,11 @@ import java.time.LocalDateTime
import java.util.*
import javax.servlet.http.HttpServletRequest
+
@RestController
@RequestMapping("${Rest.URL}/poll")
class PollPageRest : AbstractDTOPagesRest(PollDao::class.java, "poll.title") {
- private var emailSent: Boolean = false
-
private val log: Logger = LoggerFactory.getLogger(PollPageRest::class.java)
@Autowired
@@ -86,6 +88,9 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
@Autowired
private lateinit var excelExport: ExcelExport
+ @Autowired
+ private lateinit var exporter: ExcelExport
+
@Autowired
private lateinit var pollResponseDao: PollResponseDao
@@ -215,64 +220,89 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
.add(UISelect.createGroupSelect(lc, "fullAccessGroups", true, "poll.fullAccessGroups"))
.add(UISelect.createUserSelect(lc, "attendees", true, "poll.attendees"))
.add(UISelect.createGroupSelect(lc, "groupAttendees", true, "poll.groupAttendees"))
- if (!dto.isAlreadyCreated()) {
+
+ if(!dto.isAlreadyCreated()) {
+
fieldset.add(
UIRow()
.add(
- UICol(UILength(xs = 9, sm = 9, md = 9, lg = 9))
+ UICol(UILength(xs = 10, sm = 10, md = 10, lg = 10))
.add(
UISelect(
- "questionType",
- values = BaseType.values()
- .map { UISelectValue(it, translateMsg("poll.questionType." + it.name)) },
- label = "poll.questionType"
- )
- )
- )
- .add(
- UICol(UILength(xs = 3, sm = 3, md = 3, lg = 3))
- .add(UISpacer())
- .add(
- UIButton.createDefaultButton(
- id = "add-question-button",
- title = "poll.button.addQuestion",
- responseAction = ResponseAction(
- "${Rest.URL}/poll/add",
- targetType = TargetType.PUT
- ),
- default = false
+ "prequestionType",
+ values = PreType.values()
+ .map { UISelectValue(it, translateMsg("poll.templateType" + it.name)) },
+ label = "poll.questionTemplate"
)
)
)
)
+
.add(
UIRow()
.add(
- UICol(UILength(xs = 9, sm = 9, md = 9, lg = 9))
+ UICol(UILength(xs = 11, sm = 11, md = 11, lg = 11))
)
.add(
- UICol(UILength(xs = 3, sm = 3, md = 3, lg = 3))
+ UICol(UILength(xs = 2, sm = 2, md = 2, lg = 2))
.add(
- //Sollte zu UISelect geändert werden um mehrere Vorlagen erstellen zu können ohne mehrer Buttons zu haben
UIButton.createDefaultButton(
id = "template-button",
+ title = "poll.premade.template",
responseAction = ResponseAction(
"${Rest.URL}/poll/addPremadeQuestions",
targetType = TargetType.PUT
),
- title = "poll.button.template",
default = false
)
)
)
)
+
+ fieldset.add(
+ UIRow()
+ .add(
+ UICol(UILength(xs = 10, sm = 10, md = 10, lg = 10))
+ .add(
+ UISelect(
+ "questionType",
+ values = BaseType.values()
+ .map { UISelectValue(it, translateMsg("poll.questionType." + it.name)) },
+ label = "poll.questionType"
+ )
+ )
+ )
+ )
+
+
+
+ .add(
+ UIRow()
+ .add(
+ UICol(UILength(xs = 11, sm = 11, md = 11, lg = 11))
+ )
+ .add(
+ UICol(UILength(xs = 3, sm = 3, md = 3, lg = 3))
+ .add(UISpacer())
+ .add(
+ UIButton.createDefaultButton(
+ id = "add-question-button",
+ title = "poll.button.addQuestion",
+ responseAction = ResponseAction(
+ "${Rest.URL}/poll/add",
+ targetType = TargetType.PUT
+ ),
+ default = false
+ )
+ )
+ )
+ )
}
addQuestionFieldset(layout, dto, fieldset)
layout.watchFields.add("delegationUser")
layout.watchFields.addAll(listOf("groupAttendees"))
-
val processedLayout = LayoutUtils.processEditPage(layout, dto, this)
if (!dto.isFinished()) {
processedLayout.actions.filterIsInstance().find {
@@ -300,45 +330,97 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
+ @GetMapping("export")
+ fun export(@RequestParam("id") id: String): ResponseEntity? {
+ val poll = Poll()
+ val pollDo = pollDao.getById(id.toInt())
+ poll.copyFrom(pollDo)
+ User.restoreDisplayNames(poll.attendees, userService)
+ val bytes: ByteArray? = excelExport
+ .getExcel(poll)
+ val filename = ("${poll.title}_${LocalDateTime.now().year}_Result.xlsx")
+
+ if (bytes == null || bytes.isEmpty()) {
+ log.error("Oops, xlsx is empty. Filename: $filename")
+ return null
+ }
+ log.info("Exporting $filename")
+ return RestUtils.downloadFile(filename, bytes)
+ }
+
@PutMapping("/finish")
fun changeStateToFinish(
request: HttpServletRequest, obj: PollDO,
- @RequestBody postData: PostData
+ @RequestBody postData: PostData,
): ResponseEntity {
postData.data.state = PollDO.State.FINISHED
postData.data.deadline = LocalDate.now()
val responseEntity = super.saveOrUpdate(request, postData)
+ var emailSent: Boolean = false
+ var FUemailSent: Boolean = false
- if (postData.data.state == PollDO.State.FINISHED) {
+ if (postData.data.state == PollDO.State.FINISHED) {
- val owner = userService.getUser(postData.data.owner?.id)
- val mailFrom = owner?.email.toString()
- val mailTo = pollMailService.getAllMails(postData.data)
- val mailSubject = translateMsg("poll.mail.ended.subject", postData.data.title)
- val mailContent = translateMsg("poll.mail.ended.content", postData.data.title, owner?.displayName)
- pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
- emailSent = true
- }
+ val poll = Poll()
+ val id: String
+ id = postData.data.id.toString()
+ val pollDo = pollDao.getById(id.toInt())
+ poll.copyFrom(pollDo)
+ User.restoreDisplayNames(poll.attendees, userService)
+
+ val excel = excelExport.getExcel(poll)
+ val filename = ("${postData.data.title}_${LocalDateTime.now().year}_Result.xlsx")
+
+ val mailAttachment = object : MailAttachment {
+ override fun getFilename(): String {
+ return filename
+ }
+
+ override fun getContent(): ByteArray? {
+ return excel
+ }
+ }
+
+ if (FUemailSent != true) {
+
+ val owner = userService.getUser(postData.data.owner?.id)
+ val mailFrom = owner?.email.toString()
+ val mailTo = pollMailService.getAllFullAccessEmails(postData.data)
+ val mailSubject = translateMsg("poll.mail.ended.fullAccess.subject", postData.data.title)
+ val mailContent = translateMsg("poll.mail.ended.fullAccess.content", postData.data.title, owner?.displayName)
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent, listOf(mailAttachment))
+ FUemailSent = true
+ }
+
+ val owner = userService.getUser(postData.data.owner?.id)
+ val mailFrom = owner?.email.toString()
+ val mailTo = pollMailService.getAllAttendesEmails(postData.data)
+ val mailSubject = translateMsg("poll.mail.ended.subject", postData.data.title)
+ val mailContent = translateMsg("poll.mail.ended.content", postData.data.title, owner?.displayName)
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+ emailSent = true
+ }
return responseEntity
}
-
override fun onBeforeSaveOrUpdate(request: HttpServletRequest, obj: PollDO, postData: PostData) {
if (obj.inputFields.isNullOrEmpty() || obj.inputFields.equals("[]")) {
throw AccessException("poll.error.oneQuestionRequired")
}
- super.onBeforeSaveOrUpdate(request, obj, postData)
+ if (obj.attendeeIds.isNullOrEmpty() || obj.attendeeIds.equals("[]")) {
+ throw AccessException("poll.error.oneAttendeRequired")
+ }
+
+ super.onBeforeSaveOrUpdate(request, obj,postData)
}
override fun onAfterSaveOrUpdate(request: HttpServletRequest, obj: PollDO, postData: PostData) {
if (postData.data.state != PollDO.State.FINISHED) {
- var mailTo = pollMailService.getAllMails(postData.data)
-
val owner = userService.getUser(obj.owner?.id)
val mailFrom = owner?.email.toString()
val mailSubject: String
@@ -346,16 +428,20 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
if (postData.data.isAlreadyCreated()) {
- var mailTo = pollMailService.getAllFullAccessEmails(postData.data)
+ val mailTo = pollMailService.getAllFullAccessEmails(postData.data)
mailSubject = translateMsg("poll.mail.update.subject")
- mailContent = translateMsg("poll.mail.update.content", obj.title, owner?.displayName
+ mailContent = translateMsg(
+ "poll.mail.update.content", obj.title, owner?.displayName
)
pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
} else {
+
+ val mailTo = pollMailService.getAllMails(postData.data)
+
mailSubject = translateMsg("poll.mail.created.subject", obj.title)
mailContent = translateMsg(
"poll.mail.created.content",
@@ -366,9 +452,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
}
-
}
-
super.onAfterSaveOrUpdate(request, obj, postData)
}
@@ -402,6 +486,8 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val question = Question(uid = UUID.randomUUID().toString(), type = type)
if (type == BaseType.SingleResponseQuestion) {
question.answers = mutableListOf("", "")
+ } else if (type == BaseType.MultiResponseQuestion) {
+ question.answers = mutableListOf("", "", "")
}
dto.inputFields?.add(question)
@@ -452,12 +538,24 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
@PutMapping("/addPremadeQuestions")
private fun addPremadeQuestionsField(
- @RequestBody postData: PostData,
+ @RequestBody postData: PostData
): ResponseEntity {
val dto = postData.data
- PREMADE_QUESTIONS.entries.forEach { entry ->
- dto.inputFields?.add(entry.value)
+ val ptype = dto.prequestionType?.let { PreType.valueOf(it) } ?: PreType.Neujahrsfeier
+ val question = PQuestion(uid = UUID.randomUUID().toString(), pType = ptype)
+ if (ptype == PreType.Sommerfest) {
+ Sommerfest.entries.forEach { entry ->
+ dto.inputFields?.add(entry.value)
+ }
+ } else if (ptype == PreType.Neujahrsfeier) {
+ Neujahrsfeier.entries.forEach { entry ->
+ dto.inputFields?.add(entry.value)
+ }
+ } else if (ptype == PreType.Teamessen) {
+ Teamessen.entries.forEach { entry ->
+ dto.inputFields?.add(entry.value)
+ }
}
return ResponseEntity.ok(
@@ -466,7 +564,6 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
)
}
-
private fun addQuestionFieldset(layout: UILayout, dto: Poll, fieldset: UIFieldset) {
fieldset.add(UISpacer())
dto.inputFields?.forEachIndexed { index, field ->
@@ -515,7 +612,6 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
}
-
private fun generateSingleAndMultiResponseAnswer(
objGiven: Boolean,
inputFieldIndex: Int,
@@ -613,25 +709,6 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
- @GetMapping("export")
- fun export(@RequestParam("id") id: String): ResponseEntity? {
- val poll = Poll()
- val pollDo = pollDao.getById(id.toInt())
- poll.copyFrom(pollDo)
- User.restoreDisplayNames(poll.attendees, userService)
- val bytes: ByteArray? = excelExport
- .getExcel(poll)
- val filename = ("${poll.title}_${LocalDateTime.now().year}_Result.xlsx")
-
- if (bytes == null || bytes.isEmpty()) {
- log.error("Oops, xlsx is empty. Filename: $filename")
- return null
- }
- log.info("Exporting $filename")
- return RestUtils.downloadFile(filename, bytes)
- }
-
-
companion object {
/**
* Once created, questions should be ReadOnly
@@ -644,7 +721,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
dataType: UIDataType = UIDataType.STRING
): UIElement {
return if (isReadOnly)
- UIInput(id, label = label, dataType = dataType)
+ UIReadOnlyField(id, label = label, dataType = dataType)
else
UIInput(id, label = label, dataType = dataType)
}
@@ -677,6 +754,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
/**
* restricts the user access accordingly
*/
+
private fun getUserAccess(pollDto: Poll): UILayout.UserAccess {
val pollDO = PollDO()
pollDto.copyTo(pollDO)
@@ -698,5 +776,8 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
}
}
-
}
+
+
+
+
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
index c7bf53815f..2cb797df19 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
@@ -126,8 +126,7 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
.add(UIReadOnlyField(value = pollDto.location, label = translateMsg("poll.location")))
.add(UIReadOnlyField(value = pollDto.owner?.displayName, label = translateMsg("poll.owner")))
.add(UIReadOnlyField(value = pollDto.deadline.toString(), label = translateMsg("poll.deadline")))
- .add(UISpacer())
- .add(UISpacer())
+
if (!pollDto.isFinished() && ThreadLocalUserContext.userId === questionOwnerId) {
val fieldSetDelegationUser = UIFieldset(title = "poll.userDelegation")
@@ -165,6 +164,7 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
pollResponse.copyFrom(it)
}
+ var index = 0
pollDto.inputFields?.forEachIndexed { index, field ->
val fieldSetQuestions = UIFieldset(title = field.question)
val questionAnswer = QuestionAnswer()
@@ -194,24 +194,36 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
if (pollResponse.responses?.get(index)?.answers?.getOrNull(index2) == null) {
pollResponse.responses?.get(index)?.answers?.add(index2, false)
}
- if (field.type == BaseType.MultiResponseQuestion) {
+ if (field.type == BaseType.SingleResponseQuestion) {
col.add(
- UICheckbox(
+ UIRadioButton(
"responses[$index].answers[$index2]",
+ value = field.answers?.get(index2) ?: "",
label = field.answers?.get(index2) ?: ""
)
)
- } else {
+ } else if (field.type == BaseType.MultiResponseQuestion) {
col.add(
- UIRadioButton(
- "responses[$index].answers[0]",
- value = field.answers?.get(index2) ?: "",
+ UICheckbox(
+ "responses[$index].answers[$index2]",
label = field.answers?.get(index2) ?: ""
)
)
}
}
}
+
+ /* val isLastField = index == pollDto.inputFields?.size?.minus(1)
+
+ if (isLastField) {
+ col.add(
+ UIInput(
+ "responses[$index].answers[$index]",
+ )
+ )
+ }
+ */
+
fieldSetQuestions.add(UIRow().add(col))
fieldset.add(fieldSetQuestions)
}
@@ -355,4 +367,4 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
}
return poll
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
new file mode 100644
index 0000000000..db3179467f
--- /dev/null
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
@@ -0,0 +1,25 @@
+package org.projectforge.rest.poll.types
+
+import com.fasterxml.jackson.databind.ObjectMapper
+
+class PQuestion (
+ val uid: String? = null,
+ val question: String? = "",
+ val pType: PreType? = PreType.Neujahrsfeier,
+ var answers: MutableList? = mutableListOf(""),
+ var parent: String? = null,
+ var isRequired: Boolean? = false,
+ var numberOfSelect: Int? = 1,
+) {
+ fun toObject(string: String): PQuestion {
+ return ObjectMapper().readValue(string, PQuestion::class.java)
+ }
+
+ fun toJson(): String {
+ return ObjectMapper().writeValueAsString(this)
+ }
+}
+
+enum class PreType {
+ Neujahrsfeier, Sommerfest, Teamessen,
+}
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
index 987d2b836c..d83f02f538 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
@@ -26,7 +26,7 @@ package org.projectforge.rest.poll.types
import java.util.UUID
-val PREMADE_QUESTIONS = mapOf(
+val Neujahrsfeier = mapOf(
"HAS_FOOD" to Question(
uid = UUID.randomUUID().toString(),
question = "Was willst du essen?",
@@ -64,3 +64,64 @@ val PREMADE_QUESTIONS = mapOf(
answers = mutableListOf("Ja", "Nein")
),
)
+
+val Sommerfest = mapOf(
+ "IS_IN" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Nimmst du teil ?",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Ja", "Nein")
+ ),
+ "WHAT_TO_EAT" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Zur Essens Auswahl gibt es",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Pizza", "Pasta", "Burger")
+ ),
+ "CAN_HAVE_COMPANIONS" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Kommst du in Begleitung ?",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Ja", "Nein")
+ ),
+ "HOW_MANY_COMPANIONS" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Wenn du in Begleitung kommst wie viele ?",
+ type = BaseType.TextQuestion,
+ answers = mutableListOf("")
+ ),
+ "CAN_STAY_OVERNIGHT" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Willst du vor ort Ãœbernachten ?",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Ja", "Nein")
+ ),
+ "HAS_BREAKFAST" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Wenn du übernachtest möchtest du am nächsten tag Frühstück ?",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Ja", "Nein")
+ ),
+)
+
+val Teamessen = mapOf(
+ "IS_IN" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Hast du Zeit und Lust ?",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Ja", "Nein")
+ ),
+ "WHAT_TO_EAT" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Zur Essens Auswahl gibt es",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Pizza", "Pasta", "Burger")
+ ),
+ "CAN_STAY_OVERNIGHT" to Question(
+ uid = UUID.randomUUID().toString(),
+ question = "Welcher dieser Termine passt dir am besten ? (Du kannst auch mehrere ankreuzen)",
+ type = BaseType.MultiResponseQuestion,
+ answers = mutableListOf("", "")
+ ),
+)
+
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
index f69e487753..433721ec31 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
@@ -45,6 +45,6 @@ class Question(
}
enum class BaseType {
- TextQuestion, SingleResponseQuestion, MultiResponseQuestion,
+ TextQuestion, SingleResponseQuestion, MultiResponseQuestion
}
From b2e9145aa84e6ad170ad3bebf7986ec456533b2b Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Thu, 18 Apr 2024 12:02:33 +0200
Subject: [PATCH 03/16] =?UTF-8?q?Excel=20Export=20with=20Annotations,=20Ne?=
=?UTF-8?q?w=20Poll=20Design,=20Email=20for=20FAU=20and=20Attendes,=20Cust?=
=?UTF-8?q?om=20Email=20Field=20in=20Poll=20Creation,=20Annotation=20field?=
=?UTF-8?q?=20under=20Every=20Single=20or=20Multi=20Response=20question,?=
=?UTF-8?q?=20New=20Premadequestions=20like=20Sommerfest,=20Fr=C3=BChlings?=
=?UTF-8?q?fest=20or=20Neujahrsfeier.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../main/resources/I18nResources.properties | 64 +++-
.../resources/I18nResources_de.properties | 43 ++-
.../kotlin/org/projectforge/rest/poll/Poll.kt | 4 +-
.../projectforge/rest/poll/PollCronJobs.kt | 3 +-
.../rest/poll/PollInfoPageRest.kt | 2 +-
.../projectforge/rest/poll/PollMailService.kt | 2 +-
.../projectforge/rest/poll/PollPageRest.kt | 306 ++++++++++++++----
.../rest/poll/PollResponsePageRest.kt | 33 +-
.../rest/poll/excel/ExcelExport.kt | 72 +++--
.../projectforge/rest/poll/types/PQuestion.kt | 2 +-
.../rest/poll/types/PollResponse.kt | 3 +-
.../rest/poll/types/PremadeQuestions.kt | 36 +--
.../projectforge/rest/poll/types/Question.kt | 3 +-
13 files changed, 421 insertions(+), 152 deletions(-)
diff --git a/projectforge-business/src/main/resources/I18nResources.properties b/projectforge-business/src/main/resources/I18nResources.properties
index e328ad239d..ddf625ad02 100644
--- a/projectforge-business/src/main/resources/I18nResources.properties
+++ b/projectforge-business/src/main/resources/I18nResources.properties
@@ -100,6 +100,7 @@ uptodate=up-to-date
wizard=Wizard
# Common
+location=Location
akquise=Acquisition
changes=Changes
charactersLeft=characters left.
@@ -278,7 +279,7 @@ timePeriod=Time period
timestamp=Time stamp
timezone=Time zone
tip=Tip
-title=Title
+titel=Title
totalSum=Total sum
undefined=undefined
until=until
@@ -2021,20 +2022,57 @@ poll.groupAttendees=Attendee Groups
poll.guide=Poll Guide
poll.infopage=Info Page
poll.location=Location
-poll.mail.ended.content=Dear Attendees,
\
-We wanted to let you know that the poll "{0}" created by {1} has now ended. Thank you to everyone who participated and provided valuable input.
\
-If you missed the deadline to submit your responses, we encourage you to still share your thoughts with us. While we may not be able to include your responses in the official results, your feedback is still valuable for future polls.
\
-Thank you again for your participation.
\
-Best regards,
\
-{1}
-poll.mail.ended.subject=Poll ended
-poll.mail.endingSoon.content=Dear Attendees,
\
-This is a friendly reminder that the poll "{0}" created by {1} is ending soon, on {2}. Please make sure to submit your responses before the deadline.
\
-If you have not yet had a chance to participate, please take a few moments to do so before the poll closes. Your input is important and valued.
\
-{3}
\
-Thank you for your attention, and have a great day!
\
+
+
+poll.mail.ended.fullAccess.subject=The survey titled "{0}" has ended
+poll.mail.ended.fullAccess.content=This email is for all full-access users. Attached is the Excel spreadsheet containing the survey results.
+
+poll.annotations.description=In the annotation field, you can add information that you believe is not clearly defined in the responses or if you wish to provide important information, such as allergies.
+
+poll.email-subject-tooltip=Here you can choose the subject of the email yourself. Use {0} to insert the survey title and {1} to set the automatic end date of the survey - which is the deadline for voting. \
+
+
+poll.email-content-tooltip=Here you can determine the content of the email yourself. Use {0} to call the survey title. With {1}, you can display the survey creator, with {2} you create a direct link to the survey.\
+ \ Use {3} to retrieve the survey description, and {4} to automatically retrieve the end date of the survey, i.e., the deadline for voting.
+
+poll.fullAccessUser.tooltip=Full access users have the ability to close the survey, view the Excel results, and add or remove individuals (they cannot remove themselves). They are not counted as participants.\
+ \ If these individuals are also supposed to vote, they must be additionally registered as participants.
+
+poll.fullAccessgroups.tooltip=Full access groups include, for example, the BUs, the MUK team, or the Marketing team. Individuals with full access can close the survey prematurely, view the Excel results, or add users. \
+ If these individuals are supposed to vote, they must be added as participants.
+
+poll.attendees.tooltip=Attendees can only vote.
+
+poll.groupAttendees.tooltip=Group attendees are a convenient way to add entire groups, such as BUs, all at once instead of individually. Attendees can only vote.
+
+poll.premadeQuestion.tooltip=In this menu, you will find frequently used templates that help you create the survey quickly. If questions are missing in the template, you can also add them. Additionally,\
+ \ you have the option to revise or correct questions if they do not apply to your situation in the template.
+
+poll.questionType.tooltip=Question types offer various options for questions, including single-choice questions, multiple-choice questions, and text questions. You can easily add them if a question is missing\
+ \ in the template or if you want to create your own survey without using a template.
+
+
+
+annotations=Annotations
+
+email-content-field=Email Content
+email-subject-field=Email Subject
+
+poll.premade.template=Add Template
+poll.questionTemplate=Templates
+poll.templateTypeNeujahrsfeier=New Year's Party
+poll.templateTypeSommerfest=Summer Party
+poll.templateTypeTeamessen=Team Dinner
+
+poll.mail.ended.subject=The survey titled "{0}" has ended
+poll.mail.ended.content=Dear participants,
\
+We would like to inform you that the survey "{0}", created by {1}, has now ended. Thank you to all who participated.
\
+You can still view your results/answers, but you can no longer edit them.
\
+If you forgot to vote or perhaps want to make some changes, please contact an authorized person or the creator, in this case "{1}".
\
+
\
Best regards,
\
{1}
+
poll.mail.endingSoon.subject=Poll ending in {0} days
poll.mail.update.content=Dear Attendees,
\
We wanted to let you know that the poll "{0}" was edited recently.
\
diff --git a/projectforge-business/src/main/resources/I18nResources_de.properties b/projectforge-business/src/main/resources/I18nResources_de.properties
index 10afc1604c..70843de279 100644
--- a/projectforge-business/src/main/resources/I18nResources_de.properties
+++ b/projectforge-business/src/main/resources/I18nResources_de.properties
@@ -2114,21 +2114,53 @@ poll.groupAttendees=Teilnehmergruppen
poll.guide=Anleitung
poll.infopage=Infoseite
poll.location=Ort
+location.description=Hier kann man die Location vom Event eintragen.
location=Ort
owner=Ersteller
+annotations=Anmerkungen
+
+email-content-field=Email Inhalt
+email-subject-field=Email Titel
+
+poll.annotations.description=Im Anmerkungsfeld kannst du Informationen hinzufügen, die in den Antworten nicht klar definiert wurden deiner Meinung nach oder wenn du wichtige informationen hinzugeben möchtest wie zum Beispiel Allergien.
+
+poll.email-subject-tooltip= Hier kannst du den Betreff der E-Mail selbst wählen. Verwende {0}, um den Titel der Umfrage einzufügen, und {1}, um das automatische Enddatum der Umfrage zu setzen -\
+ \ das ist die Deadline für die Abstimmung.
+poll.email-content-tooltip=Hier kannst du den Inhalt der E-Mail selbst bestimmen. Verwende {0}, um den Titel der Umfrage aufzurufen. Mit {1} kannst du den Ersteller der Umfrage anzeigen, mit {2} \
+ erstellst du einen direkten Link zur Umfrage. Nutze {3}, um die Beschreibung der Umfrage abzurufen, und {4} um automatische das Enddatum der Umfrage abzurufen, also die Deadline für die Abstimmung. \
+
+poll.fullAccessUser.tooltip=Vollzugriffbenutzer:innen haben die Möglichkeit, die Umfrage zu beenden, die Excel-Ergebnisse einzusehen sowie Personen hinzuzufügen oder zu entfernen\
+ \ (Sie können sich nicht selbst entfernen). Sie werden nicht als Teilnehmer gezählt. Wenn diese Personen auch abstimmen sollen, müssen sie zusätzlich als Teilnehmer eingetragen werden.
+
+poll.fullAccessgroups.tooltip=Zu den Vollzugriffgruppen gehören beispielsweise die BU's, das MUK-Team oder auch das Marketing-Team. Personen mit Vollzugriff können die Umfrage vorzeitig beenden,\
+ \ die Excel-Ergebnisse einsehen oder auch Nutzer hinzufügen. Wenn diese Personen abstimmen sollen, müssen sie diese noch als Teilnehmer hinzufügen.
+
+poll.attendees.tooltip=Teilnehmer:innen können nur abstimmen.
+
+poll.groupAttendees.tooltip=Teilnehmergruppen sind eine praktische Möglichkeit, nicht jede Person einzeln hinzufügen, sondern ganze Gruppen wie BUs auf einmal. Teilnehmer können nur abstimmen.
+
+poll.premadeQuestion.tooltip=In diesem Menü findest du häufig verwendete Vorlagen, die dir dabei helfen, die Umfrage schnell zu erstellen. Falls Fragen in der Vorlage fehlen, kannst du sie auch hinzufügen. \
+ Außerdem hast du die Möglichkeit, Fragen zu überarbeiten oder zu korrigieren, wenn sie in der Vorlage nicht auf deine Situtation zutreffen.
+
+poll.questionType.tooltip=Fragetypen bieten verschiedene Möglichkeiten für Fragen, darunter Einzelantwortfragen, Mehrfachantwortfragen und Textfragen. Du kannst sie einfach hinzufügen, \
+ falls eine Frage in der Vorlage fehlt oder wenn du deine eigene Umfrage erstellen möchtest, ohne eine Vorlage zu verwenden.
+
+poll.error.cantremoveyourself=Du kannst dich nicht selber als Full Access User entfernen bitte einen anderen Full Access User oder den Erstelle dieser Umfrage dies für dich zu tun.
+
+
poll.premade.template=Vorlage hinzufügen
poll.questionTemplate=Vorlagen
poll.templateTypeNeujahrsfeier=Neujahrsfeier
poll.templateTypeSommerfest=Sommerfest
poll.templateTypeTeamessen=Teamessen
-
#Umfrage wurde erstellt
-poll.mail.created.subject=Sie wurden zu einer Umfrage eingeladen mit dem Titel "{0}"
+poll.mail.created.subject=Sie wurden zu einer Umfrage eingeladen mit dem Titel "{0}" eingeladen.
poll.mail.created.content=Liebe Teilnehmerinnen und Teilnehmer,
\
Wir möchten Ihnen mitteilen, dass eine Umfrage erstellt wurde mit dem Titel "{0}", und Sie wurden herzlichst eingeladen bei dieser Abzustimmen.
\
Hier kommst du direkt zur Umfrage
\
+ \\
Mit Freundlichen Grüßen,
\
{1}
@@ -2169,8 +2201,7 @@ poll.mail.ended.content=Liebe Teilnehmerinnen und Teilnehmer,
\
{1}
poll.mail.ended.fullAccess.subject=Die Umfrage mit dem Title "{0}" wurde Beendet
-poll.mail.ended.fullAccess.content=Den Text nochmal ändern damit die Full Access\
-\User bescheid wissen das diese Email nur die Excel enthält
+poll.mail.ended.fullAccess.content=Diese Email ist für Alle Vollzugriffnutzer:innen. Im Anhang ist die Excel Tabelle mit den Ergebnissen der Umfrage.
#Umfrage abgelaufen
@@ -2198,12 +2229,14 @@ poll.question.text=Eingabe
poll.question.single=Frage
poll.question.multi=Frage
+poll.running=
+poll.finished=
poll.question.texttitle= Text Frage
poll.question.singletitel= Eine Antwort Frage
poll.question.multititle= Mehrere Antworten Frage
-
+poll.error.oneAttendeRequired=Bitte füge mindestens einen Teilnehmer hinzu
#Kalender Monate
January=Januar
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt
index d5566b51e8..00dba155f6 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/Poll.kt
@@ -40,6 +40,8 @@ class Poll(
var deadline: LocalDate? = null,
var state: PollDO.State? = PollDO.State.RUNNING,
var questionType: String? = null,
+ var customemailsubject: String? = null,
+ var customemailcontent: String? = null,
var prequestionType: String? = null,
var inputFields: MutableList? = mutableListOf(),
var fullAccessGroups: List? = null,
@@ -78,4 +80,4 @@ class Poll(
fun isFinished(): Boolean {
return state == PollDO.State.FINISHED
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt
index d4689e210d..eb083bdfa3 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollCronJobs.kt
@@ -65,13 +65,14 @@ class PollCronJobs {
* Cron job for daily stuff
*/
- @Scheduled(cron = "0 0 1 * * *") // 1am everyday
+ @Scheduled(cron = "0 0 */12 * * *") //Alle 12 Stunden
fun dailyCronJobs() {
log.info("Start daily cron jobs")
cronDeletePolls()
cronEndPolls()
}
+
/**
* Method to end polls after deadline
*/
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt
index e5e58afd71..85bc0381ec 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollInfoPageRest.kt
@@ -121,4 +121,4 @@ class PollInfoPageRest : AbstractDynamicPageRest() {
return FormLayoutData(null, layout, createServerData(request))
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
index 8038cb993d..9d8a1728a9 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
@@ -129,4 +129,4 @@ class PollMailService {
User.restoreEmails(userList, userService)
return userList!!.mapNotNull { it.email }
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
index 38de4a0bea..1e489d8de8 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
@@ -33,6 +33,7 @@ import org.projectforge.business.poll.filter.PollAssignmentFilter
import org.projectforge.business.poll.filter.PollState
import org.projectforge.business.poll.filter.PollStateFilter
import org.projectforge.business.user.service.UserService
+import org.projectforge.common.i18n.UserException
import org.projectforge.framework.access.AccessException
import org.projectforge.framework.i18n.translate
import org.projectforge.framework.i18n.translateMsg
@@ -215,36 +216,99 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
addDefaultParameterFields(dto, fieldset, isRunning = dto.state == PollDO.State.RUNNING)
- fieldset
- .add(UISelect.createUserSelect(lc, "fullAccessUsers", true, "poll.fullAccessUsers"))
- .add(UISelect.createGroupSelect(lc, "fullAccessGroups", true, "poll.fullAccessGroups"))
- .add(UISelect.createUserSelect(lc, "attendees", true, "poll.attendees"))
- .add(UISelect.createGroupSelect(lc, "groupAttendees", true, "poll.groupAttendees"))
-
- if(!dto.isAlreadyCreated()) {
+ val rowWidth = UILength(xs = 12, sm = 12, md = 12, lg = 12)
+ val colWidth = UILength(xs = 12, sm = 12, md = 6, lg = 6)
- fieldset.add(
+ fieldset
+ .add(
UIRow()
.add(
- UICol(UILength(xs = 10, sm = 10, md = 10, lg = 10))
+ UICol(colWidth)
+ .add(
+ UISelect.createUserSelect(
+ lc,
+ "fullAccessUsers",
+ true,
+ "poll.fullAccessUsers",
+ tooltip = "poll.fullAccessUser.tooltip"
+ )
+ )
+ )
+ .add(
+ UICol(colWidth)
.add(
- UISelect(
- "prequestionType",
- values = PreType.values()
- .map { UISelectValue(it, translateMsg("poll.templateType" + it.name)) },
- label = "poll.questionTemplate"
+ UISelect.createGroupSelect(
+ lc,
+ "fullAccessGroups",
+ true,
+ "poll.fullAccessGroups",
+ tooltip = "poll.fullAccessgroups.tooltip"
)
)
)
)
+ .add(
+ UIRow()
+ .add(
+ UICol(colWidth)
+ .add(
+ UISelect.createUserSelect(
+ lc,
+ "attendees",
+ true,
+ "poll.attendees",
+ tooltip = "poll.attendees.tooltip"
+ )
+ )
+ )
+ .add(
+ UICol(colWidth)
+ .add(
+ UISelect.createGroupSelect(
+ lc,
+ "groupAttendees",
+ true,
+ "poll.groupAttendees",
+ tooltip = "poll.groupAttendees.tooltip"
+ )
+ )
+ )
+ )
+
+ if(!dto.isAlreadyCreated()) {
+ fieldset
.add(
UIRow()
.add(
- UICol(UILength(xs = 11, sm = 11, md = 11, lg = 11))
+ UICol(colWidth)
+ .add(
+ UISelect(
+ "prequestionType",
+ values = PreType.values()
+ .map { UISelectValue(it, translateMsg("poll.templateType" + it.name)) },
+ label = "poll.questionTemplate",
+ tooltip = "poll.premadeQuestion.tooltip"
+ )
+ )
+ )
+ .add(
+ UICol(colWidth)
+ .add(
+ UISelect(
+ "questionType",
+ values = BaseType.values()
+ .map { UISelectValue(it, translateMsg("poll.questionType." + it.name)) },
+ label = "poll.questionType",
+ tooltip = "poll.questionType.tooltip"
+ )
+ )
)
+ )
+ .add(
+ UIRow()
.add(
- UICol(UILength(xs = 2, sm = 2, md = 2, lg = 2))
+ UICol(colWidth)
.add(
UIButton.createDefaultButton(
id = "template-button",
@@ -257,47 +321,79 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
)
)
)
+ .add(
+ UICol(colWidth)
+ .add(
+ UIButton.createDefaultButton(
+ id = "add-question-button",
+ title = "poll.button.addQuestion",
+ responseAction = ResponseAction(
+ "${Rest.URL}/poll/add",
+ targetType = TargetType.PUT
+ ),
+ default = false
+ )
+ )
+ )
)
-
- fieldset.add(
- UIRow()
- .add(
- UICol(UILength(xs = 10, sm = 10, md = 10, lg = 10))
- .add(
- UISelect(
- "questionType",
- values = BaseType.values()
- .map { UISelectValue(it, translateMsg("poll.questionType." + it.name)) },
- label = "poll.questionType"
- )
- )
- )
- )
-
-
-
- .add(
- UIRow()
- .add(
- UICol(UILength(xs = 11, sm = 11, md = 11, lg = 11))
- )
- .add(
- UICol(UILength(xs = 3, sm = 3, md = 3, lg = 3))
- .add(UISpacer())
- .add(
- UIButton.createDefaultButton(
- id = "add-question-button",
- title = "poll.button.addQuestion",
- responseAction = ResponseAction(
- "${Rest.URL}/poll/add",
- targetType = TargetType.PUT
- ),
- default = false
- )
+ .add(
+ UIRow()
+ .add(
+ UICol(colWidth)
+ .add(
+ UIInput(
+ "customemailsubject",
+ required = false,
+ label = "email-subject-field",
+ tooltip = "poll.email-subject-tooltip"
)
- )
- )
+ )
+ )
+ .add(
+ UICol(colWidth)
+ .add(
+ UISpacer()
+ )
+ )
+ )
+ .add(
+ UIRow()
+ .add(
+ UICol(colWidth)
+ .add(
+ UITextArea (
+ "customemailcontent",
+ label = "email-content-field",
+ tooltip = "poll.email-content-tooltip",
+ rows = 12,
+ maxRows = 60
+ )
+ )
+ )
+ .add(
+ UICol(colWidth)
+ .add(
+ UISpacer()
+ )
+ )
+ )
+
}
+
+
+ val content = "Liebe Teilnehmerinnen und Teilnehmer\n" +
+ "Wir möchten Ihnen mitteilen, dass eine Umfrage erstellt wurde mit dem Titel \"{0}\", und Sie wurden herzlichst eingeladen bei dieser Abzustimmen.\n" +
+ "\n" +
+ "Die Umfrage zu welcher sie Eingeladen worden endet am {4} eine Kurze Beschreibung um was es geht gibt es hier nochmal '{3}'\n" +
+ "Hier kommst du direkt zur {2}\n" +
+ "\n" +
+ "Mit Freundlichen Grüßen\n" +
+ "{1}"
+ dto.customemailcontent = content
+
+ val subject = "Sie wurden zu einer Umfrage eingeladen mit dem Titel \"{0}\" eingeladen."
+ dto.customemailsubject = subject
+
addQuestionFieldset(layout, dto, fieldset)
layout.watchFields.add("delegationUser")
@@ -415,10 +511,13 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
super.onBeforeSaveOrUpdate(request, obj,postData)
+
}
+
override fun onAfterSaveOrUpdate(request: HttpServletRequest, obj: PollDO, postData: PostData) {
+
if (postData.data.state != PollDO.State.FINISHED) {
val owner = userService.getUser(obj.owner?.id)
@@ -430,7 +529,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val mailTo = pollMailService.getAllFullAccessEmails(postData.data)
- mailSubject = translateMsg("poll.mail.update.subject")
+ mailSubject = translateMsg("poll.mail.update.subject", obj.description, obj.deadline)
mailContent = translateMsg(
"poll.mail.update.content", obj.title, owner?.displayName
)
@@ -439,18 +538,64 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
} else {
+ val dto = postData.data
- val mailTo = pollMailService.getAllMails(postData.data)
+ val subject = dto.customemailsubject
+ val content = dto.customemailcontent
+
+ if (subject.isNullOrEmpty() && content.isNullOrEmpty()) {
+ val mailTo = pollMailService.getAllMails(postData.data)
+
+ mailSubject = translateMsg("poll.mail.created.subject", obj.title, obj.description, obj.deadline)
+ mailContent = translateMsg(
+ "poll.mail.created.content",
+ obj.title,
+ owner?.displayName,
+ "http://localhost:8080/react/pollResponse/dynamic/?pollId=${obj.id}"
+ )
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+
+ } else if (subject.isNullOrEmpty() && !content.isNullOrEmpty()) {
+ val mailTo = pollMailService.getAllMails(postData.data)
+
+ mailSubject = translateMsg("poll.mail.created.subject", obj.title, obj.deadline)
+ mailContent = translateMsg(content,
+ obj.title,
+ owner?.displayName,
+ "Hier kommst du direkt zur Umfrage
",
+ obj.description,
+ obj.deadline
+ )
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+ } else if (!subject.isNullOrEmpty() && content.isNullOrEmpty()) {
+ val mailTo = pollMailService.getAllMails(postData.data)
+
+ mailSubject = translateMsg("$subject", obj.title, obj.deadline)
+ mailContent = translateMsg("poll.mail.created.content",
+ obj.title,
+ owner?.displayName,
+ "http://localhost:8080/react/pollResponse/dynamic/?pollId=${obj.id}",
+ obj.description,
+ obj.deadline
+ )
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+
+ } else if (!subject.isNullOrEmpty() && !content.isNullOrEmpty()){
+ val mailTo = pollMailService.getAllMails(postData.data)
+
+ mailSubject = translateMsg("$subject", obj.title, obj.deadline)
+ mailContent = translateMsg(content,
+ obj.title,
+ owner?.displayName,
+ "Hier kommst du direkt zur Umfrage
",
+ obj.description,
+ obj.deadline
+ )
+ pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
+
+ }
- mailSubject = translateMsg("poll.mail.created.subject", obj.title)
- mailContent = translateMsg(
- "poll.mail.created.content",
- obj.title,
- owner?.displayName,
- "http://localhost:8080/react/pollResponse/dynamic/?pollId=${obj.id}"
- )
- pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
}
}
super.onAfterSaveOrUpdate(request, obj, postData)
@@ -729,11 +874,32 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
private fun addDefaultParameterFields(pollDto: Poll, fieldset: UIFieldset, isRunning: Boolean) {
+
+ val colWidth = UILength(xs = 12, sm = 12, md = 6, lg = 6)
if (isRunning) {
fieldset
.add(lc, "title", "description", "location")
- .add(UISelect.createUserSelect(lc, "owner", false, "poll.owner"))
- .add(lc, "deadline")
+ .add(
+ UIRow()
+ .add(
+ UICol(colWidth)
+ .add(
+ UISelect.createUserSelect(
+ lc,
+ "owner",
+ false,
+ "poll.owner",
+ )
+ )
+ )
+ .add(
+ UICol(colWidth)
+ .add(
+ lc,
+ "deadline",
+ )
+ )
+ )
} else {
fieldset
.add(UIReadOnlyField(value = pollDto.title, label = "titel", dataType = UIDataType.STRING))
@@ -759,6 +925,8 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val pollDO = PollDO()
pollDto.copyTo(pollDO)
+ //Fua entfernen
+
return if (!pollDao.hasFullAccess(pollDO)) {
// no full access user
UILayout.UserAccess(insert = false, update = false, delete = false, history = false)
@@ -776,8 +944,4 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
}
}
-}
-
-
-
-
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
index 2cb797df19..35ef5a4ba1 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
@@ -128,7 +128,9 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
.add(UIReadOnlyField(value = pollDto.deadline.toString(), label = translateMsg("poll.deadline")))
- if (!pollDto.isFinished() && ThreadLocalUserContext.userId === questionOwnerId) {
+
+ /* Aktuell nicht benutzbar auskommentiert bis es behoben wird
+ if (pollDto.isFinished() && ThreadLocalUserContext.userId === questionOwnerId && pollDao.hasFullAccess(pollData)) {
val fieldSetDelegationUser = UIFieldset(title = "poll.userDelegation")
fieldSetDelegationUser.add(
UIInput(
@@ -154,6 +156,8 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
layout.add(fieldSetDelegationUser)
}
+ */
+
val pollResponse = PollResponse()
pollResponse.poll = pollData
@@ -164,7 +168,6 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
pollResponse.copyFrom(it)
}
- var index = 0
pollDto.inputFields?.forEachIndexed { index, field ->
val fieldSetQuestions = UIFieldset(title = field.question)
val questionAnswer = QuestionAnswer()
@@ -189,40 +192,38 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
)
}
+ var index3 = 0
if (field.type == BaseType.MultiResponseQuestion || field.type === BaseType.SingleResponseQuestion) {
field.answers?.forEachIndexed { index2, _ ->
if (pollResponse.responses?.get(index)?.answers?.getOrNull(index2) == null) {
pollResponse.responses?.get(index)?.answers?.add(index2, false)
}
- if (field.type == BaseType.SingleResponseQuestion) {
+ if (field.type == BaseType.MultiResponseQuestion) {
col.add(
- UIRadioButton(
+ UICheckbox(
"responses[$index].answers[$index2]",
- value = field.answers?.get(index2) ?: "",
label = field.answers?.get(index2) ?: ""
)
)
- } else if (field.type == BaseType.MultiResponseQuestion) {
+ } else {
col.add(
- UICheckbox(
- "responses[$index].answers[$index2]",
+ UIRadioButton(
+ "responses[$index].answers[0]",
+ value = field.answers?.get(index2) ?: "",
label = field.answers?.get(index2) ?: ""
)
)
}
}
- }
-
- /* val isLastField = index == pollDto.inputFields?.size?.minus(1)
-
- if (isLastField) {
col.add(
- UIInput(
- "responses[$index].answers[$index]",
+ UITextArea(
+ "responses[$index].annotation[0]",
+ label = "annotations",
+ additionalLabel = "poll.annotations.description"
)
)
+
}
- */
fieldSetQuestions.add(UIRow().add(col))
fieldset.add(fieldSetQuestions)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index 86c58d3ccc..a614283153 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -133,12 +133,19 @@ class ExcelExport {
val excelRow = excelSheet.getRow(0)
val excelRow1 = excelSheet.getRow(1)
+
style.alignment = HorizontalAlignment.CENTER
var merge = 1
poll.inputFields?.forEach { question ->
val answers = question.answers
+ var totalAnswerLength = question.answers?.sumBy { countWords(it) } ?: 0
+ var questionLength = question.question?.let { countWords(it) }
if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
+ if (!question.answers!!.contains("Anmerkung")) {
+ val ind = question.answers!!.size
+ question.answers!!.add(ind,"Anmerkung")
+ }
var counter = merge
question.answers?.forEach { answer ->
excelRow1.getCell(counter).setCellValue(answer)
@@ -170,36 +177,52 @@ class ExcelExport {
excelRow.getCell(0).setCellValue(user.displayName)
- excelSheet.autosize(0)
var cell = 0
+ excelSheet.autosize(0)
var largestAnswer = ""
poll.inputFields?.forEachIndexed { _, question ->
- val questionAnswer = res?.responses?.find { it.questionUid == question.uid }
+ val questionpossibilities = res?.responses?.find { it.questionUid == question.uid }
- if (questionAnswer?.answers.isNullOrEmpty()) {
- cell += question.answers?.size ?: 0
- }
- questionAnswer?.answers?.forEachIndexed { ind, answer ->
- cell++
- if (question.type == BaseType.MultiResponseQuestion) {
- if (answer is Boolean && answer == true) {
- excelRow.getCell(cell).setCellValue("X")
- }
- } else if (question.type == BaseType.SingleResponseQuestion) {
- if (answer is String && answer.equals(question.answers?.get(ind))) {
- excelRow.getCell(cell).setCellValue("X")
+ var index = 0
+ var size = 0;
+ question.answers?.forEachIndexed { ind, answer ->
+ index = question.answers!!.size - 1
+ cell++
+
+
+ if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
+ if (index == ind && questionpossibilities != null) {
+ excelSheet.autosize(cell)
+ excelRow.getCell(cell).setCellValue(questionpossibilities.annotation!!.get(0))
+ }
}
- } else {
- excelRow.getCell(cell).setCellValue(answer.toString())
- if (countLines(answer.toString()) > countLines(largestAnswer)) {
- largestAnswer = answer.toString()
+
+ if (question.type == BaseType.MultiResponseQuestion) {
+ questionpossibilities?.answers?.forEach {
+ excelSheet.autosize(cell)
+ if (questionpossibilities.answers?.get(ind)!!.equals(true) && ind != index) {
+ excelRow.getCell(cell).setCellValue("X")
+ }
+ }
+ } else if (question.type == BaseType.SingleResponseQuestion) {
+ excelSheet.autosize(cell)
+ if (answer is String && answer.equals(questionpossibilities?.answers?.get(0)) && ind != index) {
+ excelRow.getCell(cell).setCellValue("X")
+ }
+ } else {
+ if (questionpossibilities?.answers?.isNotEmpty() == true) {
+ excelSheet.autosize(cell)
+ excelRow.getCell(cell).setCellValue(questionpossibilities.answers?.get(0).toString())
+ if (countLines(answer.toString()) > countLines(largestAnswer)) {
+ largestAnswer = answer.toString()
+ }
+ }
}
}
- excelSheet.autosize(cell)
}
- }
+ largestAnswer = "i"
val puffer: String = largestAnswer
var counterOfBreaking = 0
var counterOfOverlength = 0
@@ -209,13 +232,19 @@ class ExcelExport {
// check for line-breaks
for (i in pufferSplit.indices) {
counterOfBreaking++
- counterOfOverlength += pufferSplit[i].length / 70
+ counterOfOverlength += pufferSplit[i].length / 20
}
excelRow.setHeight((14 + counterOfOverlength * 14 + counterOfBreaking * 14).toFloat())
}
+
+ private fun countWords(text: String): Int {
+ return text.split("\\s+".toRegex()).filter { it.isNotEmpty() }.size
+ }
+
private fun countLines(str: String): Int {
val lines = str.split("\r\n|\r|\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+
return lines.size
}
@@ -240,3 +269,4 @@ class ExcelExport {
}
}
}
+
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
index db3179467f..31c8ff5dbb 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
@@ -22,4 +22,4 @@ class PQuestion (
enum class PreType {
Neujahrsfeier, Sommerfest, Teamessen,
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PollResponse.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PollResponse.kt
index 081a1b6584..36e83eab2f 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PollResponse.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PollResponse.kt
@@ -53,9 +53,10 @@ class QuestionAnswer {
var uid: String? = null
var questionUid: String? = ""
var answers: MutableList? = mutableListOf()
+ var annotation: MutableList? = mutableListOf()
fun toObject(string: String): QuestionAnswer {
return ObjectMapper().readValue(string, QuestionAnswer::class.java)
}
-}
+}
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
index d83f02f538..79ccf74ad5 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PremadeQuestions.kt
@@ -23,6 +23,7 @@
package org.projectforge.rest.poll.types
+import net.bytebuddy.pool.TypePool.Empty
import java.util.UUID
@@ -33,12 +34,6 @@ val Neujahrsfeier = mapOf(
type = BaseType.SingleResponseQuestion,
answers = mutableListOf("Fleisch", "Vegetarisch", "Vegan")
),
- "IS_REMOTE" to Question(
- uid = UUID.randomUUID().toString(),
- question = "Nimmst du remote teil?",
- type = BaseType.SingleResponseQuestion,
- answers = mutableListOf("Ja", "Nein")
- ),
"CAN_HAVE_COMPANIONS" to Question(
uid = UUID.randomUUID().toString(),
question = "Nimmst du eine Begleitung mit? (Name der Begleitung)",
@@ -72,21 +67,21 @@ val Sommerfest = mapOf(
type = BaseType.SingleResponseQuestion,
answers = mutableListOf("Ja", "Nein")
),
- "WHAT_TO_EAT" to Question(
+ "WITH_HOW_MANY" to Question(
uid = UUID.randomUUID().toString(),
- question = "Zur Essens Auswahl gibt es",
- type = BaseType.SingleResponseQuestion,
- answers = mutableListOf("Pizza", "Pasta", "Burger")
+ question = "Kommst du in Begleitung ? Wenn ja mit wie vielen ?",
+ type = BaseType.TextQuestion,
+ answers = mutableListOf("")
),
- "CAN_HAVE_COMPANIONS" to Question(
+ "CHILDRENS" to Question(
uid = UUID.randomUUID().toString(),
- question = "Kommst du in Begleitung ?",
+ question = "Sind Kinder unter deiner Begleitpersonen ?",
type = BaseType.SingleResponseQuestion,
answers = mutableListOf("Ja", "Nein")
),
- "HOW_MANY_COMPANIONS" to Question(
+ "HOW_OLD_ARE_THE_CHILDS" to Question(
uid = UUID.randomUUID().toString(),
- question = "Wenn du in Begleitung kommst wie viele ?",
+ question = "Wenn du Kinder unter deiner Begleitung hast wie alt sind diese ?",
type = BaseType.TextQuestion,
answers = mutableListOf("")
),
@@ -96,12 +91,18 @@ val Sommerfest = mapOf(
type = BaseType.SingleResponseQuestion,
answers = mutableListOf("Ja", "Nein")
),
- "HAS_BREAKFAST" to Question(
+ "WHERE_DO_YOU_WANT_TO_STAY" to Question(
uid = UUID.randomUUID().toString(),
- question = "Wenn du übernachtest möchtest du am nächsten tag Frühstück ?",
+ question = "Wenn du übernachtest wo möchtest du übernachten ?",
type = BaseType.SingleResponseQuestion,
- answers = mutableListOf("Ja", "Nein")
+ answers = mutableListOf("In meinem eigenen Van/Mobil", "Ich bräuchte eine Übernachtungsmöglichkeit", "Ich komme irgendwo anders unter")
),
+ "WHAT_DO_YOU_EAT" to Question (
+ uid = UUID.randomUUID().toString(),
+ question = "Welche Art von Ernährung bevorzugst du ?",
+ type = BaseType.SingleResponseQuestion,
+ answers = mutableListOf("Omnivor (Fleisch)", "Pescetarier (Fisch)", "Vegetarisch", "Vegan")
+ )
)
val Teamessen = mapOf(
@@ -124,4 +125,3 @@ val Teamessen = mapOf(
answers = mutableListOf("", "")
),
)
-
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
index 433721ec31..48b41d5bfe 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/Question.kt
@@ -46,5 +46,4 @@ class Question(
enum class BaseType {
TextQuestion, SingleResponseQuestion, MultiResponseQuestion
-}
-
+}
\ No newline at end of file
From 50e9512493c116531a1877feb0f53d7850dd3ed7 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Thu, 25 Apr 2024 08:33:48 +0200
Subject: [PATCH 04/16] Pull Request fixes
---
.../main/resources/I18nResources.properties | 59 +---------
.../resources/I18nResources_de.properties | 109 +-----------------
.../projectforge/rest/AddressViewPageRest.kt | 5 +-
.../projectforge/rest/poll/PollPageRest.kt | 5 +-
.../types/{PQuestion.kt => PreQuestion.kt} | 6 +-
5 files changed, 14 insertions(+), 170 deletions(-)
rename projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/{PQuestion.kt => PreQuestion.kt} (79%)
diff --git a/projectforge-business/src/main/resources/I18nResources.properties b/projectforge-business/src/main/resources/I18nResources.properties
index ddf625ad02..6acc28ddee 100644
--- a/projectforge-business/src/main/resources/I18nResources.properties
+++ b/projectforge-business/src/main/resources/I18nResources.properties
@@ -13,19 +13,15 @@ validation.error.range.integerOutOfRange=Value out of range {0}-{1}.
validation.error.range.integerToHigh=Value must not be higher than {0}.
validation.error.range.integerToLow=Value must not be lower than {0}.
validation.required.valueNotPresent=Value ''{0}'' not present.
-
# React UI
select.placeholder=Select...
table.showing=Showing
-
# own validations:
bicvalidator.wronglength=The field ''${label}'' must be 8 or 11 characters long.
ibanvalidator.wronglength.de=The field ''${label}'' starts with ''DE'', but a german IBAN must have 22 characters.
-
# Currency format
currencyConverter.percentage.help=You can enter amounts as well as percent values (e. g. 10%).
currencyFormat={0,number,,##0.00}
-
# Not internationalized properties:
exception.notYetSupported=Not yet supported.
menu.adminGuide=Administration guide
@@ -35,7 +31,6 @@ menu.projectDocumentation=Project docs
menu.sqlConsole=SQL console
menu.userGuide=Handbuch
message.notYetImplemented=Not yet implemented.
-
# Buttons:
add=Add
assign=Assign
@@ -98,9 +93,10 @@ updateAndNext=Update and next
upload=Upload
uptodate=up-to-date
wizard=Wizard
-
# Common
location=Location
+no=No
+yes=Yes
akquise=Acquisition
changes=Changes
charactersLeft=characters left.
@@ -188,14 +184,6 @@ moreEntriesAvailable=More entries available.
name=Name
new=New
nickname=Nickname
-
-
-
-
-
-
-
-
notEnded=not ended
nothingFound=Nothing found.
notLoggedIn=Not logged in.
@@ -279,7 +267,7 @@ timePeriod=Time period
timestamp=Time stamp
timezone=Time zone
tip=Tip
-titel=Title
+title=Title
totalSum=Total sum
undefined=undefined
until=until
@@ -1982,17 +1970,10 @@ plugins.teamcal.title.add=Add calendar
plugins.teamcal.title.edit=Edit team calendar
plugins.teamcal.title.heading=Calendar
plugins.teamcal.title.list=List of calendars
-
-
-
-
-
# poll plugin
TextQuestion=Text Question
SingleResponseQuestion=Single Response Question
MultiResponseQuestion=Multiple Choice Question
-
-
poll=Poll
poll.access=Access
poll.answer=Option
@@ -2022,48 +2003,30 @@ poll.groupAttendees=Attendee Groups
poll.guide=Poll Guide
poll.infopage=Info Page
poll.location=Location
-
-
poll.mail.ended.fullAccess.subject=The survey titled "{0}" has ended
poll.mail.ended.fullAccess.content=This email is for all full-access users. Attached is the Excel spreadsheet containing the survey results.
-
poll.annotations.description=In the annotation field, you can add information that you believe is not clearly defined in the responses or if you wish to provide important information, such as allergies.
-
poll.email-subject-tooltip=Here you can choose the subject of the email yourself. Use {0} to insert the survey title and {1} to set the automatic end date of the survey - which is the deadline for voting. \
-
-
poll.email-content-tooltip=Here you can determine the content of the email yourself. Use {0} to call the survey title. With {1}, you can display the survey creator, with {2} you create a direct link to the survey.\
\ Use {3} to retrieve the survey description, and {4} to automatically retrieve the end date of the survey, i.e., the deadline for voting.
-
poll.fullAccessUser.tooltip=Full access users have the ability to close the survey, view the Excel results, and add or remove individuals (they cannot remove themselves). They are not counted as participants.\
\ If these individuals are also supposed to vote, they must be additionally registered as participants.
-
poll.fullAccessgroups.tooltip=Full access groups include, for example, the BUs, the MUK team, or the Marketing team. Individuals with full access can close the survey prematurely, view the Excel results, or add users. \
If these individuals are supposed to vote, they must be added as participants.
-
poll.attendees.tooltip=Attendees can only vote.
-
poll.groupAttendees.tooltip=Group attendees are a convenient way to add entire groups, such as BUs, all at once instead of individually. Attendees can only vote.
-
poll.premadeQuestion.tooltip=In this menu, you will find frequently used templates that help you create the survey quickly. If questions are missing in the template, you can also add them. Additionally,\
\ you have the option to revise or correct questions if they do not apply to your situation in the template.
-
poll.questionType.tooltip=Question types offer various options for questions, including single-choice questions, multiple-choice questions, and text questions. You can easily add them if a question is missing\
\ in the template or if you want to create your own survey without using a template.
-
-
-
annotations=Annotations
-
email-content-field=Email Content
email-subject-field=Email Subject
-
poll.premade.template=Add Template
poll.questionTemplate=Templates
poll.templateTypeNeujahrsfeier=New Year's Party
poll.templateTypeSommerfest=Summer Party
poll.templateTypeTeamessen=Team Dinner
-
poll.mail.ended.subject=The survey titled "{0}" has ended
poll.mail.ended.content=Dear participants,
\
We would like to inform you that the survey "{0}", created by {1}, has now ended. Thank you to all who participated.
\
@@ -2072,7 +2035,6 @@ poll.mail.ended.content=Dear participants,
\
\
Best regards,
\
{1}
-
poll.mail.endingSoon.subject=Poll ending in {0} days
poll.mail.update.content=Dear Attendees,
\
We wanted to let you know that the poll "{0}" was edited recently.
\
@@ -2094,26 +2056,15 @@ poll.questionType=Question Type
poll.questionType.TextQuestion=Text Question
poll.questionType.SingleResponseQuestion=Single response Question
poll.questionType.MultiResponseQuestion=Multiple Choice Questions
-
poll.question.texttitle= Text Questions
poll.question.singletitel= Singel response Question
poll.question.multititle= Multiple Choice Questions
-
poll.question.text=Question
poll.question.single=Question
poll.question.multi=Question
-
poll.question.TextQuestion=Answer
poll.question.SingleResponseQuestion=Question
poll.question.MultiResponseQuestion=Question
-
-
-
-
-
-
-
-
poll.respond=Send responses
poll.response.mail.update.content=Dear {0},
\
I wanted to inform you that Person {2} has updated their answer to Poll {1}.
\
@@ -2738,7 +2689,6 @@ webauthn.registration.button.authenticate=WebAuthn
webauthn.registration.button.authenticate.info=You may use any of your registered WebAuthn tokens here (for example Yubikey).
webauthn.registration.button.register=Register
webauthn.title=WebAuthn (Fido2 etc.)
-
# (timeable) attributes
attr.deletemodal.heading=Would you like to delete this entry?
attr.deletemodal.question=Yes: This entry will be deleted and all changes on this page will be saved.
Cancel: This entry will not be deleted and you stay on this page.
@@ -2748,7 +2698,6 @@ attr.savemodal.question=Yes: All changes on this page will be saved.
<
attr.starttime.alreadyexists.day=There is already an entry with the same date (Day).
attr.starttime.alreadyexists.month=There is already an entry with the same date (Month).
attr.validFrom=Valid from
-
birthdayButler.email.content=In the month of {0}, {1} employees are celebrating their birthdays. Attached, you will find the list of birthdays.
birthdayButler.email.content.noBirthdaysFound=No birthday entries were found in the month of {0}.
birthdayButler.email.opening=New month, new birthday list!
@@ -2757,4 +2706,4 @@ birthdayButler.month.response.noEntry=There are no birthday entries for this mon
birthdayButler.month.response.nothingSelected=The month is required.
birthdayButler.organization.noMatchingUser=There are no users assigned to the organization configured in projectforge.properties.
birthdayButler.organization.notSet=No organization is defined in the application.properties. -> projectforge.birthdayButler.organization=Your Organization
-birthdayButler.wordDocument.error=Error while creating the Word document.
+birthdayButler.wordDocument.error=Error while creating the Word document.
\ No newline at end of file
diff --git a/projectforge-business/src/main/resources/I18nResources_de.properties b/projectforge-business/src/main/resources/I18nResources_de.properties
index 70843de279..e687deafcd 100644
--- a/projectforge-business/src/main/resources/I18nResources_de.properties
+++ b/projectforge-business/src/main/resources/I18nResources_de.properties
@@ -90,8 +90,6 @@
# system.pluginAdmin.button.deactivate=Deactivate
# system.pluginAdmin.title=Plugins
# system.statistics.databasePool=Data base pool
-
-
# Wicket:
datatable.no-records-found=Keine Einträge gefunden.
NavigatorLabel=Zeile ${from} bis ${to} von ${of}.
@@ -107,19 +105,15 @@ validation.error.range.integerOutOfRange=Wert au
validation.error.range.integerToHigh=Wert darf nicht größer als {0} sein.
validation.error.range.integerToLow=Wert darf nicht kleiner als {0} sein.
validation.required.valueNotPresent=Wert ''{0}'' nicht gegeben.
-
# React UI
select.placeholder=Auswählen...
table.showing=Anzeige
-
# own validations:
bicvalidator.wronglength=Das Feld ''${label}'' muss 8 oder 11 Zeichen lang sein.
ibanvalidator.wronglength.de=Das Feld ''${label}'' beginnt mit ''DE''. Eine deutsche IBAN muss jedoch aus 22 Zeichen bestehen.
-
# Currency format
currencyConverter.percentage.help=Es können sowohl Beträge als auch Prozentzahlen (z. B. 10%) eingegeben werden.
currencyFormat={0,number,,##0.00}
-
# Not internationalized properties:
### not translated: exception.notYetSupported=Not yet supported.
### not translated: menu.adminGuide=Administration guide
@@ -129,13 +123,11 @@ currencyFormat={0,number,,##0.00}
### not translated: menu.sqlConsole=SQL console
### not translated: menu.userGuide=Handbuch
### not translated: message.notYetImplemented=Not yet implemented.
-
# Buttons:
add=Hinzufügen
assign=Zuweisen
back=Zurück
cancel=Abbrechen
-
create=Anlegen
change=Ändern
check=Check
@@ -144,9 +136,9 @@ close=Schlie
copy=Kopieren
delete=Löschen
deselectAll=Alle abwählen
-download=Herunterladen
+download=Download
download.expired=Downloaddatei nicht mehr verfügbar. Bitte Aktion wiederholen.
-drop=Verwerfern
+drop=Drop
execute=Ausführen
exportAsPdf=Pdf-Exportieren
exportAsXls=Excel-Exportieren
@@ -157,7 +149,6 @@ favorite.untitled=unbenannt
favorites=Favoriten
favorites.saveModification=Änderungen speichern
finish=Fertig
-Button_Finish=Ja
forceDelete=Unwiderruflich löschen
import=Importieren
login=Anmelden
@@ -194,8 +185,6 @@ updateAndNext=
upload=Hochladen
uptodate=aktuell
wizard=Assistent
-
-
State.running=Laufend
poll.state.running
running=Laufend
@@ -380,7 +369,6 @@ username=Benutzer:innenname
value=Wert
values=Werte
weekOfYear=Kalenderwoche
-
access=Zugriffsrecht
access.accessTable=Zugriffstabelle
access.exception.demoUserHasNoAccess=Der oder die Demobenutzer:in ist für diese Aktion gesperrt.
@@ -2073,14 +2061,6 @@ plugins.teamcal.title.add=Kalender hinzuf
plugins.teamcal.title.edit=Team-Kalender bearbeiten
plugins.teamcal.title.heading=Kalender
plugins.teamcal.title.list=Kalenderliste
-
-
-
-
-
-
-
-
# poll plugin
poll=Umfrage
poll.access=Zugriff
@@ -2095,16 +2075,11 @@ Stelle ebenfalls sicher, dass du Teilnehmer f
poll.confirmation.deleteAnswer=Möchtest du diese Antwort wirklich löschen?
poll.confirmation.deleteQuestion=Möchtest du diese Frage wirklich löschen?
poll.confirmation.finish=Willst du die Umfrage wirklich beenden?
-
-
-
-
poll.state=Status
poll.date=Datum
poll.deadline=Umfragen Frist
poll.delegationAnswers=Antworten von
poll.description=Beschreibung
-
poll.error.oneQuestionRequired=Mindestens eine Frage ist erforderlich.
poll.exception.noAttendee=Dieser Nutzer ist nicht Teil der Umfrage.
poll.export.response.poll=Ergebnisse exportieren
@@ -2117,44 +2092,30 @@ poll.location=Ort
location.description=Hier kann man die Location vom Event eintragen.
location=Ort
owner=Ersteller
-
annotations=Anmerkungen
-
email-content-field=Email Inhalt
email-subject-field=Email Titel
-
poll.annotations.description=Im Anmerkungsfeld kannst du Informationen hinzufügen, die in den Antworten nicht klar definiert wurden deiner Meinung nach oder wenn du wichtige informationen hinzugeben möchtest wie zum Beispiel Allergien.
-
poll.email-subject-tooltip= Hier kannst du den Betreff der E-Mail selbst wählen. Verwende {0}, um den Titel der Umfrage einzufügen, und {1}, um das automatische Enddatum der Umfrage zu setzen -\
\ das ist die Deadline für die Abstimmung.
poll.email-content-tooltip=Hier kannst du den Inhalt der E-Mail selbst bestimmen. Verwende {0}, um den Titel der Umfrage aufzurufen. Mit {1} kannst du den Ersteller der Umfrage anzeigen, mit {2} \
erstellst du einen direkten Link zur Umfrage. Nutze {3}, um die Beschreibung der Umfrage abzurufen, und {4} um automatische das Enddatum der Umfrage abzurufen, also die Deadline für die Abstimmung. \
-
poll.fullAccessUser.tooltip=Vollzugriffbenutzer:innen haben die Möglichkeit, die Umfrage zu beenden, die Excel-Ergebnisse einzusehen sowie Personen hinzuzufügen oder zu entfernen\
\ (Sie können sich nicht selbst entfernen). Sie werden nicht als Teilnehmer gezählt. Wenn diese Personen auch abstimmen sollen, müssen sie zusätzlich als Teilnehmer eingetragen werden.
-
poll.fullAccessgroups.tooltip=Zu den Vollzugriffgruppen gehören beispielsweise die BU's, das MUK-Team oder auch das Marketing-Team. Personen mit Vollzugriff können die Umfrage vorzeitig beenden,\
\ die Excel-Ergebnisse einsehen oder auch Nutzer hinzufügen. Wenn diese Personen abstimmen sollen, müssen sie diese noch als Teilnehmer hinzufügen.
-
poll.attendees.tooltip=Teilnehmer:innen können nur abstimmen.
-
poll.groupAttendees.tooltip=Teilnehmergruppen sind eine praktische Möglichkeit, nicht jede Person einzeln hinzufügen, sondern ganze Gruppen wie BUs auf einmal. Teilnehmer können nur abstimmen.
-
poll.premadeQuestion.tooltip=In diesem Menü findest du häufig verwendete Vorlagen, die dir dabei helfen, die Umfrage schnell zu erstellen. Falls Fragen in der Vorlage fehlen, kannst du sie auch hinzufügen. \
Außerdem hast du die Möglichkeit, Fragen zu überarbeiten oder zu korrigieren, wenn sie in der Vorlage nicht auf deine Situtation zutreffen.
-
poll.questionType.tooltip=Fragetypen bieten verschiedene Möglichkeiten für Fragen, darunter Einzelantwortfragen, Mehrfachantwortfragen und Textfragen. Du kannst sie einfach hinzufügen, \
falls eine Frage in der Vorlage fehlt oder wenn du deine eigene Umfrage erstellen möchtest, ohne eine Vorlage zu verwenden.
-
poll.error.cantremoveyourself=Du kannst dich nicht selber als Full Access User entfernen bitte einen anderen Full Access User oder den Erstelle dieser Umfrage dies für dich zu tun.
-
-
poll.premade.template=Vorlage hinzufügen
poll.questionTemplate=Vorlagen
poll.templateTypeNeujahrsfeier=Neujahrsfeier
poll.templateTypeSommerfest=Sommerfest
poll.templateTypeTeamessen=Teamessen
-
#Umfrage wurde erstellt
poll.mail.created.subject=Sie wurden zu einer Umfrage eingeladen mit dem Titel "{0}" eingeladen.
poll.mail.created.content=Liebe Teilnehmerinnen und Teilnehmer,
\
@@ -2163,9 +2124,6 @@ poll.mail.created.content=Liebe Teilnehmerinnen und Teilnehmer,
\
\\
Mit Freundlichen Grüßen,
\
{1}
-
-
-
#Umfrage wurde Bearbeitet
poll.mail.update.subject=Umfrage wurde bearbeitet
poll.mail.update.content=Liebe Teilnehmerinnen und Teilnehmer,
\
@@ -2174,8 +2132,6 @@ poll.mail.update.content=Liebe Teilnehmerinnen und Teilnehmer,
\
Nochmals vielen Dank für Ihre Teilnahme.
\
Mit Freundlichen Grüßen,
\
{1}
-
-
#Umfrage endet Bald
poll.mail.endingSoon.subject=Umfrage endet in {0} Tagen
poll.mail.endingSoon.content=Liebe Teilnehmerinnen und Teilnehmer,
\
@@ -2186,10 +2142,6 @@ poll.mail.endingSoon.content=Liebe Teilnehmerinnen und Teilnehmer,
\
\
Mit Freundlichen Grüßen,
\
{1}
-
-
-
-
#Umfrage beendet
poll.mail.ended.subject=Die Umfrage mit dem Title "{0}" wurde Beendet
poll.mail.ended.content=Liebe Teilnehmerinnen und Teilnehmer,
\
@@ -2199,11 +2151,8 @@ poll.mail.ended.content=Liebe Teilnehmerinnen und Teilnehmer,
\
\
Mit Freundlichen Grüßen,
\
{1}
-
poll.mail.ended.fullAccess.subject=Die Umfrage mit dem Title "{0}" wurde Beendet
poll.mail.ended.fullAccess.content=Diese Email ist für Alle Vollzugriffnutzer:innen. Im Anhang ist die Excel Tabelle mit den Ergebnissen der Umfrage.
-
-
#Umfrage abgelaufen
poll.mail.endedafterdeadline.subject=Die Umfrage mit dem Title "{0}" ist Beendet die Deadline ist abgelaufen
poll.mail.endedafterdeadline.content=Liebe Teilnehmerinnen und Teilnehmer,
\
@@ -2213,8 +2162,6 @@ poll.mail.endedafterdeadline.content=Liebe Teilnehmerinnen und Teilnehmer,
\
Mit Freundlichen Grüßen,
\
{1}
-
-
poll.manual.title=Anleitung, um eine Umfrage zu erstellen | Als Erstes muss man den
poll.manual.questions=Anlegen. Anschließend werden die Fragen der Umfrage angelegt. Die Fragen können aus verschiedenen Typen bestehen.
poll.manual.singleResponse=Eine Frage, bei der man eine Antwort auswählen kann. Beispielsweise für eine simple Ja- oder Nein-Frage.
@@ -2223,21 +2170,15 @@ poll.manual.textQuestion=Eine Frage, bei der man mit Freitext antworten kann. Gu
poll.other=Andere
poll.owner=Ersteller
poll.popup.closed=Umfrage wurde bereits beendet
-
-
poll.question.text=Eingabe
poll.question.single=Frage
poll.question.multi=Frage
-
poll.running=
poll.finished=
-
poll.question.texttitle= Text Frage
poll.question.singletitel= Eine Antwort Frage
poll.question.multititle= Mehrere Antworten Frage
-
poll.error.oneAttendeRequired=Bitte füge mindestens einen Teilnehmer hinzu
-
#Kalender Monate
January=Januar
February=Februar
@@ -2251,82 +2192,42 @@ September=September
October=October
November=November
December=Dezember
-
-
-
#Fragen Dropdown menü name
poll.questionType=Fragetypen
-
#Frage Typen endung
poll.question.TextQuestion=Antwort
poll.question.SingleResponseQuestion=Frage
poll.question.MultiResponseQuestion=Frage
poll.question.AnnotationField=Anmerkungen:
-
#Fragen Container Überschrift
TextQuestion=Frage mit freier text Antwort
SingleResponseQuestion=Frage mit einer Ankreuzmöglichkeit
MultiResponseQuestion=Frage mit mehreren Ankrauzmöglichkeiten
-
#Fragen erstellung überschrift
Question=Fragestellung
-
#Eingabefeld überschriften/Auswahl möglichkeiten überschrift
poll.answer=Auswahl möglichkeit
-
PollState.RUNNING=Am Laufen
question.answers.Yes=Ja
question.answers=Ja
question.answers.0=Ja
question.answers.No=Nein
question.answers.1=Nein
-
-
-
-
-
-
poll.respond=Antworten abschicken
yes=Ja
+no=Nein
poll.questionType.TextQuestion=Text Frage
poll.questionType.SingleResponseQuestion=Einzelantwort Frage
poll.questionType.MultiResponseQuestion=Mehrfachauswahl Frage
-
-
-
-
-### not translated: poll.response.mail.update.content=Dear {0},
\
-#I wanted to inform you that Person {2} has updated their answer to Poll {1}.
\
-#If you were not notified about this,
\
-#I recommend reaching out to the person directly or adjusting your results accordingly.
\
-#You can modify your response until "{3}".
\
-#Best regards,
\
-#{2}
-### not translated: poll.response.mail.update.subject=Response was edited by {0}
poll.response.page=Seite zur Umfrageantwort
poll.response.title=Seite zur Umfrageantwort
poll.selectUser=Nutzer auswählen
-
-
-
poll.title=Titel
poll.title.add=Neue Umfrage erstellen
poll.title.edit=Umfrage bearbeiten
poll.title.list=Umfragen
poll.userDelegation=Für andere Nutzer abstimmen
poll.yourAnswers=Deine Antworten
-
-
-
-
-
-
-
-
-
-
-
-
projectmanagement.personDays=Personentage
projectmanagement.personDays.short=PT
question.deleteQuestion=Soll das Objekt wirklich unwiderruflich gelöscht werden?
@@ -2932,7 +2833,6 @@ webauthn.registration.button.authenticate=WebAuthn
webauthn.registration.button.authenticate.info=Du kannst hier registrierte WebAuthn-Token benutzen (z. B. Yubikey).
webauthn.registration.button.register=Registrieren
webauthn.title=WebAuthn (Fido2 etc.)
-
# (timeable) attributes
attr.deletemodal.heading=Soll dieser Eintrag wirklich gelöscht werden?
attr.deletemodal.question=Ja: Der Eintrag wird gelöscht und alle Änderungen auf dieser Seite werden gespeichert.
Abbrechen: Der Eintrag wird nicht gelöscht und Sie bleiben auf dieser Seite.
@@ -2942,7 +2842,6 @@ attr.savemodal.question=Ja: Alle
attr.starttime.alreadyexists.day=Es existiert bereits ein Eintrag mit gleichem Datum (Tag).
attr.starttime.alreadyexists.month=Es existiert bereits ein Eintrag mit gleichem Datum (Monat).
attr.validFrom=Gültig ab
-
birthdayButler.email.content=Im Monat {0} haben {1} Mitarbeiter Geburtstag. Im Anhang findest du die Liste der Geburtstage.
birthdayButler.email.content.noBirthdaysFound=Im Monat {0} wurden keine Geburtstagseinträge gefunden.
birthdayButler.email.opening=Ein neuer Monat, eine neue Geburtstagsliste!
@@ -2951,4 +2850,4 @@ birthdayButler.month.response.noEntry=Es gibt keine Geburtstagseintr
birthdayButler.month.response.nothingSelected=Der Monat muss ausgewählt sein.
birthdayButler.organization.noMatchingUser=Es gibt keine Benutzer:innen, die der in projectforge.properties gesetzten Organisation zugeordnet sind.
birthdayButler.organization.notSet=Es ist keine Organisation in den application.properties definiert. -> projectforge.birthdayTool.organization=Your Organization
-birthdayButler.wordDocument.error=Es ist ein Fehler beim Erstellen des Word-Dokuments aufgetreten.
+birthdayButler.wordDocument.error=Es ist ein Fehler beim Erstellen des Word-Dokuments aufgetreten.
\ No newline at end of file
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
index 2bff5443d4..d70c48629c 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
@@ -287,15 +287,12 @@ class AddressViewPageRest : AbstractDynamicPageRest() {
if (email.isNullOrBlank()) {
return
}
- val emailObject = EMail(email)
col.add(
UIRow()
.add(UICol(6).add(UILabel(title)))
- .add(UICol(6).add(UICustomized("email", mutableMapOf("email" to emailObject))))
+ .add(UICol(6).add(UICustomized("email", mutableMapOf("data" to EMail(email)))))
)
}
-
-
private fun createAddressCol(
row: UIRow,
numberOfAddresses: Int,
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
index 1e489d8de8..c08ef48307 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
@@ -33,7 +33,6 @@ import org.projectforge.business.poll.filter.PollAssignmentFilter
import org.projectforge.business.poll.filter.PollState
import org.projectforge.business.poll.filter.PollStateFilter
import org.projectforge.business.user.service.UserService
-import org.projectforge.common.i18n.UserException
import org.projectforge.framework.access.AccessException
import org.projectforge.framework.i18n.translate
import org.projectforge.framework.i18n.translateMsg
@@ -688,7 +687,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val dto = postData.data
val ptype = dto.prequestionType?.let { PreType.valueOf(it) } ?: PreType.Neujahrsfeier
- val question = PQuestion(uid = UUID.randomUUID().toString(), pType = ptype)
+ val question = PreQuestion(uid = UUID.randomUUID().toString(), pType = ptype)
if (ptype == PreType.Sommerfest) {
Sommerfest.entries.forEach { entry ->
dto.inputFields?.add(entry.value)
@@ -902,7 +901,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
)
} else {
fieldset
- .add(UIReadOnlyField(value = pollDto.title, label = "titel", dataType = UIDataType.STRING))
+ .add(UIReadOnlyField(value = pollDto.title, label = "title", dataType = UIDataType.STRING))
.add(UIReadOnlyField(value = pollDto.description, label = "description", dataType = UIDataType.STRING))
.add(UIReadOnlyField(value = pollDto.location, label = "location", dataType = UIDataType.STRING))
.add(
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PreQuestion.kt
similarity index 79%
rename from projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
rename to projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PreQuestion.kt
index 31c8ff5dbb..a7c3b91ade 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PQuestion.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/types/PreQuestion.kt
@@ -2,7 +2,7 @@ package org.projectforge.rest.poll.types
import com.fasterxml.jackson.databind.ObjectMapper
-class PQuestion (
+class PreQuestion (
val uid: String? = null,
val question: String? = "",
val pType: PreType? = PreType.Neujahrsfeier,
@@ -11,8 +11,8 @@ class PQuestion (
var isRequired: Boolean? = false,
var numberOfSelect: Int? = 1,
) {
- fun toObject(string: String): PQuestion {
- return ObjectMapper().readValue(string, PQuestion::class.java)
+ fun toObject(string: String): PreQuestion {
+ return ObjectMapper().readValue(string, PreQuestion::class.java)
}
fun toJson(): String {
From 1688ab5122eb2a2452338c28b42d3f484c79fb65 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 29 May 2024 12:27:21 +0200
Subject: [PATCH 05/16] ExcelExport IndexOutOfBoundFix
---
.../rest/poll/excel/ExcelExport.kt | 67 ++++++++++---------
1 file changed, 35 insertions(+), 32 deletions(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index a614283153..40159b2504 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -78,44 +78,44 @@ class ExcelExport {
createNewRow(excelSheet, emptyRow, anzNewRows)
setFirstRow(excelSheet, style, poll)
+ if (responses.isNotEmpty()) {
+ poll.attendees?.sortedBy { it.displayName }
+ poll.attendees?.forEachIndexed { index, user ->
+ val res = PollResponse()
+ responses.find { it.owner?.id == user.id }?.let { res.copyFrom(it) }
+ setNewRows(excelSheet, poll, user, res, index + FIRST_DATA_ROW_NUM)
+ }
+ val fullAccessUser = poll.fullAccessUsers?.toMutableList() ?: mutableListOf()
+ val accessGroupIds = poll.fullAccessGroups?.filter { it.id != null }?.map { it.id!! }?.toIntArray()
+ val accessUserIds = UserService().getUserIds(groupService.getGroupUsers(accessGroupIds))
+ val accessUsers = User.toUserList(accessUserIds)
+ User.restoreDisplayNames(accessUsers, userService)
- poll.attendees?.sortedBy { it.displayName }
- poll.attendees?.forEachIndexed { index, user ->
- val res = PollResponse()
- responses.find { it.owner?.id == user.id }?.let { res.copyFrom(it) }
- setNewRows(excelSheet, poll, user, res, index + FIRST_DATA_ROW_NUM)
- }
-
- val fullAccessUser = poll.fullAccessUsers?.toMutableList() ?: mutableListOf()
- val accessGroupIds = poll.fullAccessGroups?.filter { it.id != null }?.map { it.id!! }?.toIntArray()
- val accessUserIds = UserService().getUserIds(groupService.getGroupUsers(accessGroupIds))
- val accessUsers = User.toUserList(accessUserIds)
- User.restoreDisplayNames(accessUsers, userService)
-
- accessUsers?.forEach { user ->
- if (fullAccessUser.none { it.id == user.id }) {
- fullAccessUser.add(user)
+ accessUsers?.forEach { user ->
+ if (fullAccessUser.none { it.id == user.id }) {
+ fullAccessUser.add(user)
+ }
}
- }
- var owner = User.getUser(poll.owner?.id, false)
- if (owner != null) {
- fullAccessUser.add(owner)
- }
+ var owner = User.getUser(poll.owner?.id, false)
+ if (owner != null) {
+ fullAccessUser.add(owner)
+ }
- User.restoreDisplayNames(fullAccessUser, userService)
- fullAccessUser.forEachIndexed { _, user ->
- var number = (anzNewRows)
- if (poll.attendees?.map { it.id }?.contains(user.id) == false) {
- val res = PollResponse()
- responses.find { it.owner?.id == user.id }?.let { res.copyFrom(it) }
- // User add a Response
- if (res.id != null) {
- // Put data in the Row
- setNewRows(excelSheet, poll, user, res, number)
+ User.restoreDisplayNames(fullAccessUser, userService)
+ fullAccessUser.forEachIndexed { _, user ->
+ var number = (anzNewRows)
+ if (poll.attendees?.map { it.id }?.contains(user.id) == false) {
+ val res = PollResponse()
+ responses.find { it.owner?.id == user.id }?.let { res.copyFrom(it) }
+ if (res.id != null) {
+ setNewRows(excelSheet, poll, user, res, number)
+ }
}
}
+ } else {
+ println("Keine Antworten gefunden.")
}
return returnByteFile(excelSheet)
@@ -129,6 +129,7 @@ class ExcelExport {
}
+
private fun setFirstRow(excelSheet: ExcelSheet, style: CellStyle, poll: Poll) {
val excelRow = excelSheet.getRow(0)
val excelRow1 = excelSheet.getRow(1)
@@ -194,7 +195,9 @@ class ExcelExport {
if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
if (index == ind && questionpossibilities != null) {
excelSheet.autosize(cell)
- excelRow.getCell(cell).setCellValue(questionpossibilities.annotation!!.get(0))
+ if (questionpossibilities.annotation != null && questionpossibilities.annotation!!.size != 0) {
+ excelRow.getCell(cell).setCellValue(questionpossibilities.annotation!![0])
+ }
}
}
From 49118fddca69c7576188c6d4643e6c080fe71eb1 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 29 May 2024 13:30:07 +0200
Subject: [PATCH 06/16] Pull Request fixes
---
.../org/projectforge/rest/poll/excel/ExcelExport.kt | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index 40159b2504..415bf68a18 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -185,18 +185,18 @@ class ExcelExport {
poll.inputFields?.forEachIndexed { _, question ->
val questionpossibilities = res?.responses?.find { it.questionUid == question.uid }
- var index = 0
- var size = 0;
- question.answers?.forEachIndexed { ind, answer ->
- index = question.answers!!.size - 1
- cell++
+ var index = 0
+ var size = 0;
+ question.answers?.forEachIndexed { ind, answer ->
+ index = question.answers!!.size - 1
+ cell++
if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
if (index == ind && questionpossibilities != null) {
excelSheet.autosize(cell)
if (questionpossibilities.annotation != null && questionpossibilities.annotation!!.size != 0) {
- excelRow.getCell(cell).setCellValue(questionpossibilities.annotation!![0])
+ excelRow.getCell(cell).setCellValue(questionpossibilities.annotation?.get(0))
}
}
}
From 7c9d45b14bbc4547ffb11d7c3afce9f01f2b28f3 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 29 May 2024 13:58:55 +0200
Subject: [PATCH 07/16] Excel Export fix
---
.../org/projectforge/rest/poll/excel/ExcelExport.kt | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index 415bf68a18..4e4b18dd39 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -98,14 +98,14 @@ class ExcelExport {
}
}
- var owner = User.getUser(poll.owner?.id, false)
+ val owner = User.getUser(poll.owner?.id, false)
if (owner != null) {
fullAccessUser.add(owner)
}
User.restoreDisplayNames(fullAccessUser, userService)
fullAccessUser.forEachIndexed { _, user ->
- var number = (anzNewRows)
+ val number = (anzNewRows)
if (poll.attendees?.map { it.id }?.contains(user.id) == false) {
val res = PollResponse()
responses.find { it.owner?.id == user.id }?.let { res.copyFrom(it) }
@@ -140,8 +140,6 @@ class ExcelExport {
var merge = 1
poll.inputFields?.forEach { question ->
val answers = question.answers
- var totalAnswerLength = question.answers?.sumBy { countWords(it) } ?: 0
- var questionLength = question.question?.let { countWords(it) }
if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
if (!question.answers!!.contains("Anmerkung")) {
val ind = question.answers!!.size
@@ -186,12 +184,10 @@ class ExcelExport {
val questionpossibilities = res?.responses?.find { it.questionUid == question.uid }
var index = 0
- var size = 0;
question.answers?.forEachIndexed { ind, answer ->
index = question.answers!!.size - 1
cell++
-
if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
if (index == ind && questionpossibilities != null) {
excelSheet.autosize(cell)
From a79b83bcc4163adaeb92811af54019c2b477de6b Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 29 May 2024 14:14:03 +0200
Subject: [PATCH 08/16] Excel Export fix
---
.../org/projectforge/rest/poll/excel/ExcelExport.kt | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index 4e4b18dd39..cc4059a1a2 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -183,7 +183,7 @@ class ExcelExport {
poll.inputFields?.forEachIndexed { _, question ->
val questionpossibilities = res?.responses?.find { it.questionUid == question.uid }
- var index = 0
+ var index: Int
question.answers?.forEachIndexed { ind, answer ->
index = question.answers!!.size - 1
cell++
@@ -206,15 +206,15 @@ class ExcelExport {
}
} else if (question.type == BaseType.SingleResponseQuestion) {
excelSheet.autosize(cell)
- if (answer is String && answer.equals(questionpossibilities?.answers?.get(0)) && ind != index) {
+ if (answer == questionpossibilities?.answers?.get(0) && ind != index) {
excelRow.getCell(cell).setCellValue("X")
}
} else {
if (questionpossibilities?.answers?.isNotEmpty() == true) {
excelSheet.autosize(cell)
excelRow.getCell(cell).setCellValue(questionpossibilities.answers?.get(0).toString())
- if (countLines(answer.toString()) > countLines(largestAnswer)) {
- largestAnswer = answer.toString()
+ if (countLines(answer) > countLines(largestAnswer)) {
+ largestAnswer = answer
}
}
}
@@ -236,11 +236,6 @@ class ExcelExport {
excelRow.setHeight((14 + counterOfOverlength * 14 + counterOfBreaking * 14).toFloat())
}
-
- private fun countWords(text: String): Int {
- return text.split("\\s+".toRegex()).filter { it.isNotEmpty() }.size
- }
-
private fun countLines(str: String): Int {
val lines = str.split("\r\n|\r|\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
From ed2bb05b590c0a99b14659297a67c95027e627ee Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 29 May 2024 15:01:11 +0200
Subject: [PATCH 09/16] Excel Export fix
---
.../projectforge/rest/poll/PollMailService.kt | 21 ++++++-------------
.../projectforge/rest/poll/PollPageRest.kt | 18 ++++++----------
.../rest/poll/PollResponsePageRest.kt | 1 -
3 files changed, 12 insertions(+), 28 deletions(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
index 9d8a1728a9..463ecd13c8 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollMailService.kt
@@ -24,9 +24,6 @@
package org.projectforge.rest.poll
import org.projectforge.business.group.service.GroupService
-import org.projectforge.business.poll.PollDO
-import org.projectforge.business.poll.PollDao
-import org.projectforge.business.poll.PollResponseDao
import org.projectforge.business.user.service.UserService
import org.projectforge.mail.Mail
import org.projectforge.mail.MailAttachment
@@ -49,12 +46,6 @@ class PollMailService {
@Autowired
private lateinit var userService: UserService
- @Autowired
- private lateinit var pollDao: PollDao
-
- @Autowired
- private lateinit var pollResponseDao: PollResponseDao
-
private val log: Logger = LoggerFactory.getLogger(PollMailService::class.java)
fun sendMail(
@@ -84,19 +75,19 @@ class PollMailService {
fun getAllMails(poll: Poll): List {
val attendees = poll.attendees
- var fullAccessUser = poll.fullAccessUsers?.toMutableList() ?: mutableListOf()
+ val fullAccessUser = poll.fullAccessUsers?.toMutableList() ?: mutableListOf()
val accessGroupIds = poll.fullAccessGroups?.filter { it.id != null }?.map { it.id!! }?.toIntArray()
val accessUserIds = UserService().getUserIds(groupService.getGroupUsers(accessGroupIds))
val accessUsers = User.toUserList(accessUserIds)
- var userList = fullAccessUser
+ val userList = fullAccessUser
accessUsers?.forEach { user ->
if (fullAccessUser.none { it.id == user.id }) {
userList.add(user)
}
}
- var owner = User.getUser(poll.owner?.id, false)
+ val owner = User.getUser(poll.owner?.id, false)
if (owner != null) {
userList.add(owner)
}
@@ -113,9 +104,9 @@ class PollMailService {
fun getAllFullAccessEmails(poll: Poll): List {
val fullAccessUser = poll.fullAccessUsers?.toMutableList() ?: mutableListOf()
- val accessGroupIds = poll.fullAccessGroups?.filter { it.id != null }?.map { it.id!! }?.toIntArray()
+ poll.fullAccessGroups?.filter { it.id != null }?.map { it.id!! }?.toIntArray()
- var userList = fullAccessUser
+ val userList = fullAccessUser
User.restoreEmails(userList, userService)
return userList.mapNotNull { it.email }
@@ -124,7 +115,7 @@ class PollMailService {
fun getAllAttendesEmails(poll: Poll): List {
val attendees = poll.attendees
- var userList = attendees
+ val userList = attendees
User.restoreEmails(userList, userService)
return userList!!.mapNotNull { it.email }
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
index c08ef48307..0ed50a3cf3 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
@@ -88,9 +88,6 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
@Autowired
private lateinit var excelExport: ExcelExport
- @Autowired
- private lateinit var exporter: ExcelExport
-
@Autowired
private lateinit var pollResponseDao: PollResponseDao
@@ -215,7 +212,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
addDefaultParameterFields(dto, fieldset, isRunning = dto.state == PollDO.State.RUNNING)
- val rowWidth = UILength(xs = 12, sm = 12, md = 12, lg = 12)
+ UILength(xs = 12, sm = 12, md = 12, lg = 12)
val colWidth = UILength(xs = 12, sm = 12, md = 6, lg = 6)
fieldset
@@ -445,14 +442,13 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
@PutMapping("/finish")
fun changeStateToFinish(
- request: HttpServletRequest, obj: PollDO,
+ request: HttpServletRequest,
@RequestBody postData: PostData,
): ResponseEntity {
postData.data.state = PollDO.State.FINISHED
postData.data.deadline = LocalDate.now()
val responseEntity = super.saveOrUpdate(request, postData)
- var emailSent: Boolean = false
- var FUemailSent: Boolean = false
+ val fuemailSent = false
if (postData.data.state == PollDO.State.FINISHED) {
@@ -477,7 +473,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
}
}
- if (FUemailSent != true) {
+ if (fuemailSent != true) {
val owner = userService.getUser(postData.data.owner?.id)
val mailFrom = owner?.email.toString()
@@ -486,7 +482,6 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val mailContent = translateMsg("poll.mail.ended.fullAccess.content", postData.data.title, owner?.displayName)
pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent, listOf(mailAttachment))
- FUemailSent = true
}
val owner = userService.getUser(postData.data.owner?.id)
@@ -495,7 +490,6 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val mailSubject = translateMsg("poll.mail.ended.subject", postData.data.title)
val mailContent = translateMsg("poll.mail.ended.content", postData.data.title, owner?.displayName)
pollMailService.sendMail(mailFrom, mailTo, mailSubject, mailContent)
- emailSent = true
}
return responseEntity
}
@@ -626,7 +620,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
): ResponseEntity {
val dto = postData.data
- val type = dto.questionType?.let { BaseType.valueOf(it) } ?: BaseType.TextQuestion;
+ val type = dto.questionType?.let { BaseType.valueOf(it) } ?: BaseType.TextQuestion
val question = Question(uid = UUID.randomUUID().toString(), type = type)
if (type == BaseType.SingleResponseQuestion) {
question.answers = mutableListOf("", "")
@@ -687,7 +681,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
val dto = postData.data
val ptype = dto.prequestionType?.let { PreType.valueOf(it) } ?: PreType.Neujahrsfeier
- val question = PreQuestion(uid = UUID.randomUUID().toString(), pType = ptype)
+ PreQuestion(uid = UUID.randomUUID().toString(), pType = ptype)
if (ptype == PreType.Sommerfest) {
Sommerfest.entries.forEach { entry ->
dto.inputFields?.add(entry.value)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
index 35ef5a4ba1..87b15e930b 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollResponsePageRest.kt
@@ -192,7 +192,6 @@ class PollResponsePageRest : AbstractDynamicPageRest() {
)
}
- var index3 = 0
if (field.type == BaseType.MultiResponseQuestion || field.type === BaseType.SingleResponseQuestion) {
field.answers?.forEachIndexed { index2, _ ->
if (pollResponse.responses?.get(index)?.answers?.getOrNull(index2) == null) {
From 9261835d4ef69d03d09cb644c205ab3a523a7764 Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 29 May 2024 15:15:30 +0200
Subject: [PATCH 10/16] Excel Export fix
---
.../main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt | 1 -
1 file changed, 1 deletion(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index cc4059a1a2..d6c6330d50 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -228,7 +228,6 @@ class ExcelExport {
val pufferSplit: Array =
puffer.split("\r\n|\r|\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
- // check for line-breaks
for (i in pufferSplit.indices) {
counterOfBreaking++
counterOfOverlength += pufferSplit[i].length / 20
From 8381106bd6ed1cf3e99b1edd491d6643be8081de Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Mon, 3 Jun 2024 10:14:37 +0200
Subject: [PATCH 11/16] Test fail
---
.../main/resources/I18nResources.properties | 13 +++--
.../resources/I18nResources_de.properties | 10 +++-
.../rest/poll/excel/ExcelExport.kt | 48 +++++++++----------
3 files changed, 41 insertions(+), 30 deletions(-)
diff --git a/projectforge-business/src/main/resources/I18nResources.properties b/projectforge-business/src/main/resources/I18nResources.properties
index 6acc28ddee..4fa1f253f5 100644
--- a/projectforge-business/src/main/resources/I18nResources.properties
+++ b/projectforge-business/src/main/resources/I18nResources.properties
@@ -13,12 +13,15 @@ validation.error.range.integerOutOfRange=Value out of range {0}-{1}.
validation.error.range.integerToHigh=Value must not be higher than {0}.
validation.error.range.integerToLow=Value must not be lower than {0}.
validation.required.valueNotPresent=Value ''{0}'' not present.
+
# React UI
select.placeholder=Select...
table.showing=Showing
+
# own validations:
bicvalidator.wronglength=The field ''${label}'' must be 8 or 11 characters long.
ibanvalidator.wronglength.de=The field ''${label}'' starts with ''DE'', but a german IBAN must have 22 characters.
+
# Currency format
currencyConverter.percentage.help=You can enter amounts as well as percent values (e. g. 10%).
currencyFormat={0,number,,##0.00}
@@ -31,6 +34,7 @@ menu.projectDocumentation=Project docs
menu.sqlConsole=SQL console
menu.userGuide=Handbuch
message.notYetImplemented=Not yet implemented.
+
# Buttons:
add=Add
assign=Assign
@@ -93,6 +97,7 @@ updateAndNext=Update and next
upload=Upload
uptodate=up-to-date
wizard=Wizard
+
# Common
location=Location
no=No
@@ -1397,7 +1402,7 @@ history.was=was
hr.planning.description=Activity report
hr.planning.entry.copyFromPredecessor=Copy from predecessor
hr.planning.entry.error.entryDoesAlreadyExistForUserAndWeekOfYear=An entry with the same user and week of year does already exist.
-hr.planning.entry.error.noRightForProject=You don''t have permissions to create or edit entries for the project ''{0}''.
+hr.planning.entry.error.noRightForProject=You don''t have permissions to create or edit entries for the project ''{0}''.
hr.planning.entry.error.statusAndProjektNotAllowed=Status and project not allowed.
hr.planning.entry.error.statusOrProjektRequired=Status or project required.
hr.planning.entry.status.absence=absence
@@ -1828,7 +1833,7 @@ plugins.teamcal.event.changedby=Changed by
plugins.teamcal.event.convert2Timesheet=Convert to time-sheet
plugins.teamcal.event.decline=decline
plugins.teamcal.event.deletedby=Deleted by
-plugins.teamcal.event.duplicatedUidFromDifferentUser=An event from a another user with UID {0} already exists in calendar {1}.
+plugins.teamcal.event.duplicatedUidFromDifferentUser=An event from a another user with UID {0} already exists in calendar {1}.
plugins.teamcal.event.duration=Duration
plugins.teamcal.event.duration.error=Duration error. Please check start and end date.
plugins.teamcal.event.endDate=End
@@ -1991,7 +1996,7 @@ poll.confirmation.deleteButton=Yes
poll.confirmation.finish=Do you really want to finish this Poll?
poll.date=Date
poll.deadline=Deadline
-poll.delegationAnswers=Answers of
+poll.delegationAnswers=Answers of
poll.description=Description
poll.error.oneQuestionRequired=At least one question is required.
poll.exception.noAttendee=This user is not part of the poll.
@@ -2373,7 +2378,7 @@ timesheet.stopTime=Stop time
timesheet.tag=Tag
timesheet.taskReference=Reference of element
timesheet.templates=Templates
-timesheet.templates.migrationOfLegacy.button=Old templates
+timesheet.templates.migrationOfLegacy.button=Old templates
timesheet.templates.migrationOfLegacy.confirmationMessage=Do you want to import your old templates from the classical version now? Any existing entry will not be overwritten.
timesheet.templates.migrationOfLegacy.tooltip=Imports old templates of classical version.
timesheet.templates.new=New template
diff --git a/projectforge-business/src/main/resources/I18nResources_de.properties b/projectforge-business/src/main/resources/I18nResources_de.properties
index e687deafcd..0d66ae186a 100644
--- a/projectforge-business/src/main/resources/I18nResources_de.properties
+++ b/projectforge-business/src/main/resources/I18nResources_de.properties
@@ -90,6 +90,7 @@
# system.pluginAdmin.button.deactivate=Deactivate
# system.pluginAdmin.title=Plugins
# system.statistics.databasePool=Data base pool
+
# Wicket:
datatable.no-records-found=Keine Einträge gefunden.
NavigatorLabel=Zeile ${from} bis ${to} von ${of}.
@@ -105,12 +106,15 @@ validation.error.range.integerOutOfRange=Wert au
validation.error.range.integerToHigh=Wert darf nicht größer als {0} sein.
validation.error.range.integerToLow=Wert darf nicht kleiner als {0} sein.
validation.required.valueNotPresent=Wert ''{0}'' nicht gegeben.
+
# React UI
select.placeholder=Auswählen...
table.showing=Anzeige
+
# own validations:
bicvalidator.wronglength=Das Feld ''${label}'' muss 8 oder 11 Zeichen lang sein.
ibanvalidator.wronglength.de=Das Feld ''${label}'' beginnt mit ''DE''. Eine deutsche IBAN muss jedoch aus 22 Zeichen bestehen.
+
# Currency format
currencyConverter.percentage.help=Es können sowohl Beträge als auch Prozentzahlen (z. B. 10%) eingegeben werden.
currencyFormat={0,number,,##0.00}
@@ -188,6 +192,7 @@ wizard=Assistent
State.running=Laufend
poll.state.running
running=Laufend
+
# Common
akquise=Akquise
changes=Änderungen
@@ -2061,6 +2066,7 @@ plugins.teamcal.title.add=Kalender hinzuf
plugins.teamcal.title.edit=Team-Kalender bearbeiten
plugins.teamcal.title.heading=Kalender
plugins.teamcal.title.list=Kalenderliste
+
# poll plugin
poll=Umfrage
poll.access=Zugriff
@@ -2117,7 +2123,7 @@ poll.templateTypeNeujahrsfeier=Neujahrsfeier
poll.templateTypeSommerfest=Sommerfest
poll.templateTypeTeamessen=Teamessen
#Umfrage wurde erstellt
-poll.mail.created.subject=Sie wurden zu einer Umfrage eingeladen mit dem Titel "{0}" eingeladen.
+poll.mail.created.subject=Sie wurden zu einer Umfrage eingeladen mit dem Titel "{0}" eingeladen.
poll.mail.created.content=Liebe Teilnehmerinnen und Teilnehmer,
\
Wir möchten Ihnen mitteilen, dass eine Umfrage erstellt wurde mit dem Titel "{0}", und Sie wurden herzlichst eingeladen bei dieser Abzustimmen.
\
Hier kommst du direkt zur Umfrage
\
@@ -2185,7 +2191,7 @@ February=Februar
March=März
April=April
May=Mai
-June=Juni
+June=Juni
July=Juli
August=August
September=September
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
index d6c6330d50..f972fd3129 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/excel/ExcelExport.kt
@@ -188,38 +188,38 @@ class ExcelExport {
index = question.answers!!.size - 1
cell++
- if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
- if (index == ind && questionpossibilities != null) {
- excelSheet.autosize(cell)
- if (questionpossibilities.annotation != null && questionpossibilities.annotation!!.size != 0) {
- excelRow.getCell(cell).setCellValue(questionpossibilities.annotation?.get(0))
- }
+ if (question.type == BaseType.MultiResponseQuestion || question.type == BaseType.SingleResponseQuestion) {
+ if (index == ind && questionpossibilities != null) {
+ excelSheet.autosize(cell)
+ if (questionpossibilities.annotation != null && questionpossibilities.annotation!!.size != 0) {
+ excelRow.getCell(cell).setCellValue(questionpossibilities.annotation?.get(0))
}
}
+ }
- if (question.type == BaseType.MultiResponseQuestion) {
- questionpossibilities?.answers?.forEach {
- excelSheet.autosize(cell)
- if (questionpossibilities.answers?.get(ind)!!.equals(true) && ind != index) {
- excelRow.getCell(cell).setCellValue("X")
- }
- }
- } else if (question.type == BaseType.SingleResponseQuestion) {
+ if (question.type == BaseType.MultiResponseQuestion) {
+ questionpossibilities?.answers?.forEach {
excelSheet.autosize(cell)
- if (answer == questionpossibilities?.answers?.get(0) && ind != index) {
+ if (questionpossibilities.answers?.get(ind)!!.equals(true) && ind != index) {
excelRow.getCell(cell).setCellValue("X")
}
- } else {
- if (questionpossibilities?.answers?.isNotEmpty() == true) {
- excelSheet.autosize(cell)
- excelRow.getCell(cell).setCellValue(questionpossibilities.answers?.get(0).toString())
- if (countLines(answer) > countLines(largestAnswer)) {
- largestAnswer = answer
- }
+ }
+ } else if (question.type == BaseType.SingleResponseQuestion) {
+ excelSheet.autosize(cell)
+ if (answer == questionpossibilities?.answers?.get(0) && ind != index) {
+ excelRow.getCell(cell).setCellValue("X")
+ }
+ } else {
+ if (questionpossibilities?.answers?.isNotEmpty() == true) {
+ excelSheet.autosize(cell)
+ excelRow.getCell(cell).setCellValue(questionpossibilities.answers?.get(0).toString())
+ if (countLines(answer) > countLines(largestAnswer)) {
+ largestAnswer = answer
}
}
}
}
+ }
largestAnswer = "i"
val puffer: String = largestAnswer
@@ -228,6 +228,7 @@ class ExcelExport {
val pufferSplit: Array =
puffer.split("\r\n|\r|\n".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ // check for line-breaks
for (i in pufferSplit.indices) {
counterOfBreaking++
counterOfOverlength += pufferSplit[i].length / 20
@@ -261,5 +262,4 @@ class ExcelExport {
return byteArrayOutputStream.toByteArray()
}
}
-}
-
+}
\ No newline at end of file
From be5b9e48cc82b4129edc8d48eda1bb9433fd0f3a Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Tue, 4 Jun 2024 12:56:03 +0200
Subject: [PATCH 12/16] Test fail
---
.../plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt b/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt
index 11d5168650..1773efe6d4 100644
--- a/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt
+++ b/plugins/org.projectforge.plugins.datatransfer/src/main/kotlin/org/projectforge/plugins/datatransfer/rest/DataTransferPersonalBoxPageRest.kt
@@ -25,6 +25,7 @@ package org.projectforge.plugins.datatransfer.rest
import org.projectforge.business.user.UserGroupCache
import org.projectforge.business.user.service.UserPrefService
+import org.projectforge.framework.i18n.translate
import org.projectforge.framework.utils.NumberHelper
import org.projectforge.model.rest.RestPaths
import org.projectforge.plugins.datatransfer.DataTransferAreaDao
From 9346629037300f6220e0fb32a77eeb5f42885528 Mon Sep 17 00:00:00 2001
From: Nico <144223089+Nico0000000@users.noreply.github.com>
Date: Wed, 10 Jul 2024 08:24:46 +0200
Subject: [PATCH 13/16] Update CustomerPagesRest.kt
---
.../main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt
index bbccaf7806..b4ff3534ae 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/fibu/CustomerPagesRest.kt
@@ -31,6 +31,7 @@ import org.projectforge.rest.config.JacksonConfiguration
import org.projectforge.rest.config.Rest
import org.projectforge.rest.core.AbstractDTOPagesRest
import org.projectforge.rest.dto.Customer
+import org.projectforge.rest.dto.Konto
import org.projectforge.ui.*
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
From bd9bffc2b976e4d8382eefbfb06e15f680d969cb Mon Sep 17 00:00:00 2001
From: Nico <144223089+Nico0000000@users.noreply.github.com>
Date: Wed, 10 Jul 2024 08:25:21 +0200
Subject: [PATCH 14/16] Update AddressViewPageRest.kt
---
.../src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
index d70c48629c..c6040a2393 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/AddressViewPageRest.kt
@@ -293,6 +293,7 @@ class AddressViewPageRest : AbstractDynamicPageRest() {
.add(UICol(6).add(UICustomized("email", mutableMapOf("data" to EMail(email)))))
)
}
+
private fun createAddressCol(
row: UIRow,
numberOfAddresses: Int,
From 35ec1811f42b89d1438eaa480141d5d2fa47b7c1 Mon Sep 17 00:00:00 2001
From: Nico <144223089+Nico0000000@users.noreply.github.com>
Date: Wed, 10 Jul 2024 08:25:59 +0200
Subject: [PATCH 15/16] Update AddressViewPageRest.kt
From 27b563362b2feafc7c216fa2823bd8108e2a01be Mon Sep 17 00:00:00 2001
From: Nico Sinkin
Date: Wed, 31 Jul 2024 13:51:26 +0200
Subject: [PATCH 16/16] Email new Line Fixed
---
.../main/kotlin/org/projectforge/rest/poll/PollPageRest.kt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
index 0ed50a3cf3..ba17ed06a1 100644
--- a/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
+++ b/projectforge-rest/src/main/kotlin/org/projectforge/rest/poll/PollPageRest.kt
@@ -387,7 +387,7 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
"{1}"
dto.customemailcontent = content
- val subject = "Sie wurden zu einer Umfrage eingeladen mit dem Titel \"{0}\" eingeladen."
+ val subject = "Sie wurden zu einer Umfrage eingeladen mit dem Titel '{0}' eingeladen."
dto.customemailsubject = subject
addQuestionFieldset(layout, dto, fieldset)
@@ -503,6 +503,8 @@ class PollPageRest : AbstractDTOPagesRest(PollDao::class.
throw AccessException("poll.error.oneAttendeRequired")
}
+ postData.data.customemailcontent = postData.data.customemailcontent?.replace("\n", "
")
+
super.onBeforeSaveOrUpdate(request, obj,postData)
}