2024.11.28 01:57:21

This commit is contained in:
Christian Moser 2024-11-28 01:57:21 +01:00
parent b442dbc2e1
commit e59816de20
25 changed files with 1480 additions and 179 deletions

View File

@ -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

View File

@ -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

145
PO/de.po
View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 <christian@cmoser.eu>\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"

35
PO/makemessages Normal file
View File

@ -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

View File

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""

View File

@ -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

View File

@ -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;
}

2
config/config.yaml Normal file
View File

@ -0,0 +1,2 @@
framework:
default_locale: de

View File

@ -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]

View File

@ -29,6 +29,14 @@ 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

View File

@ -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
{

41
scripts/run_dispatched Normal file
View File

@ -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

3
src/Constants/const.php Normal file
View File

@ -0,0 +1,3 @@
<?php
const WEBROOT_GETTEXT_DOMAIN="mydevel-webroot";

View File

@ -14,14 +14,19 @@ use Doctrine\ORM\EntityManagerInterface;
use App\Controller\WebrootSetupController;
use App\Entity\WebrootUser;
use App\Entity\WebrootRole;
use App\Entity\WebrootFile;
use App\Entity\WebrootFilePermission;
class SetupController extends WebrootSetupController
{
#[Route('/setup',name:'webroot.setup.initial')]
public function initialSetup(Request $request,
EntityManagerInterface $em,
UserPasswordHasherInterface $passwd_hasher): Response
{
$lang= getenv("LANG");
$dotenv_file = join(DIRECTORY_SEPARATOR,[$this->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.
if (count($errors) > 0) {
return $this->render("setup/initial-setup.html.twig",[
"error" => $errors,
"form" => $form]);
"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()
{

View File

@ -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",
"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);
}
}

View File

@ -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
// */

39
src/Utility/i18n.php Normal file
View File

@ -0,0 +1,39 @@
<?php
namespace App\Utility;
function gettext_init(string $package,string $localedir,?string $lang=null)
{
if (function_exists("gettext"))
{
if (!lang) {
$lang=getenv("LANG");
if (!$lang) {
$lang="";
}
}
setlocale(LC_ALL,$lang);
bindtextdomain($package,$localedir);
textdomain($package);
if (function_exists("bind_textdomain_codeset")) {
bind_textdomain_codeset($package, "UTF-8");
}
}
}
function gettext_lib_init(string $package,string$localedir,?string $lang=null)
{
if (function_exists("gettext")) {
if (!$lang) {
$lang=getenv("LANG");
if (!$lang) {
$lang="";
}
}
setlocale(LC_ALL,$lang);
bindtextdomain($package,$localedir);
if (function_exists("bind_textdomain_codeset")) {
bind_textdomain_codeset($package, "UTF-8");
}
}
}

View File

@ -1,9 +1,121 @@
{% extends 'base.html.twig' %}
{% block body %}
<div class="form-box full width">
<h1>Webroot Setup</h1>
<div class="form-box">
<div class="error-message">
<ul>
{% for error in errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{{ form_start(form) }}
{{ form_widget(form) }}
<fieldset>
<legend><strong>{{ translations.site }}</strong></legend>
<table class="full-width">
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.locale) }}</th>
<td>{{ form_widget(form.locale) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.env) }}</th>
<td>{{ form_widget(form.env) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.site_name) }}</th>
<td>{{ form_widget(form.site_name) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.site_email) }}</th>
<td>{{ form_widget(form.site_email) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.site_rootdir) }}</th>
<td>{{ form_widget(form.site_rootdir) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.tempdir) }}</th>
<td>{{ form_widget(form.tempdir) }}</td>
</tr>
</table>
</fieldset>
<fieldset>
<legend><strong>{{ translations.user }}</strong></legend>
<table class="full-width">
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.user_username) }}</th>
<td>{{ form_widget(form.user_username) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.user_password0) }}</th>
<td>{{ form_widget(form.user_password0) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.user_email) }}</th>
<td>{{ form_widget(form.user_email) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.user_password1) }}</th>
<td>{{ form_widget(form.user_password1) }}</td>
</tr>
</table>
</fieldset>
<fieldset>
<legend><strong>{{ translations.db }}</strong></legend>
<table class="full-width">
<tr>
<td colspan="2" class="left">{{ form_widget(form.db_migrate) }} {{ form_label(form.db_migrate) }}</td>
<td colspan="2" class="left">{{ form_widget(form.db_create) }} {{ form_label(form.db_create) }}</td>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_backend) }}</th>
<td>{{ form_widget(form.db_backend) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_database) }}</th>
<td>{{ form_widget(form.db_database) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_host) }}</th>
<td>{{ form_widget(form.db_host) }}</td>
<th class="standard-background shrink-to-fit">{{ form_label(form.db_port) }}</th>
<td>{{ form_widget(form.db_port) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_user) }}</th>
<td>{{ form_widget(form.db_user) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_password) }}</th>
<td>{{ form_widget(form.db_password) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.db_url) }}</th>
<td colspan="3">{{ form_widget(form.db_url) }}</td>
</tr>
</table>
</fieldset>
<fieldset>
<legend><strong>{{ translations.email }}</strong></legend>
<table class="full-width">
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_backend) }}</th>
<td>{{ form_widget(form.email_backend) }}</td>
<th class="standard-background shrink-to-fit">{{ form_label(form.email_address) }}</th>
<td>{{ form_widget(form.email_address) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_user) }}</th>
<td>{{ form_widget(form.email_user) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_password) }}</th>
<td>{{ form_widget(form.email_password) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_host) }}</th>
<td>{{ form_widget(form.email_host) }}</td>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_port) }}</th>
<td>{{ form_widget(form.email_port) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_path) }}</th>
<td colspan="3">{{ form_widget(form.email_path) }}</td>
</tr>
<tr>
<th class="standard-background left shrink-to-fit">{{ form_label(form.email_dsn) }}</th>
<td colspan="3">{{ form_widget(form.email_dsn) }}</td>
</tr>
</table>
</fieldset>
{{ form_widget(form.submit) }}
{{ form_end(form) }}
<div>
{% endblock %}

Binary file not shown.

View File

@ -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.'

View File

@ -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.'

View File

@ -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.'

View File

@ -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.'