diff --git a/PO/POTFILES b/PO/POTFILES index e2894a8..f1229f0 100644 --- a/PO/POTFILES +++ b/PO/POTFILES @@ -1,4 +1,16 @@ +../src/Constants/const.php ../src/Controller/MainController.php ../src/Controller/SecurityController.php ../src/Controller/SetupController.php +../src/Controller/WebrootController.php +../src/Controller/WebrootSetupController.php +../src/Entity/WebrootFile.php +../src/Entity/WebrootFilePermission.php +../src/Entity/WebrootRole.php +../src/Entity/WebrootUser.php ../src/Kernel.php +../src/Repository/WebrootFilePermissionRepository.php +../src/Repository/WebrootFileRepository.php +../src/Repository/WebrootRoleRepository.php +../src/Repository/WebrootUserRepository.php +../src/Utility/i18n.php diff --git a/PO/compilemessages b/PO/compilemessages index 4766057..54f499d 100644 --- a/PO/compilemessages +++ b/PO/compilemessages @@ -13,10 +13,7 @@ for i in `cat LINGUAS`; do fi if [ -f $i.po ]; then - msgfmt -o "$msgdir/messages.mo" $i.po - fi - if [ -f webroot/$i.po ]; then - msgfmt -o "$msgdir/mydevel.webroot.mo" "webroot/$i.po" + msgfmt -o "$msgdir/mydevel-webroot.mo" $i.po fi done diff --git a/PO/de.po b/PO/de.po index 4ee1245..e8a5ee7 100644 --- a/PO/de.po +++ b/PO/de.po @@ -6,13 +6,146 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-26 20:44+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" +"POT-Creation-Date: 2024-11-27 19:03+0100\n" +"PO-Revision-Date: 2024-11-27 19:12+0100\n" +"Last-Translator: Christian Moser \n" +"Language-Team: \n" +"Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.5\n" + +#: ../src/Controller/SetupController.php:45 +msgid "Email Settings" +msgstr "Email Einstellungen" + +#: ../src/Controller/SetupController.php:46 +msgid "Site Settings" +msgstr "Site Einstellungen" + +#: ../src/Controller/SetupController.php:47 +msgid "Database Settings" +msgstr "Datenbank Einstellungen" + +#: ../src/Controller/SetupController.php:48 +msgid "User Settings" +msgstr "Nutzer Einstellungen" + +#: ../src/Controller/SetupController.php:56 +msgid "Enter the site name that should be displayed in titles." +msgstr "Gib den Setiennamen and, der in Titeln angezeigt werden soll." + +#: ../src/Controller/SetupController.php:57 +msgid "Site name" +msgstr "Name der Site" + +#: ../src/Controller/SetupController.php:61 +msgid "Site root directory" +msgstr "Wurzelverzeichnis" + +#: ../src/Controller/SetupController.php:65 +msgid "Contact email" +msgstr "Kontakt Email" + +#: ../src/Controller/SetupController.php:69 +msgid "Username" +msgstr "Nutzername" + +#: ../src/Controller/SetupController.php:73 +msgid "Email" +msgstr "Email" + +#: ../src/Controller/SetupController.php:77 +#: ../src/Controller/SetupController.php:117 +#: ../src/Controller/SetupController.php:144 +msgid "Password" +msgstr "Passwort" + +#: ../src/Controller/SetupController.php:81 +msgid "Confirm Password" +msgstr "Passwort bestätigen" + +#: ../src/Controller/SetupController.php:84 +msgid "Run Migrations?" +msgstr "Migrationen anwenden?" + +#: ../src/Controller/SetupController.php:93 +msgid "SQLite3" +msgstr "SQLite3" + +#: ../src/Controller/SetupController.php:94 +msgid "MySQL/MariaDB" +msgstr "MySQL/MariaDB" + +#: ../src/Controller/SetupController.php:95 +msgid "PostgreSQL" +msgstr "PostgreSQL" + +#: ../src/Controller/SetupController.php:96 +#: ../src/Controller/SetupController.php:120 +msgid "Database URL" +msgstr "Datenbank URL" + +#: ../src/Controller/SetupController.php:101 +msgid "Database" +msgstr "Datenbank" + +#: ../src/Controller/SetupController.php:105 +msgid "Host" +msgstr "Host" + +#: ../src/Controller/SetupController.php:109 +msgid "Port" +msgstr "Port" + +#: ../src/Controller/SetupController.php:113 +#: ../src/Controller/SetupController.php:140 +msgid "User" +msgstr "Nutzer" + +#: ../src/Controller/SetupController.php:124 +msgid "Backend" +msgstr "Backend" + +#: ../src/Controller/SetupController.php:127 +msgid "No email support" +msgstr "Keine Emailunterstützung" + +#: ../src/Controller/SetupController.php:128 +msgid "SMTP" +msgstr "SMTP" + +#: ../src/Controller/SetupController.php:129 +msgid "Sendmail" +msgstr "Sendmail" + +#: ../src/Controller/SetupController.php:130 +msgid "Naitve" +msgstr "Nativ" + +#: ../src/Controller/SetupController.php:131 +msgid "User DSN" +msgstr "Nutzer DSN" + +#: ../src/Controller/SetupController.php:136 +msgid "Email Path" +msgstr "Email-Pfad" + +#: ../src/Controller/SetupController.php:148 +msgid "SMTP Host" +msgstr "SMTP Host" + +#: ../src/Controller/SetupController.php:152 +msgid "SMTP Port" +msgstr "SMTP Port" + +#: ../src/Controller/SetupController.php:156 +msgid "DSN" +msgstr "DSN" + +#: ../src/Controller/SetupController.php:160 +msgid "Sender address" +msgstr "Adresse des Senders" diff --git a/PO/makemessages b/PO/makemessages new file mode 100644 index 0000000..c036930 --- /dev/null +++ b/PO/makemessages @@ -0,0 +1,35 @@ +#!/bin/sh + +SELF="$(realpath "$0")" +PODIR="$(dirname "$SELF")" +PROJECT_ROOT="$(dirname "$PODIR")" + +cd "$PODIR" + +echo "Creating POTFILES" +rm -v POTFILES + +for i in $(find ../src | grep '\.*php$'); do + echo $i >> POTFILES +done +if [ -f messages.pot ]; then + JOIN="--join-existing" +else + JOIN="" +fi +echo "extracting messages" + +xgettext -f POTFILES -d mydevel.webroot -L PHP $JOIN --force-po -o messages.pot +if [ -z "$JOIN" ]; then + sed -i s/charset=CHARSET/charset=UTF-8/g messages.pot +fi + +for i in `cat LINGUAS`; do + if [ ! -f $i.po ]; then + cp messages.pot $i.po + else + msgmerge $i.po messages.pot + fi +done + + diff --git a/PO/messages.pot b/PO/messages.pot index 4ee1245..c5fc16e 100644 --- a/PO/messages.pot +++ b/PO/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-26 20:44+0100\n" +"POT-Creation-Date: 2024-11-27 19:03+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,3 +16,135 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" + +#: ../src/Controller/SetupController.php:45 +msgid "Email Settings" +msgstr "" + +#: ../src/Controller/SetupController.php:46 +msgid "Site Settings" +msgstr "" + +#: ../src/Controller/SetupController.php:47 +msgid "Database Settings" +msgstr "" + +#: ../src/Controller/SetupController.php:48 +msgid "User Settings" +msgstr "" + +#: ../src/Controller/SetupController.php:56 +msgid "Enter the site name that should be displayed in titles." +msgstr "" + +#: ../src/Controller/SetupController.php:57 +msgid "Site name" +msgstr "" + +#: ../src/Controller/SetupController.php:61 +msgid "Site root directory" +msgstr "" + +#: ../src/Controller/SetupController.php:65 +msgid "Contact email" +msgstr "" + +#: ../src/Controller/SetupController.php:69 +msgid "Username" +msgstr "" + +#: ../src/Controller/SetupController.php:73 +msgid "Email" +msgstr "" + +#: ../src/Controller/SetupController.php:77 +#: ../src/Controller/SetupController.php:117 +#: ../src/Controller/SetupController.php:144 +msgid "Password" +msgstr "" + +#: ../src/Controller/SetupController.php:81 +msgid "Confirm Password" +msgstr "" + +#: ../src/Controller/SetupController.php:84 +msgid "Run Migrations?" +msgstr "" + +#: ../src/Controller/SetupController.php:93 +msgid "SQLite3" +msgstr "" + +#: ../src/Controller/SetupController.php:94 +msgid "MySQL/MariaDB" +msgstr "" + +#: ../src/Controller/SetupController.php:95 +msgid "PostgreSQL" +msgstr "" + +#: ../src/Controller/SetupController.php:96 +#: ../src/Controller/SetupController.php:120 +msgid "Database URL" +msgstr "" + +#: ../src/Controller/SetupController.php:101 +msgid "Database" +msgstr "" + +#: ../src/Controller/SetupController.php:105 +msgid "Host" +msgstr "" + +#: ../src/Controller/SetupController.php:109 +msgid "Port" +msgstr "" + +#: ../src/Controller/SetupController.php:113 +#: ../src/Controller/SetupController.php:140 +msgid "User" +msgstr "" + +#: ../src/Controller/SetupController.php:124 +msgid "Backend" +msgstr "" + +#: ../src/Controller/SetupController.php:127 +msgid "No email support" +msgstr "" + +#: ../src/Controller/SetupController.php:128 +msgid "SMTP" +msgstr "" + +#: ../src/Controller/SetupController.php:129 +msgid "Sendmail" +msgstr "" + +#: ../src/Controller/SetupController.php:130 +msgid "Naitve" +msgstr "" + +#: ../src/Controller/SetupController.php:131 +msgid "User DSN" +msgstr "" + +#: ../src/Controller/SetupController.php:136 +msgid "Email Path" +msgstr "" + +#: ../src/Controller/SetupController.php:148 +msgid "SMTP Host" +msgstr "" + +#: ../src/Controller/SetupController.php:152 +msgid "SMTP Port" +msgstr "" + +#: ../src/Controller/SetupController.php:156 +msgid "DSN" +msgstr "" + +#: ../src/Controller/SetupController.php:160 +msgid "Sender address" +msgstr "" diff --git a/PO/mkpotfiles.sh b/PO/mkpotfiles.sh deleted file mode 100644 index 738b6f3..0000000 --- a/PO/mkpotfiles.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/sh - -SELF="$(realpath "$0")" -PODIR="$(dirname "$SELF")" -PROJECT_ROOT="$(dirname "$PODIR")" - -cd "$PODIR" - -echo "Creating POTFILES" -rm -v POTFILES - -for i in $(find ../src | grep '\.php' | grep -v '\.\./src/MyDevel'); do - echo $i >> POTFILES -done -if [ -f messages.pot ]; then - JOIN="--join-existing" -else - JOIN="" -fi -echo "extracting messages" - -xgettext -f POTFILES -d messages -L PHP $JOIN --force-po -o messages.pot -if [ -z "$JOIN" ]; then - sed -i s/charset=CHARSET/charset=UTF-8/g messages.pot -fi - -for i in `cat LINGUAS`; do - if [ ! -f $i.po ]; then - cp messages.pot $i.po - else - msgmerge $i.po messages.pot - fi -done - -echo "Creating POTFILES.webroot" -rm -v POTFILES.webroot -for i in $(find ../src/MyDevel/Webroot | grep '\.php'); do - echo $i >> POTFILES.webroot -done - -if [ ! -d webroot ]; then - mkdir -v webroot -fi - -if [ -f webroot/messages.pot ]; then - JOIN="--join-existing" -else - JOIN="" -fi -xgettext -d mydevel.webroot -f POTFILES.webroot -L PHP $JOIN --force-po -o webroot/messages.pot -if [ -z "$JOIN" ]; then - sed -i s/charset=CHARSET/charset=UTF-8/g webroot/messages.pot -fi -for i in `cat LINGUAS`; do - if [ ! -f webroot/$i.po ]; then - cp webroot/messages.pot webroot/$i.po - else - msgmerge webroot/$i.po webroot/messages.pot - fi -done - diff --git a/assets/styles/app.css b/assets/styles/app.css index 1d84a8d..ad8375f 100644 --- a/assets/styles/app.css +++ b/assets/styles/app.css @@ -274,3 +274,19 @@ code { background-color: var(--color-background); color: var(--color-text); } + +.shrink-to-fit { + width:0.1%; + white-space:nowrap; +} + +.standard-background { + background-color: var(--color-background); +} + +fieldset { + border: 2px var(--color-text) solid; + border-radius: 4px; + margin-top: 5px; + margin-bottom: 5px; +} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..0b4096f --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,2 @@ +framework: + default_locale: de diff --git a/config/packages/translation.yaml b/config/packages/translation.yaml index b3f8f9c..a1d4d3e 100644 --- a/config/packages/translation.yaml +++ b/config/packages/translation.yaml @@ -1,7 +1,13 @@ framework: - default_locale: en + default_locale: de translator: default_path: '%kernel.project_dir%/translations' fallbacks: - en providers: + mo: + dsn: '%kernel.project_dir%/translations' + locales: [de] + domains: [mydevel_webroot,messages] + + diff --git a/config/services.yaml b/config/services.yaml index b66817b..c675c86 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -29,7 +29,15 @@ services: tags: ['controller.service_arguments'] - + translation.loader.po: + class: Symfony\Component\Translation\Loader\PoFileLoader + tags: + - { name: translation.loader, alias: po } + tranlation.loader.mo: + class: Symfony\Component\Translation\Loader\MoFileLoader + tags: + - { name: translation.loader, alias: mo } + # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones diff --git a/migrations/Version20241126213642.php b/migrations/Version20241127204952.php similarity index 98% rename from migrations/Version20241126213642.php rename to migrations/Version20241127204952.php index 08ebc8d..918a4b2 100644 --- a/migrations/Version20241126213642.php +++ b/migrations/Version20241127204952.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20241126213642 extends AbstractMigration +final class Version20241127204952 extends AbstractMigration { public function getDescription(): string { diff --git a/scripts/run_dispatched b/scripts/run_dispatched new file mode 100644 index 0000000..18f68d9 --- /dev/null +++ b/scripts/run_dispatched @@ -0,0 +1,41 @@ +#!/bin/sh +# vim: syn=sh ts=4 sts=4 sw=4 ff=unix smartindent expandtab + + +#set default script interval to 5 minutes +: ${SCRIPT_INTERVAL:=300} +: ${TASK_SLEEP_TIME:=2} +: ${TASK_DIR:=${HOME}/.tasks} +: ${TASK_WAITING_DIR:=${TASK_DIR}/waiting} +: ${TASK_RUNNING_DIR:=${TASK_DIR}/running} + +$start=`time +%s` +$end=$(( $start + $SCRIPT_INTERVAL )) + +if [ ! -d "$TASK_DIR" ]; then + mkdir -p "$TASK_DIR" +fi +if [ ! -d "$TASK_WAITING_DIR" ]; then + mkdir -p "$TASK_WAITING_DIR" +fi +if [ ! -d "$TASK_RUNNING_DIR" ]; then + mkdir -p "$TASK_RUNNING_DIR" +if + +run_task() { + task="$1" + $task + rm $task +} + +while [ `time +%s` -lt $end ]; do + for waiting in `ls ${TASK_WAITING_DIR}`; do + if [ -x $waiting ]; then + task=${TASK_RUNNING_DIR}/`basename $waiting` + mv $waiting $task + run_task "$task" & + fi + done + sleep $TASK_SLEEP_TIME +done + diff --git a/src/Constants/const.php b/src/Constants/const.php new file mode 100644 index 0000000..16122ca --- /dev/null +++ b/src/Constants/const.php @@ -0,0 +1,3 @@ +getProjectDir(),".env"]); $dotenvlocal_file = join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),".env.local"]); $errors = array(); @@ -30,93 +35,40 @@ class SetupController extends WebrootSetupController fclose($file); } - $form = $this->createFormBuilder() - ->add('language',FormType\TextType::class,) - ->add('site_name',FormType\TextType::class,[ - "mapped"=>false, - "label" => "Site name"]) - ->add('site_rootdir',FormType\TextType::class,[ - "mapped"=>false, - "label" => "Site Root Directory"]) - ->add('site_email',FormType\EmailType::class,[ - "mapped"=>false, - "label" => "Contact email"]) - ->add('user_username',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"Username"]) - ->add('user_email',FormType\EmailType::class,[ - "mapped"=>false, - "label"=> "Email address"]) - ->add("user_password0", FormType\PasswordType::class,[ - "mapped"=>false, - "label"=>"Password"]) - ->add("user_password1",FormType\PasswordType::class,[ - "mapped"=>false, - "label"=>"Confirm Password"]) - ->add('db_backend',FormType\ChoiceType::class,[ - "mapped" => false, - "label" => "Database Backend", - "choices" => [ - "sqlite" => "SQLite3", - "mysql" => "MySQL/MariaDB", - "postgresql" => "PostgreSQL", - ]]) - ->add('db_database',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"Database"]) - ->add('db_host', FormType\TextType::class,[ - "mapped"=>false, - "label"=>"Host"]) - ->add('db_port', FormType\IntegerType::class,[ - "mapped"=>false, - "label"=>"Port"]) - ->add('db_user',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"User"]) - ->add('db_password',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"Password"]) - ->add('email_backend', FormType\ChoiceType::class, [ - "mapped"=>false, - "label" => "Email Backend", - "choices"=> [ - "none", "None", - "smtp", "SMTP", - "sendmail","Sendmail", - "native","Naitve", - ]]) - ->add('email_path',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"Email Path"]) - ->add('email_user',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"User"]) - ->add('email_password', FormType\PasswordType::class,[ - "mapped"=>false, - "label"=> "Password"]) - ->add('email_host',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"SMTP Host"]) - ->add('email_port',FormType\TextType::class,[ - "mapped"=>false, - "label"=>"SMTP Port"]) - ->add('email_address', FormType\EmailType::class,[ - "mapped"=>false, - "label"=>"Sender address"]) - ->add('submit', FormType\SubmitType::class) - ->getForm(); + $command_output=['migration'=>"",'migrate'=>""]; + $have_migration_output=false; + + $translations=[ + 'email'=>_("Email Settings"), + 'site' => _("Site Settings"), + 'db' => _("Database Settings"), + 'user' => _("User Settings"), + ]; + + $form = $this->createSetupForm(); + $this->setSetupFormDefaultsFromEnv($form); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $password0 = $form.get('user_password0')->getData(); - $password1 = $form.get('user_password1')->get_data(); - $errors[] = "Passwords dont match"; + $password0 = $form->get('user_password0')->getData(); + $password1 = $form->get('user_password1')->getData(); + if (strlen($password0) < 8) { + array_push($errors,"Password does not have the minimal length of 8 characters!"); + } + if (strcmp($password0,$password1)) { + array_push($errors,"Passwords dont match!"); + } //if passwords don't match rerender form. - return $this->render("setup/initial-setup.html.twig",[ - "error" => $errors, - "form" => $form]); + if (count($errors) > 0) { + return $this->render("setup/initial-setup.html.twig",[ + "errors" => $errors, + "form" => $form, + "translations" => $translations, + "have_migration_output"=>false, + "command_output"=>$command_output]); + } $dotevnlocal = join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),'.env.local']); @@ -126,20 +78,21 @@ class SetupController extends WebrootSetupController if ($language || strlen($language) > 1) { fwrite($file,"LANG=\"" . $language . "\"\n"); } + fwrite($file,"APP_LOCALEDIR=\"%kernel.project_dir%/Translations\""); fwrite($file,"SITE_NAME=\"" . $form->get("site_name")->getNormData() . "\"\n"); fwrite($file,"SITE_EMAIL=\"". $form->get('site_email')->getNormData() . "\"\n"); $db_backend=$form->get('db_backend')->getNormData(); if ($db_backend === "sqlite") { - fwrite("DATABASE_URL=\"sqlite://" . $form.get('db_database') . "\"\n"); + fwrite($file,"DATABASE_URL=\"sqlite://" . $form->get('db_database')->getNormData() . "\"\n"); } elseif ($db_backend === "mysql") { fwrite("DATABASE_URL=\"msysql://" . urlencode($form.get('db_user')->getNormData()) - . ":" . urlencode($form.get('db_password')->getNormData()) - . "@" . urlencode($form.get('db_host')->getNormData()) + . ":" . urlencode($form->get('db_password')->getNormData()) + . "@" . urlencode($form->get('db_host')->getNormData()) . ":" . $form.get('db_port')->getNormData() - . "/" . urlencode($form.get('db_database')->getNormData()) + . "/" . urlencode($form->get('db_database')->getNormData()) . "?charset=utf8mb4\"\n"); } elseif ($db_backend === "postgresql") { fwrite("DATABASE_URL=\"postgresql://" @@ -147,22 +100,30 @@ class SetupController extends WebrootSetupController . ":" . urlencode($form->get('db_password')->getNormData()) . "@" . urlencode($form->get('db_host')->getNormData()) . ":" . $form->get('db_port')->getNormData() - . "/" . urlencode($form.get('db_database')->getNormData()) + . "/" . urlencode($form->get('db_database')->getNormData()) . "?charset=utf8"); } fclose($file); (new Dotenv())->loadEnv(join(DIRECTORY_SEPARATOR,[$this->getProjectDir(),".env"])); try { - $migration_message = $this->runMakeMigration(); - $migrate_message = $this->runMigrate(); + $have_migration_output=true; + + $command_output["migration"] = $this->runMakeMigration(); + $create_database = $form->get('db_create')->getNormData(); + if ($create_database) { + $command_output["create_database"] = $this->runCreateDatabase(); + } + + $command_output["migrate"] = $this->runMigrate(); $user = new WebrootUser(); $user->setAdmin(true); $user->setUsername($form->get('user_username')->getNormData()); $user->setRoles(["ROLE_SUPERADMIN","ROLE_ADMIN","ROLE_USER"]); $user->setEmail($form->get("user_email")->getNormData()); - $user->set_password($passwd_hasher->hashPassword($user, $password0)); + $user->setPassword($passwd_hasher->hashPassword($user, $password0)); $em->persist($user); + $em->flush(); foreach($this->getInitialRoles() as $roledata) { $role = new WebrootRole(); @@ -171,19 +132,46 @@ class SetupController extends WebrootSetupController $role->setDescription($roledata["description"]); $em->persist($role); } + $em->flush(); + + $rootdir = $form->get("site_rootdir")->getNormData(); + $db_rootdir = new WebrootFile(); + $db_rootdir->setUrl("/weboot"); + $db_rootdir->setPath($rootdir); + $db_rootdir->setDescription($webroot); + $em->persist($db_rootdir); + $em->flush(); + + $db_file_repos = $em->getRespository(WebrootFile::class); + $db_role_repos = $em->getRepository(WebroorRole::class); + + $role = findByRoleName("ROLE_SUPERADMIN"); + $perm = new App\Entity\WebrootFilePermission(); + $perm->setWebrootFile($db_rootdir); + $perm->setReadable(true); + $perm->setWriteable(true); + $perm->setDeleteable(true); + $perm->setRole($role); + + $rm->persist($perm); + $rm->flush(); + return redirectToRoute("app_login"); } catch (\Exception $ex) { + array_push($errors,$ex->getMessage()); unlink($dotevnlocal); - $errors[] = $ex->getMessage(); + throw $ex; } finally { - } - + } } return $this->render('setup/initial-setup.html.twig', [ "form" => $form, - "errors" => $errors + "errors" => $errors, + "translations" => $translations, + "have_migration_output"=>true, + "command_output"=>$command_output, ]); } @@ -204,7 +192,6 @@ class SetupController extends WebrootSetupController ]); } - #[Route('/setup/login',name:'webroot.setup.login')] public function login() { diff --git a/src/Controller/WebrootSetupController.php b/src/Controller/WebrootSetupController.php index 242c595..264e697 100644 --- a/src/Controller/WebrootSetupController.php +++ b/src/Controller/WebrootSetupController.php @@ -6,15 +6,19 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Form\Form; +use Symfony\Component\Form\Extension\Core\Type as FormType; +use Symfony\Component\Yaml\Yaml; - -use MyDevel\Webroot\Entity\WebrootUser; +use App\Utility; +use App\Entity\WebrootUser; abstract class WebrootSetupController extends AbstractController { @@ -24,11 +28,18 @@ abstract class WebrootSetupController extends AbstractController */ private ?KernelInterface $kernel = null; private ?string $project_dir = null; + private ?UserPasswordHasherInterface $password_hasher; - public function __construct(KernelInterface $kernel) { + public function __construct(KernelInterface $kernel, UserPasswordHasherInterface $password_hasher) { $this->kernel = $kernel; $this->project_dir = $kernel->getProjectDir(); + $this->password_hasher = $password_hasher; + Utility\gettext_lib_init( + WEBROOT_GETTEXT_DOMAIN, + join(DIRECTORY_SEPARATOR,[$this->project_dir,"translations"]), + getenv("LANG")); + } /** @@ -97,6 +108,7 @@ abstract class WebrootSetupController extends AbstractController "command" => "make:migration", "--formatted" => true, "--no-interaction" => true, + "--quiet" => true, ]); $output = new BufferedOutput(); @@ -106,7 +118,29 @@ abstract class WebrootSetupController extends AbstractController $content=$output->fetch(); if ($errc) { - throw new \Exception("make:migration failed!"); + throw new \Exception("make:migration failed!\n" . $content); + } + + return $content; + } + + protected function runCreateDatabase(): string + { + $application = new Application($this->kernel); + $application->setAutoExit(false); + + $input = new ArrayInput([ + "command" => "doctrine:database:create", + "--no-interaction" => true, + "--quiet" => true, + ]); + + $output = new BufferedOutput(); + $errc = $application->run($input,$output); + + $content = $output->fetch(); + if ($errc) { + throw new \Exception("doctrine:database:create failed!\n". $content); } return $content; @@ -122,13 +156,15 @@ abstract class WebrootSetupController extends AbstractController $application->setAutoExit(false); $input = new ArrayInput([ - "command" => "doctrine:migrations:migrate", - "--no-interaction" => true, + "command" => "doctrine:migration:migrate", + "--no-interaction" => true, + "--quiet" => true, ]); + $output = new BufferedOutput(); - $ercode = $application->run($input,$output); + $errcode = $application->run($input,$output); if ($errcode) { - throw new \Excpetion("runMigrate failed!"); + throw new \Exception("runMigrate failed!\n". $output->fetch()); } $content = $output->fetch(); @@ -145,4 +181,387 @@ abstract class WebrootSetupController extends AbstractController ["role"=>"ROLE_PUBLIC","name"=>"Public Access","description"=>"Role for public access."], ]; } + + public function createSetupForm(): Form + { + return $this->createFormBuilder() + ->add('env', FormType\ChoiceType::class,[ + "label"=>"Environment", + "mapped"=>false, + "required"=>true, + "choices"=>[ + "Production" => "prod", + "Development" => "dev" + ], + "data" => "prod"]) + ->add('locale',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false]) + ->add('tempdir',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false]) + ->add('site_name',FormType\TextType::class,[ + "mapped"=>false, + "required"=>true, + "help"=>_("Enter the site name that should be displayed in titles."), + "label" => _("Site name")]) + ->add('site_rootdir',FormType\TextType::class,[ + "mapped"=>false, + "required"=>true, + "label" => _("Site root directory")]) + ->add('site_email',FormType\EmailType::class,[ + "mapped"=>false, + "required"=>false, + "label" => _("Contact email")]) + ->add('user_username',FormType\TextType::class,[ + "mapped"=>false, + "required"=>true, + "label"=>_("Username")]) + ->add('user_email',FormType\EmailType::class,[ + "mapped"=>false, + "required"=>true, + "label"=> _("Email")]) + ->add("user_password0", FormType\PasswordType::class,[ + "mapped"=>false, + "required"=>true, + "label"=>_("Password")]) + ->add("user_password1",FormType\PasswordType::class,[ + "mapped"=>false, + "required"=>true, + "label"=>"Confirm Password"]) + ->add('db_migrate', FormType\CheckboxType::class,[ + "mapped"=>false, + "label"=>"Run Migrations?", + "attr"=>["checked"=>true], + "required"=>false]) + ->add('db_create', FormType\CheckboxType::class,[ + "mapped"=>false, + "label"=>"Create Database", + "required"=>false, + "attr"=>["checked"=>false]]) + ->add('db_backend',FormType\ChoiceType::class,[ + "mapped" => false, + "label" => "Backend", + "required" => true, + "choices" => [ + _("SQLite3")=>"sqlite", + _("MySQL/MariaDB")=>"mysql", + _("PostgreSQL")=>"postgresql", + _("Database URL")=>"url", + ]]) + ->add('db_database',FormType\TextType::class,[ + "mapped"=>false, + "required"=>true, + "label"=>_("Database")]) + ->add('db_host', FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("Host")]) + ->add('db_port', FormType\IntegerType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("Port")]) + ->add('db_user',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("User")]) + ->add('db_password',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("Password")]) + ->add('db_url',FormType\TextType::class,[ + "mapped"=>false, + "label"=>_("Database URL"), + "required"=>false]) + ->add('email_backend', FormType\ChoiceType::class, [ + "mapped"=>false, + "label" => _("Backend"), + "required"=>true, + "choices"=> [ + _("No email support")=>"none", + _("SMTP")=>"smtp", + _("Sendmail")=>"sendmail", + _("Naitve")=>"native", + _("User DSN")=>"dsn", + ]]) + ->add('email_path',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("Email Path")]) + ->add('email_user',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("User")]) + ->add('email_password', FormType\PasswordType::class,[ + "mapped"=>false, + "required"=>false, + "label"=> _("Password")]) + ->add('email_host',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("SMTP Host")]) + ->add('email_port',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("SMTP Port")]) + ->add('email_dsn',FormType\TextType::class,[ + "mapped"=>false, + "required"=>false, + "label"=>_("DSN")]) + ->add('email_address', FormType\EmailType::class,[ + "mapped"=>false, + "required"=>true, + "label"=>_("Sender address")]) + ->add('submit', FormType\SubmitType::class) + ->getForm(); + } + + public function setSetupFormFromData(Form $form,array $values) + { + if (array_key_exists("locale",$values)) { + $form->get("locale")->setData($values["locale"]); + } + if (array_key_exists("tempdir",$values)) { + $form->get("locale")->setData($values["tempdir"]); + } + if (array_key_exists("site", $values)) { + $site=$values["site"]; + if (array_key_exists("name", $site)) { + $form->get("site_name")->setData($site["name"]); + } + if (array_key_exists("email",$site)) { + $form->get("site_email")->setData($site["email"]); + } + } + if (array_key_exists("database",$values)) { + $db = $values["database"]; + if (array_key_exists("backend",$values)) { + $form->get("db_backend")->setData($db["backend"]); + } + if (array_key_exists("database", $db)) { + $form->get("db_database")->setData($db["database"]); + } + if (array_key_exists("host", $db)) { + $form->get("db_host")->setData($db["host"]); + } + if (array_key_exists("port",$db)) { + $form->get("db_host")->setData($db["port"]); + } + if (array_key_exists("user",$db)) { + $form->get("db_user")->setData($db["user"]); + } + if (array_key_exists("password", $db["password"])) { + $form->get("db_password")->setData($db["password"]); + } + if (array_key_exists("url",$db)) { + $form->get("db_url")->setData($db["url"]); + } + } + if (array_key_exists("user", $values)) { + $user = $values["user"]; + if (array_key_exists("username", $user)) { + $form->get("user_username")->setData($user["username"]); + } + if (array_key_exists("email",$user)) { + $form->get("user_email")->setData($user["email"]); + } + } + if (array_key_exists("email", $values)) { + $email = $values["email"]; + if (array_key_exists("backend",$email)) { + $form->get("email_backend")->setData($email["backend"]); + } + if (array_key_exists("path",$email)) { + $form->get("email_path")->setData($email["path"]); + } + if (array_key_exists("user", $email)) { + $form->get("email_user")->setData($email["user"]); + } + if (array_key_exists("password", $email["password"])) { + $form->get("email_password")->setData($email["password"]); + } + if (array_key_exists("host",$email)) { + $form->get("email_host")->setData($email["host"]); + } + if (array_key_exists("port", $email)) { + $form->get("email_port")->setData($email["port"]); + } + if (array_key_exists("dsn", $email)) { + $form->get("email_dsn")->setData($email["dsn"]); + } + if (array_key_exists("address", $email)) { + $form->get("email_address")->setData($email["address"]); + } + } + } + + public function setSetupFormDefaultsFromEnv(Form $form) + { + if (getenv("LOCALE") && strlen(getenv("LOCALE"))) { + $form->get('locale')->setData(getenv("LOCALE")); + } elseif (getenv("LANG") && strlen(getenv("LANG"))) { + $form->get('locale')->setData(getenv("LANG")); + } + if (getenv("WEBROOT_TEMP") && strlen(getenv("WEBROOT_TEMP"))) { + $form->get('tempdir')->setData(getenv("WEBROOT_TEMP")); + } elseif (getenv("TMP") && strlen(getenv("TMP"))) { + $form->get('tempdir')->setData(join(DIRECTORY_SEPARATOR,[getenv("TMP"),"webroot"])); + } elseif (getenv('TEMP') && strlen(getenv("TEMP"))) { + $form->get("tempdir")->setData(join(DIRECTORY_SEPARATOR,[getenv("TEMP"),"webroot"])); + } else { + $form->get("tempdir")->setData(join(DIRECTORY_SEPARATOR,[$this->project_dir,"temp"])); + } + if (getenv("CONTACT_EMAIL") && strlen(getenv("CONTACT_EMAIL"))) { + form->get('site_email')->setData(getenv("CONTACT_EMAIL")); + } + if (getenv("SITE_NAME") && strlen(getenv("SITE_NAME"))) { + $form->get("site_name")->setData(getenv("SITE_NAME")); + } + if (getenv("SITE_ROOTDIR") && strlen("SITE_ROOTDIR")) { + form->set("site_rootdir")->setData(getenv("SITE_ROOTDIR")); + } + if (getenv("DATABASE_URL") && strlen("DATABASE_URL")) { + $form->get("db_url")->setData(getenv("DATABASE_URL")); + $form->get("db_backend")->setData("url"); + } + if (getenv("MAILER_DSN") && strlen(getenv("MAILER_DSN"))) { + $form->get("email_dsn")->setData(getenv("MAILER_DSN")); + $form->get("email_backend")->setData("dsn"); + } + } + + public function getDataFromSetupForm(Form $form) : array + { + $data=array(); + + $locale = $form->get('locale')->getNormData(); + if ($locale && strlen($locale)) { + $data['locale'] = $locale; + } + + $tempdir = $form->get('tempdir')->getNormData(); + if ($tempdir && strlen($tempdir)) { + $data["tempdir"] = $tempdir; + } + + $site=[ + "name" => $form->get("site_name")->getNormData(), + "email" => $form->get("site_name")->getNormData() + ]; + $data["site"] = $site; + + $user = array(); + $tmp_user = new WebrootUser(); + + $user_username = $form->get('user_username')->getNormData(); + if (!$username) { + $username=""; + } + $tmp_user->setUsername($username); + $user['username']=username; + + $user_email = $form->get('user_email')->getNormData(); + if (!$user_email) { + $user_email = ""; + } + $tmp_user->setEmail($user_email); + $user['email'] = $user_email; + + $password0 = $form->get('user_password0')->get('user_password0'); + $password1 = $form->get('user_password1')->get('user_password1'); + if ((strlen($password0) >= 8) && ($password0 == $password1)) { + $passwd = $this->password_hasher->hashPassword($tmp_user,$password0); + } + $user['password'] = $passwd; + $tmp_user->setPassword($passwd); + + $data['user'] = $user; + + $db = array(); + + $db["backend"] = $form->get("db_backend")->getNormData(); + + $db_url = $form->get('db_url')->getNormData(); + if ($db_url && strlen($db_url)) { + $db['url'] = $db_url; + } + $db_database = $form->get('db_database')->getNormData(); + if ($db_database && strlen($db_database)) { + $db["database"] = $db_database; + } + $db_host = $form->get('db_host')->getNormData(); + if ($db_host && strlen($db_host)) { + $db['host'] = db_host; + } + $db_port = $form->get('db_port')->getNormData(); + if ($db_port && (int) $db_port) { + $db['port'] = "db_port"; + } + $db_user = $form->get('db_user')->getNormData(); + if ($db_user && strlen($db_user)) { + $db["user"] = $db_user; + } + $db_password = $form->get('db_password')->getNormData(); + if ($db_password && strlen($db_password)) { + $db['password'] = $db_password; + } + $data["user"] = user; + + $email = [ + "backend" => $form->get("email_backend")->getNormData(), + "address" => $form->get("email_address")->getNormData(), + ]; + + $email_path = $form->get("email_path")->getNormData(); + if ($email_path && strlen($email_path)) { + $email["path"] = $email_path; + } + + $email_user = $form->get("email_user")->getNormData(); + if ($email_user && strlen($email_user)) { + $email["user"] = $email_user; + } + + $email_host = $form->get('email_host')->getNormData(); + if ($email_host && strlen($email_host)) { + $email["host"] = $email_host; + } + + $email_port = $form->get('email_port')->getNormData(); + if ($email_port && (int) $email_port) { + $email["port"] = $email_port; + } + + $email_dsn = $form->get('email_dsn')->getNormData(); + if ($email_dsn && strlen($email_dsn)) { + $email["dsn"] = $email_dsn; + } + $data["email"] = $email; + + return $data; + } + + public function exportSetupFormToFile(Form $form,string $yaml_file) + { + $data = (new Yaml())->dump($this->getDataFromSetupForm($form)); + $file = fopen("yaml_file","w"); + fwrite($file, $data); + $fclose($file); + } + + public function setSetupFormFromFile(Form $form,string $yaml_file) + { + $this->setSetupFormFromData($form,(new Yaml())->parseFile($yaml_file)); + } + + public function setSetupDataCookie(Form $form): string + { + $old_file = filter_input($_COOKIE["--webroot-setup--"], FILTER_DEFAULT); + if ($old_file && strlen($old_file)) { + unlink($old_file); + } + $filename = tempnam($form->get("tempdir")->getNormData(),"wrsetup-"); + $this->exportSetupFormToFile($form, $filename); + setcookie("--webroot-setup--", $filename); + } } diff --git a/src/Repository/WebrootRoleRepository.php b/src/Repository/WebrootRoleRepository.php index 2dca5be..c09b100 100644 --- a/src/Repository/WebrootRoleRepository.php +++ b/src/Repository/WebrootRoleRepository.php @@ -16,6 +16,14 @@ class WebrootRoleRepository extends ServiceEntityRepository parent::__construct($registry, WebrootRole::class); } + public function findByRoleName(string $rolename): ?WebrootRole + { + return $this->createQueryBuilder("wr") + ->andWhere("wr.role = :val") + ->setParameter("val", $rolename) + ->getQuery() + ->getOneOrNullResult(); + } // /** // * @return WebrootRole[] Returns an array of WebrootRole objects // */ diff --git a/src/Utility/i18n.php b/src/Utility/i18n.php new file mode 100644 index 0000000..e7a5f57 --- /dev/null +++ b/src/Utility/i18n.php @@ -0,0 +1,39 @@ + +

Webroot Setup

+
+
+
    + {% for error in errors %} +
  • {{ error }}
  • + {% endfor %} +
+
+ {{ form_start(form) }} - {{ form_widget(form) }} +
+ {{ translations.site }} + + + + + + + + + + + + + + + + + + + + +
{{ form_label(form.locale) }}{{ form_widget(form.locale) }}{{ form_label(form.env) }}{{ form_widget(form.env) }}
{{ form_label(form.site_name) }}{{ form_widget(form.site_name) }}{{ form_label(form.site_email) }}{{ form_widget(form.site_email) }}
{{ form_label(form.site_rootdir) }}{{ form_widget(form.site_rootdir) }}{{ form_label(form.tempdir) }}{{ form_widget(form.tempdir) }}
+
+
+ {{ translations.user }} + + + + + + + + + + + + + +
{{ form_label(form.user_username) }}{{ form_widget(form.user_username) }}{{ form_label(form.user_password0) }}{{ form_widget(form.user_password0) }}
{{ form_label(form.user_email) }}{{ form_widget(form.user_email) }}{{ form_label(form.user_password1) }}{{ form_widget(form.user_password1) }}
+
+
+ {{ translations.db }} + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ form_widget(form.db_migrate) }} {{ form_label(form.db_migrate) }}{{ form_widget(form.db_create) }} {{ form_label(form.db_create) }}
{{ form_label(form.db_backend) }}{{ form_widget(form.db_backend) }}{{ form_label(form.db_database) }}{{ form_widget(form.db_database) }}
{{ form_label(form.db_host) }}{{ form_widget(form.db_host) }}{{ form_label(form.db_port) }}{{ form_widget(form.db_port) }}
{{ form_label(form.db_user) }}{{ form_widget(form.db_user) }}{{ form_label(form.db_password) }}{{ form_widget(form.db_password) }}
{{ form_label(form.db_url) }}{{ form_widget(form.db_url) }}
+
+
+ {{ translations.email }} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ form_label(form.email_backend) }}{{ form_widget(form.email_backend) }}{{ form_label(form.email_address) }}{{ form_widget(form.email_address) }}
{{ form_label(form.email_user) }}{{ form_widget(form.email_user) }}{{ form_label(form.email_password) }}{{ form_widget(form.email_password) }}
{{ form_label(form.email_host) }}{{ form_widget(form.email_host) }}{{ form_label(form.email_port) }}{{ form_widget(form.email_port) }}
{{ form_label(form.email_path) }}{{ form_widget(form.email_path) }}
{{ form_label(form.email_dsn) }}{{ form_widget(form.email_dsn) }}
+
+ {{ form_widget(form.submit) }} {{ form_end(form) }}
+ {% endblock %} diff --git a/translations/de/LC_MESSAGES/messages.mo b/translations/de/LC_MESSAGES/messages.mo deleted file mode 100644 index 6c5906d..0000000 Binary files a/translations/de/LC_MESSAGES/messages.mo and /dev/null differ diff --git a/translations/de/LC_MESSAGES/mydevel-webroot.mo b/translations/de/LC_MESSAGES/mydevel-webroot.mo new file mode 100644 index 0000000..d94db20 Binary files /dev/null and b/translations/de/LC_MESSAGES/mydevel-webroot.mo differ diff --git a/translations/de/LC_MESSAGES/mydevel.webroot.mo b/translations/de/LC_MESSAGES/mydevel.webroot.mo deleted file mode 100644 index 6c5906d..0000000 Binary files a/translations/de/LC_MESSAGES/mydevel.webroot.mo and /dev/null differ diff --git a/translations/security.de.yaml b/translations/security.de.yaml new file mode 100644 index 0000000..0eb2ebc --- /dev/null +++ b/translations/security.de.yaml @@ -0,0 +1,19 @@ +'An authentication exception occurred.': 'Es ist ein Fehler bei der Authentifikation aufgetreten.' +'Authentication credentials could not be found.': 'Es konnten keine Zugangsdaten gefunden werden.' +'Authentication request could not be processed due to a system problem.': 'Die Authentifikation konnte wegen eines Systemproblems nicht bearbeitet werden.' +'Invalid credentials.': 'Fehlerhafte Zugangsdaten.' +'Cookie has already been used by someone else.': 'Cookie wurde bereits von jemand anderem verwendet.' +'Not privileged to request the resource.': 'Keine Rechte, um die Ressource anzufragen.' +'Invalid CSRF token.': 'Ungültiges CSRF-Token.' +'No authentication provider found to support the authentication token.': 'Es wurde kein Authentifizierungs-Provider gefunden, der das Authentifizierungs-Token unterstützt.' +'No session available, it either timed out or cookies are not enabled.': 'Keine Session verfügbar, entweder ist diese abgelaufen oder Cookies sind nicht aktiviert.' +'No token could be found.': 'Es wurde kein Token gefunden.' +'Username could not be found.': 'Der Benutzername wurde nicht gefunden.' +'Account has expired.': 'Der Account ist abgelaufen.' +'Credentials have expired.': 'Die Zugangsdaten sind abgelaufen.' +'Account is disabled.': 'Der Account ist deaktiviert.' +'Account is locked.': 'Der Account ist gesperrt.' +'Too many failed login attempts, please try again later.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es später noch einmal.' +'Invalid or expired login link.': 'Ungültiger oder abgelaufener Anmelde-Link.' +'Too many failed login attempts, please try again in %minutes% minute.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es in einer Minute noch einmal.' +'Too many failed login attempts, please try again in %minutes% minutes.': 'Zu viele fehlgeschlagene Anmeldeversuche, bitte versuchen Sie es in %minutes% Minuten noch einmal.' diff --git a/translations/security.en.yaml b/translations/security.en.yaml new file mode 100644 index 0000000..a71ad4e --- /dev/null +++ b/translations/security.en.yaml @@ -0,0 +1,19 @@ +'An authentication exception occurred.': 'An authentication exception occurred.' +'Authentication credentials could not be found.': 'Authentication credentials could not be found.' +'Authentication request could not be processed due to a system problem.': 'Authentication request could not be processed due to a system problem.' +'Invalid credentials.': 'Invalid credentials.' +'Cookie has already been used by someone else.': 'Cookie has already been used by someone else.' +'Not privileged to request the resource.': 'Not privileged to request the resource.' +'Invalid CSRF token.': 'Invalid CSRF token.' +'No authentication provider found to support the authentication token.': 'No authentication provider found to support the authentication token.' +'No session available, it either timed out or cookies are not enabled.': 'No session available, it either timed out or cookies are not enabled.' +'No token could be found.': 'No token could be found.' +'Username could not be found.': 'Username could not be found.' +'Account has expired.': 'Account has expired.' +'Credentials have expired.': 'Credentials have expired.' +'Account is disabled.': 'Account is disabled.' +'Account is locked.': 'Account is locked.' +'Too many failed login attempts, please try again later.': 'Too many failed login attempts, please try again later.' +'Invalid or expired login link.': 'Invalid or expired login link.' +'Too many failed login attempts, please try again in %minutes% minute.': 'Too many failed login attempts, please try again in %minutes% minute.' +'Too many failed login attempts, please try again in %minutes% minutes.': 'Too many failed login attempts, please try again in %minutes% minutes.' diff --git a/translations/validators.de.yaml b/translations/validators.de.yaml new file mode 100644 index 0000000..98d35da --- /dev/null +++ b/translations/validators.de.yaml @@ -0,0 +1,187 @@ +'This value should be false.': 'Dieser Wert sollte false sein.' +'This value should be true.': 'Dieser Wert sollte true sein.' +'This value should be of type {{ type }}.': 'Dieser Wert sollte vom Typ {{ type }} sein.' +'This value should be blank.': 'Dieser Wert sollte leer sein.' +'The value you selected is not a valid choice.': 'Sie haben einen ungültigen Wert ausgewählt.' +'You must select at least {{ limit }} choice': + '|You must select at least {{ limit }} choices.': 'Sie müssen mindestens {{ limit }} Möglichkeit wählen.|Sie müssen mindestens {{ limit }} Möglichkeiten wählen.' +'You must select at most {{ limit }} choice': + '|You must select at most {{ limit }} choices.': 'Sie dürfen höchstens {{ limit }} Möglichkeit wählen.|Sie dürfen höchstens {{ limit }} Möglichkeiten wählen.' +'One or more of the given values is invalid.': 'Einer oder mehrere der angegebenen Werte sind ungültig.' +'This field was not expected.': 'Dieses Feld wurde nicht erwartet.' +'This field is missing.': 'Dieses Feld fehlt.' +'This value is not a valid date.': 'Dieser Wert entspricht keiner gültigen Datumsangabe.' +'This value is not a valid datetime.': 'Dieser Wert entspricht keiner gültigen Datums- und Zeitangabe.' +'This value is not a valid email address.': 'Dieser Wert ist keine gültige E-Mail-Adresse.' +'The file could not be found.': 'Die Datei wurde nicht gefunden.' +'The file is not readable.': 'Die Datei ist nicht lesbar.' +'The file is too large ({{ size }} {{ suffix }})': + ' Allowed maximum size is {{ limit }} {{ suffix }}.': 'Die Datei ist zu groß ({{ size }} {{ suffix }}). Die maximal zulässige Größe beträgt {{ limit }} {{ suffix }}.' +'The mime type of the file is invalid ({{ type }})': + ' Allowed mime types are {{ types }}.': 'Der Dateityp ist ungültig ({{ type }}). Erlaubte Dateitypen sind {{ types }}.' +'This value should be {{ limit }} or less.': 'Dieser Wert sollte kleiner oder gleich {{ limit }} sein.' +'This value is too long': + ' It should have {{ limit }} character or less': + '|This value is too long': + ' It should have {{ limit }} characters or less.': 'Diese Zeichenkette ist zu lang. Sie sollte höchstens {{ limit }} Zeichen haben.|Diese Zeichenkette ist zu lang. Sie sollte höchstens {{ limit }} Zeichen haben.' + ' It should contain one word': + '|This value is too long': + ' It should contain {{ max }} words or less.': 'Dieser Wert ist zu lang. Er darf maximal aus einem Wort bestehen.|Dieser Wert ist zu lang. Er darf maximal {{ max }} Wörter enthalten.' +'This value should be {{ limit }} or more.': 'Dieser Wert sollte größer oder gleich {{ limit }} sein.' +'This value is too short': + ' It should have {{ limit }} character or more': + '|This value is too short': + ' It should have {{ limit }} characters or more.': 'Diese Zeichenkette ist zu kurz. Sie sollte mindestens {{ limit }} Zeichen haben.|Diese Zeichenkette ist zu kurz. Sie sollte mindestens {{ limit }} Zeichen haben.' + ' It should contain at least one word': + '|This value is too short': + ' It should contain at least {{ min }} words.': 'Dieser Wert ist zu kurz. Er muss aus mindestens einem Wort bestehen.|Dieser Wert ist zu kurz. Er muss mindestens {{ min }} Wörter enthalten.' +'This value should not be blank.': 'Dieser Wert sollte nicht leer sein.' +'This value should not be null.': 'Dieser Wert sollte nicht null sein.' +'This value should be null.': 'Dieser Wert sollte null sein.' +'This value is not valid.': 'Dieser Wert ist nicht gültig.' +'This value is not a valid time.': 'Dieser Wert entspricht keiner gültigen Zeitangabe.' +'This value is not a valid URL.': 'Dieser Wert ist keine gültige URL.' +'The two values should be equal.': 'Die beiden Werte sollten identisch sein.' +'The file is too large': + ' Allowed maximum size is {{ limit }} {{ suffix }}.': 'Die Datei ist zu groß. Die maximal zulässige Größe beträgt {{ limit }} {{ suffix }}.' +'The file is too large.': 'Die Datei ist zu groß.' +'The file could not be uploaded.': 'Die Datei konnte nicht hochgeladen werden.' +'This value should be a valid number.': 'Dieser Wert sollte eine gültige Zahl sein.' +'This file is not a valid image.': 'Diese Datei ist kein gültiges Bild.' +'This is not a valid IP address.': 'Dieser Wert ist keine gültige IP-Adresse.' +'This value is not a valid language.': 'Dieser Wert entspricht keiner gültigen Sprache.' +'This value is not a valid locale.': 'Dieser Wert entspricht keinem gültigen Gebietsschema.' +'This value is not a valid country.': 'Dieser Wert entspricht keinem gültigen Land.' +'This value is already used.': 'Dieser Wert wird bereits verwendet.' +'The size of the image could not be detected.': 'Die Größe des Bildes konnte nicht ermittelt werden.' +'The image width is too big ({{ width }}px)': + ' Allowed maximum width is {{ max_width }}px.': 'Die Bildbreite ist zu groß ({{ width }}px). Die maximal zulässige Breite beträgt {{ max_width }}px.' +'The image width is too small ({{ width }}px)': + ' Minimum width expected is {{ min_width }}px.': 'Die Bildbreite ist zu gering ({{ width }}px). Die erwartete Mindestbreite beträgt {{ min_width }}px.' +'The image height is too big ({{ height }}px)': + ' Allowed maximum height is {{ max_height }}px.': 'Die Bildhöhe ist zu groß ({{ height }}px). Die maximal zulässige Höhe beträgt {{ max_height }}px.' +'The image height is too small ({{ height }}px)': + ' Minimum height expected is {{ min_height }}px.': 'Die Bildhöhe ist zu gering ({{ height }}px). Die erwartete Mindesthöhe beträgt {{ min_height }}px.' +"This value should be the user's current password.": 'Dieser Wert sollte dem aktuellen Benutzerpasswort entsprechen.' +'This value should have exactly {{ limit }} character': + '|This value should have exactly {{ limit }} characters.': 'Dieser Wert sollte genau {{ limit }} Zeichen lang sein.|Dieser Wert sollte genau {{ limit }} Zeichen lang sein.' +'The file was only partially uploaded.': 'Die Datei wurde nur teilweise hochgeladen.' +'No file was uploaded.': 'Es wurde keine Datei hochgeladen.' +'No temporary folder was configured in php': + ini.: 'Es wurde kein temporärer Ordner in der php.ini konfiguriert oder der temporäre Ordner existiert nicht.' +'Cannot write temporary file to disk.': 'Kann die temporäre Datei nicht speichern.' +'A PHP extension caused the upload to fail.': 'Eine PHP-Erweiterung verhinderte den Upload.' +'This collection should contain {{ limit }} element or more': + '|This collection should contain {{ limit }} elements or more.': 'Diese Sammlung sollte {{ limit }} oder mehr Elemente beinhalten.|Diese Sammlung sollte {{ limit }} oder mehr Elemente beinhalten.' +'This collection should contain {{ limit }} element or less': + '|This collection should contain {{ limit }} elements or less.': 'Diese Sammlung sollte {{ limit }} oder weniger Elemente beinhalten.|Diese Sammlung sollte {{ limit }} oder weniger Elemente beinhalten.' +'This collection should contain exactly {{ limit }} element': + '|This collection should contain exactly {{ limit }} elements.': 'Diese Sammlung sollte genau {{ limit }} Element beinhalten.|Diese Sammlung sollte genau {{ limit }} Elemente beinhalten.' +'Invalid card number.': 'Ungültige Kartennummer.' +'Unsupported card type or invalid card number.': 'Nicht unterstützter Kartentyp oder ungültige Kartennummer.' +'This is not a valid International Bank Account Number (IBAN).': 'Dieser Wert ist keine gültige Internationale Bankkontonummer (IBAN).' +'This value is not a valid ISBN-10.': 'Dieser Wert entspricht keiner gültigen ISBN-10.' +'This value is not a valid ISBN-13.': 'Dieser Wert entspricht keiner gültigen ISBN-13.' +'This value is neither a valid ISBN-10 nor a valid ISBN-13.': 'Dieser Wert ist weder eine gültige ISBN-10 noch eine gültige ISBN-13.' +'This value is not a valid ISSN.': 'Dieser Wert ist keine gültige ISSN.' +'This value is not a valid currency.': 'Dieser Wert ist keine gültige Währung.' +'This value should be equal to {{ compared_value }}.': 'Dieser Wert sollte gleich {{ compared_value }} sein.' +'This value should be greater than {{ compared_value }}.': 'Dieser Wert sollte größer als {{ compared_value }} sein.' +'This value should be greater than or equal to {{ compared_value }}.': 'Dieser Wert sollte größer oder gleich {{ compared_value }} sein.' +'This value should be identical to {{ compared_value_type }} {{ compared_value }}.': 'Dieser Wert sollte identisch sein mit {{ compared_value_type }} {{ compared_value }}.' +'This value should be less than {{ compared_value }}.': 'Dieser Wert sollte kleiner als {{ compared_value }} sein.' +'This value should be less than or equal to {{ compared_value }}.': 'Dieser Wert sollte kleiner oder gleich {{ compared_value }} sein.' +'This value should not be equal to {{ compared_value }}.': 'Dieser Wert sollte nicht {{ compared_value }} sein.' +'This value should not be identical to {{ compared_value_type }} {{ compared_value }}.': 'Dieser Wert sollte nicht identisch sein mit {{ compared_value_type }} {{ compared_value }}.' +'The image ratio is too big ({{ ratio }})': + ' Allowed maximum ratio is {{ max_ratio }}.': 'Das Seitenverhältnis des Bildes ist zu groß ({{ ratio }}). Der erlaubte Maximalwert ist {{ max_ratio }}.' +'The image ratio is too small ({{ ratio }})': + ' Minimum ratio expected is {{ min_ratio }}.': 'Das Seitenverhältnis des Bildes ist zu klein ({{ ratio }}). Der erwartete Minimalwert ist {{ min_ratio }}.' +'The image is square ({{ width }}x{{ height }}px)': + ' Square images are not allowed.': 'Das Bild ist quadratisch ({{ width }}x{{ height }}px). Quadratische Bilder sind nicht erlaubt.' +'The image is landscape oriented ({{ width }}x{{ height }}px)': + ' Landscape oriented images are not allowed.': 'Das Bild ist im Querformat ({{ width }}x{{ height }}px). Bilder im Querformat sind nicht erlaubt.' +'The image is portrait oriented ({{ width }}x{{ height }}px)': + ' Portrait oriented images are not allowed.': 'Das Bild ist im Hochformat ({{ width }}x{{ height }}px). Bilder im Hochformat sind nicht erlaubt.' +'An empty file is not allowed.': 'Eine leere Datei ist nicht erlaubt.' +'The host could not be resolved.': 'Der Hostname konnte nicht aufgelöst werden.' +'This value does not match the expected {{ charset }} charset.': 'Dieser Wert entspricht nicht dem erwarteten Zeichensatz {{ charset }}.' +'This is not a valid Business Identifier Code (BIC).': 'Dieser Wert ist keine gültige internationale Bankleitzahl (BIC).' +Error: Fehler +'This is not a valid UUID.': 'Dieser Wert ist keine gültige UUID.' +'This value should be a multiple of {{ compared_value }}.': 'Dieser Wert sollte ein Vielfaches von {{ compared_value }} sein.' +'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.': 'Diese internationale Bankleitzahl (BIC) ist nicht mit der IBAN {{ iban }} assoziiert.' +'This value should be valid JSON.': 'Dieser Wert sollte gültiges JSON sein.' +'This collection should contain only unique elements.': 'Diese Sammlung darf keine doppelten Elemente enthalten.' +'This value should be positive.': 'Diese Zahl sollte positiv sein.' +'This value should be either positive or zero.': 'Diese Zahl sollte entweder positiv oder 0 sein.' +'This value should be negative.': 'Diese Zahl sollte negativ sein.' +'This value should be either negative or zero.': 'Diese Zahl sollte entweder negativ oder 0 sein.' +'This value is not a valid timezone.': 'Dieser Wert ist keine gültige Zeitzone.' +'This password has been leaked in a data breach, it must not be used': + ' Please use another password.': 'Dieses Passwort ist Teil eines Datenlecks, es darf nicht verwendet werden.' +'This value should be between {{ min }} and {{ max }}.': 'Dieser Wert sollte zwischen {{ min }} und {{ max }} sein.' +'This value is not a valid hostname.': 'Dieser Wert ist kein gültiger Hostname.' +'The number of elements in this collection should be a multiple of {{ compared_value }}.': 'Die Anzahl an Elementen in dieser Sammlung sollte ein Vielfaches von {{ compared_value }} sein.' +'This value should satisfy at least one of the following constraints:': 'Dieser Wert sollte eine der folgenden Bedingungen erfüllen:' +'Each element of this collection should satisfy its own set of constraints.': 'Jedes Element dieser Sammlung sollte seine eigene Menge an Bedingungen erfüllen.' +'This value is not a valid International Securities Identification Number (ISIN).': 'Dieser Wert ist keine gültige Internationale Wertpapierkennnummer (ISIN).' +'This value should be a valid expression.': 'Dieser Wert sollte eine gültige Expression sein.' +'This value is not a valid CSS color.': 'Dieser Wert ist keine gültige CSS-Farbe.' +'This value is not a valid CIDR notation.': 'Dieser Wert entspricht nicht der CIDR-Notation.' +'The value of the netmask should be between {{ min }} and {{ max }}.': 'Der Wert der Subnetzmaske sollte zwischen {{ min }} und {{ max }} liegen.' +'The filename is too long': + ' It should have {{ filename_max_length }} character or less': + '|The filename is too long': + ' It should have {{ filename_max_length }} characters or less.': 'Der Dateiname ist zu lang. Er sollte nicht länger als {{ filename_max_length }} Zeichen sein.|Der Dateiname ist zu lang. Er sollte nicht länger als {{ filename_max_length }} Zeichen sein.' +'The password strength is too low': + ' Please use a stronger password.': 'Das Passwort ist zu schwach.' +'This value contains characters that are not allowed by the current restriction-level.': 'Der Wert enthält Zeichen, die auf der aktuellen Einschränkungsstufe nicht erlaubt sind.' +'Using invisible characters is not allowed.': 'Unsichtbare Zeichen sind nicht erlaubt.' +'Mixing numbers from different scripts is not allowed.': 'Das Mischen von Zahlen aus verschiedenen Skripten ist nicht erlaubt.' +'Using hidden overlay characters is not allowed.': 'Verstecke Overlay-Zeichen sind nicht erlaubt.' +'The extension of the file is invalid ({{ extension }})': + ' Allowed extensions are {{ extensions }}.': 'Die Dateiendung ist ungültig ({{ extension }}). Gültige Dateiendungen sind {{ extensions }}.' +'The detected character encoding is invalid ({{ detected }})': + ' Allowed encodings are {{ encodings }}.': 'Der erkannte Zeichensatz ist nicht gültig ({{ detected }}). Gültige Zeichensätze sind {{ encodings }}.' +'This value is not a valid MAC address.': 'Dieser Wert ist keine gültige MAC-Adresse.' +'This URL is missing a top-level domain.': 'Dieser URL fehlt eine Top-Level-Domain.' +'This value does not represent a valid week in the ISO 8601 format.': 'Dieser Wert ist keine Wochenangabe im ISO 8601-Format.' +'This value is not a valid week.': 'Dieser Wert ist keine gültige Woche.' +'This value should not be before week "{{ min }}".': 'Dieser Wert darf nicht vor der Woche "{{ min }}" sein.' +'This value should not be after week "{{ max }}".': 'Dieser Wert darf nicht nach der Woche "{{ max }}" sein.' +'This form should not contain extra fields.': 'Dieses Formular sollte keine zusätzlichen Felder enthalten.' +'The uploaded file was too large': + ' Please try to upload a smaller file.': 'Die hochgeladene Datei ist zu groß. Versuchen Sie bitte eine kleinere Datei hochzuladen.' +'The CSRF token is invalid': + ' Please try to resubmit the form.': 'Der CSRF-Token ist ungültig. Versuchen Sie bitte, das Formular erneut zu senden.' +'This value is not a valid HTML5 color.': 'Dieser Wert ist keine gültige HTML5 Farbe.' +'Please enter a valid birthdate.': 'Bitte geben Sie ein gültiges Geburtsdatum ein.' +'The selected choice is invalid.': 'Die Auswahl ist ungültig.' +'The collection is invalid.': 'Diese Gruppe von Feldern ist ungültig.' +'Please select a valid color.': 'Bitte geben Sie eine gültige Farbe ein.' +'Please select a valid country.': 'Bitte wählen Sie ein gültiges Land aus.' +'Please select a valid currency.': 'Bitte wählen Sie eine gültige Währung aus.' +'Please choose a valid date interval.': 'Bitte wählen Sie ein gültiges Datumsintervall.' +'Please enter a valid date and time.': 'Bitte geben Sie ein gültiges Datum samt Uhrzeit ein.' +'Please enter a valid date.': 'Bitte geben Sie ein gültiges Datum ein.' +'Please select a valid file.': 'Bitte wählen Sie eine gültige Datei.' +'The hidden field is invalid.': 'Das versteckte Feld ist ungültig.' +'Please enter an integer.': 'Bitte geben Sie eine ganze Zahl ein.' +'Please select a valid language.': 'Bitte wählen Sie eine gültige Sprache.' +'Please select a valid locale.': 'Bitte wählen Sie eine gültige Locale-Einstellung aus.' +'Please enter a valid money amount.': 'Bitte geben Sie einen gültigen Geldbetrag ein.' +'Please enter a number.': 'Bitte geben Sie eine gültige Zahl ein.' +'The password is invalid.': 'Das Kennwort ist ungültig.' +'Please enter a percentage value.': 'Bitte geben Sie einen gültigen Prozentwert ein.' +'The values do not match.': 'Die Werte stimmen nicht überein.' +'Please enter a valid time.': 'Bitte geben Sie eine gültige Uhrzeit ein.' +'Please select a valid timezone.': 'Bitte wählen Sie eine gültige Zeitzone.' +'Please enter a valid URL.': 'Bitte geben Sie eine gültige URL ein.' +'Please enter a valid search term.': 'Bitte geben Sie einen gültigen Suchbegriff ein.' +'Please provide a valid phone number.': 'Bitte geben Sie eine gültige Telefonnummer ein.' +'The checkbox has an invalid value.': 'Das Kontrollkästchen hat einen ungültigen Wert.' +'Please enter a valid email address.': 'Bitte geben Sie eine gültige E-Mail-Adresse ein.' +'Please select a valid option.': 'Bitte wählen Sie eine gültige Option.' +'Please select a valid range.': 'Bitte wählen Sie einen gültigen Bereich.' +'Please enter a valid week.': 'Bitte geben Sie eine gültige Woche ein.' diff --git a/translations/validators.en.yaml b/translations/validators.en.yaml new file mode 100644 index 0000000..fd7233b --- /dev/null +++ b/translations/validators.en.yaml @@ -0,0 +1,187 @@ +'This value should be false.': 'This value should be false.' +'This value should be true.': 'This value should be true.' +'This value should be of type {{ type }}.': 'This value should be of type {{ type }}.' +'This value should be blank.': 'This value should be blank.' +'The value you selected is not a valid choice.': 'The value you selected is not a valid choice.' +'You must select at least {{ limit }} choice': + '|You must select at least {{ limit }} choices.': 'You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices.' +'You must select at most {{ limit }} choice': + '|You must select at most {{ limit }} choices.': 'You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices.' +'One or more of the given values is invalid.': 'One or more of the given values is invalid.' +'This field was not expected.': 'This field was not expected.' +'This field is missing.': 'This field is missing.' +'This value is not a valid date.': 'This value is not a valid date.' +'This value is not a valid datetime.': 'This value is not a valid datetime.' +'This value is not a valid email address.': 'This value is not a valid email address.' +'The file could not be found.': 'The file could not be found.' +'The file is not readable.': 'The file is not readable.' +'The file is too large ({{ size }} {{ suffix }})': + ' Allowed maximum size is {{ limit }} {{ suffix }}.': 'The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}.' +'The mime type of the file is invalid ({{ type }})': + ' Allowed mime types are {{ types }}.': 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.' +'This value should be {{ limit }} or less.': 'This value should be {{ limit }} or less.' +'This value is too long': + ' It should have {{ limit }} character or less': + '|This value is too long': + ' It should have {{ limit }} characters or less.': 'This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less.' + ' It should contain one word': + '|This value is too long': + ' It should contain {{ max }} words or less.': 'This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.' +'This value should be {{ limit }} or more.': 'This value should be {{ limit }} or more.' +'This value is too short': + ' It should have {{ limit }} character or more': + '|This value is too short': + ' It should have {{ limit }} characters or more.': 'This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more.' + ' It should contain at least one word': + '|This value is too short': + ' It should contain at least {{ min }} words.': 'This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.' +'This value should not be blank.': 'This value should not be blank.' +'This value should not be null.': 'This value should not be null.' +'This value should be null.': 'This value should be null.' +'This value is not valid.': 'This value is not valid.' +'This value is not a valid time.': 'This value is not a valid time.' +'This value is not a valid URL.': 'This value is not a valid URL.' +'The two values should be equal.': 'The two values should be equal.' +'The file is too large': + ' Allowed maximum size is {{ limit }} {{ suffix }}.': 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.' +'The file is too large.': 'The file is too large.' +'The file could not be uploaded.': 'The file could not be uploaded.' +'This value should be a valid number.': 'This value should be a valid number.' +'This file is not a valid image.': 'This file is not a valid image.' +'This is not a valid IP address.': 'This value is not a valid IP address.' +'This value is not a valid language.': 'This value is not a valid language.' +'This value is not a valid locale.': 'This value is not a valid locale.' +'This value is not a valid country.': 'This value is not a valid country.' +'This value is already used.': 'This value is already used.' +'The size of the image could not be detected.': 'The size of the image could not be detected.' +'The image width is too big ({{ width }}px)': + ' Allowed maximum width is {{ max_width }}px.': 'The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px.' +'The image width is too small ({{ width }}px)': + ' Minimum width expected is {{ min_width }}px.': 'The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px.' +'The image height is too big ({{ height }}px)': + ' Allowed maximum height is {{ max_height }}px.': 'The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px.' +'The image height is too small ({{ height }}px)': + ' Minimum height expected is {{ min_height }}px.': 'The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px.' +"This value should be the user's current password.": "This value should be the user's current password." +'This value should have exactly {{ limit }} character': + '|This value should have exactly {{ limit }} characters.': 'This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters.' +'The file was only partially uploaded.': 'The file was only partially uploaded.' +'No file was uploaded.': 'No file was uploaded.' +'No temporary folder was configured in php': + ini.: 'No temporary folder was configured in php.ini, or the configured folder does not exist.' +'Cannot write temporary file to disk.': 'Cannot write temporary file to disk.' +'A PHP extension caused the upload to fail.': 'A PHP extension caused the upload to fail.' +'This collection should contain {{ limit }} element or more': + '|This collection should contain {{ limit }} elements or more.': 'This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more.' +'This collection should contain {{ limit }} element or less': + '|This collection should contain {{ limit }} elements or less.': 'This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less.' +'This collection should contain exactly {{ limit }} element': + '|This collection should contain exactly {{ limit }} elements.': 'This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements.' +'Invalid card number.': 'Invalid card number.' +'Unsupported card type or invalid card number.': 'Unsupported card type or invalid card number.' +'This is not a valid International Bank Account Number (IBAN).': 'This value is not a valid International Bank Account Number (IBAN).' +'This value is not a valid ISBN-10.': 'This value is not a valid ISBN-10.' +'This value is not a valid ISBN-13.': 'This value is not a valid ISBN-13.' +'This value is neither a valid ISBN-10 nor a valid ISBN-13.': 'This value is neither a valid ISBN-10 nor a valid ISBN-13.' +'This value is not a valid ISSN.': 'This value is not a valid ISSN.' +'This value is not a valid currency.': 'This value is not a valid currency.' +'This value should be equal to {{ compared_value }}.': 'This value should be equal to {{ compared_value }}.' +'This value should be greater than {{ compared_value }}.': 'This value should be greater than {{ compared_value }}.' +'This value should be greater than or equal to {{ compared_value }}.': 'This value should be greater than or equal to {{ compared_value }}.' +'This value should be identical to {{ compared_value_type }} {{ compared_value }}.': 'This value should be identical to {{ compared_value_type }} {{ compared_value }}.' +'This value should be less than {{ compared_value }}.': 'This value should be less than {{ compared_value }}.' +'This value should be less than or equal to {{ compared_value }}.': 'This value should be less than or equal to {{ compared_value }}.' +'This value should not be equal to {{ compared_value }}.': 'This value should not be equal to {{ compared_value }}.' +'This value should not be identical to {{ compared_value_type }} {{ compared_value }}.': 'This value should not be identical to {{ compared_value_type }} {{ compared_value }}.' +'The image ratio is too big ({{ ratio }})': + ' Allowed maximum ratio is {{ max_ratio }}.': 'The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}.' +'The image ratio is too small ({{ ratio }})': + ' Minimum ratio expected is {{ min_ratio }}.': 'The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}.' +'The image is square ({{ width }}x{{ height }}px)': + ' Square images are not allowed.': 'The image is square ({{ width }}x{{ height }}px). Square images are not allowed.' +'The image is landscape oriented ({{ width }}x{{ height }}px)': + ' Landscape oriented images are not allowed.': 'The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed.' +'The image is portrait oriented ({{ width }}x{{ height }}px)': + ' Portrait oriented images are not allowed.': 'The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed.' +'An empty file is not allowed.': 'An empty file is not allowed.' +'The host could not be resolved.': 'The host could not be resolved.' +'This value does not match the expected {{ charset }} charset.': 'This value does not match the expected {{ charset }} charset.' +'This is not a valid Business Identifier Code (BIC).': 'This value is not a valid Business Identifier Code (BIC).' +Error: Error +'This is not a valid UUID.': 'This value is not a valid UUID.' +'This value should be a multiple of {{ compared_value }}.': 'This value should be a multiple of {{ compared_value }}.' +'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.': 'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.' +'This value should be valid JSON.': 'This value should be valid JSON.' +'This collection should contain only unique elements.': 'This collection should contain only unique elements.' +'This value should be positive.': 'This value should be positive.' +'This value should be either positive or zero.': 'This value should be either positive or zero.' +'This value should be negative.': 'This value should be negative.' +'This value should be either negative or zero.': 'This value should be either negative or zero.' +'This value is not a valid timezone.': 'This value is not a valid timezone.' +'This password has been leaked in a data breach, it must not be used': + ' Please use another password.': 'This password has been leaked in a data breach, it must not be used. Please use another password.' +'This value should be between {{ min }} and {{ max }}.': 'This value should be between {{ min }} and {{ max }}.' +'This value is not a valid hostname.': 'This value is not a valid hostname.' +'The number of elements in this collection should be a multiple of {{ compared_value }}.': 'The number of elements in this collection should be a multiple of {{ compared_value }}.' +'This value should satisfy at least one of the following constraints:': 'This value should satisfy at least one of the following constraints:' +'Each element of this collection should satisfy its own set of constraints.': 'Each element of this collection should satisfy its own set of constraints.' +'This value is not a valid International Securities Identification Number (ISIN).': 'This value is not a valid International Securities Identification Number (ISIN).' +'This value should be a valid expression.': 'This value should be a valid expression.' +'This value is not a valid CSS color.': 'This value is not a valid CSS color.' +'This value is not a valid CIDR notation.': 'This value is not a valid CIDR notation.' +'The value of the netmask should be between {{ min }} and {{ max }}.': 'The value of the netmask should be between {{ min }} and {{ max }}.' +'The filename is too long': + ' It should have {{ filename_max_length }} character or less': + '|The filename is too long': + ' It should have {{ filename_max_length }} characters or less.': 'The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less.' +'The password strength is too low': + ' Please use a stronger password.': 'The password strength is too low. Please use a stronger password.' +'This value contains characters that are not allowed by the current restriction-level.': 'This value contains characters that are not allowed by the current restriction-level.' +'Using invisible characters is not allowed.': 'Using invisible characters is not allowed.' +'Mixing numbers from different scripts is not allowed.': 'Mixing numbers from different scripts is not allowed.' +'Using hidden overlay characters is not allowed.': 'Using hidden overlay characters is not allowed.' +'The extension of the file is invalid ({{ extension }})': + ' Allowed extensions are {{ extensions }}.': 'The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}.' +'The detected character encoding is invalid ({{ detected }})': + ' Allowed encodings are {{ encodings }}.': 'The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}.' +'This value is not a valid MAC address.': 'This value is not a valid MAC address.' +'This URL is missing a top-level domain.': 'This URL is missing a top-level domain.' +'This value does not represent a valid week in the ISO 8601 format.': 'This value does not represent a valid week in the ISO 8601 format.' +'This value is not a valid week.': 'This value is not a valid week.' +'This value should not be before week "{{ min }}".': 'This value should not be before week "{{ min }}".' +'This value should not be after week "{{ max }}".': 'This value should not be after week "{{ max }}".' +'This form should not contain extra fields.': 'This form should not contain extra fields.' +'The uploaded file was too large': + ' Please try to upload a smaller file.': 'The uploaded file was too large. Please try to upload a smaller file.' +'The CSRF token is invalid': + ' Please try to resubmit the form.': 'The CSRF token is invalid. Please try to resubmit the form.' +'This value is not a valid HTML5 color.': 'This value is not a valid HTML5 color.' +'Please enter a valid birthdate.': 'Please enter a valid birthdate.' +'The selected choice is invalid.': 'The selected choice is invalid.' +'The collection is invalid.': 'The collection is invalid.' +'Please select a valid color.': 'Please select a valid color.' +'Please select a valid country.': 'Please select a valid country.' +'Please select a valid currency.': 'Please select a valid currency.' +'Please choose a valid date interval.': 'Please choose a valid date interval.' +'Please enter a valid date and time.': 'Please enter a valid date and time.' +'Please enter a valid date.': 'Please enter a valid date.' +'Please select a valid file.': 'Please select a valid file.' +'The hidden field is invalid.': 'The hidden field is invalid.' +'Please enter an integer.': 'Please enter an integer.' +'Please select a valid language.': 'Please select a valid language.' +'Please select a valid locale.': 'Please select a valid locale.' +'Please enter a valid money amount.': 'Please enter a valid money amount.' +'Please enter a number.': 'Please enter a number.' +'The password is invalid.': 'The password is invalid.' +'Please enter a percentage value.': 'Please enter a percentage value.' +'The values do not match.': 'The values do not match.' +'Please enter a valid time.': 'Please enter a valid time.' +'Please select a valid timezone.': 'Please select a valid timezone.' +'Please enter a valid URL.': 'Please enter a valid URL.' +'Please enter a valid search term.': 'Please enter a valid search term.' +'Please provide a valid phone number.': 'Please provide a valid phone number.' +'The checkbox has an invalid value.': 'The checkbox has an invalid value.' +'Please enter a valid email address.': 'Please enter a valid email address.' +'Please select a valid option.': 'Please select a valid option.' +'Please select a valid range.': 'Please select a valid range.' +'Please enter a valid week.': 'Please enter a valid week.'