mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-02-26 10:10:02 +00:00
Merge branch 'master' into ticket-app-master
# Conflicts: # docs/source/development/create-a-new-bundle.md # src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc/CheckSocialAction.vue # src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc/CheckSocialIssue.vue # src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php # src/Bundle/ChillCalendarBundle/Resources/views/Calendar/_list.html.twig # src/Bundle/ChillCalendarBundle/Resources/views/Calendar/cancelCalendarByAccompanyingCourse.html.twig # src/Bundle/ChillCalendarBundle/Resources/views/Calendar/cancelCalendarByPerson.html.twig # src/Bundle/ChillCalendarBundle/translations/messages.fr.yml # src/Bundle/ChillDocStoreBundle/Resources/public/types/index.ts # src/Bundle/ChillMainBundle/Resources/public/lib/api/apiMethods.ts # src/Bundle/ChillMainBundle/translations/messages.fr.yml # src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Confirm.vue
This commit is contained in:
@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Notification\NotificationFlagManager;
|
||||
use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
|
||||
use libphonenumber\PhoneNumber;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
final class UpdateProfileCommand
|
||||
{
|
||||
@@ -23,11 +24,13 @@ final class UpdateProfileCommand
|
||||
public function __construct(
|
||||
#[PhonenumberConstraint]
|
||||
public ?PhoneNumber $phonenumber,
|
||||
#[Assert\Choice(choices: ['fr', 'nl'], message: 'Locale must be either "fr" or "nl"')]
|
||||
public string $locale = 'fr',
|
||||
) {}
|
||||
|
||||
public static function create(User $user, NotificationFlagManager $flagManager): self
|
||||
{
|
||||
$updateProfileCommand = new self($user->getPhonenumber());
|
||||
$updateProfileCommand = new self($user->getPhonenumber(), $user->getLocale());
|
||||
|
||||
foreach ($flagManager->getAllNotificationFlagProviders() as $provider) {
|
||||
$updateProfileCommand->setNotificationFlag(
|
||||
|
||||
@@ -18,6 +18,7 @@ final readonly class UpdateProfileCommandHandler
|
||||
public function updateProfile(User $user, UpdateProfileCommand $command): void
|
||||
{
|
||||
$user->setPhonenumber($command->phonenumber);
|
||||
$user->setLocale($command->locale);
|
||||
|
||||
foreach ($command->notificationFlags as $flag => $values) {
|
||||
$user->setNotificationImmediately($flag, $values['immediate_email']);
|
||||
|
||||
@@ -12,5 +12,12 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class UserGroupApiController extends ApiController {}
|
||||
class UserGroupApiController extends ApiController
|
||||
{
|
||||
protected function customizeQuery(string $action, Request $request, $query): void
|
||||
{
|
||||
$query->andWhere('e.active = TRUE');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\DataFixtures\ORM;
|
||||
|
||||
use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\LocationType;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
class LoadAdministrativeLocation extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
final public const ADMINISTRATIVE_LOCATION = 'administrative_location';
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 9000;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$o = new Location();
|
||||
/** @var LocationType $locationType */
|
||||
$locationType = $this->getReference(LoadLocationType::LOCATION_TYPE.'_0');
|
||||
$o->setLocationType($locationType);
|
||||
$o->setName('Commune de Bruxelles');
|
||||
$o->setAvailableForUsers(true);
|
||||
|
||||
$manager->persist($o);
|
||||
|
||||
$this->addReference(self::ADMINISTRATIVE_LOCATION, $o);
|
||||
echo "Adding one Administrative Location\n";
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,8 @@ class LoadLocationType extends AbstractFixture implements ContainerAwareInterfac
|
||||
{
|
||||
private ?ContainerInterface $container = null;
|
||||
|
||||
final public const LOCATION_TYPE = 'location_type';
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 52;
|
||||
@@ -53,13 +55,15 @@ class LoadLocationType extends AbstractFixture implements ContainerAwareInterfac
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($arr as $a) {
|
||||
foreach ($arr as $index => $a) {
|
||||
$locationType = (new LocationType())
|
||||
->setTitle($a['name'])
|
||||
->setAvailableForUsers(true)
|
||||
->setActive(true)
|
||||
->setAddressRequired($a['address_required']);
|
||||
$manager->persist($locationType);
|
||||
|
||||
$this->addReference(self::LOCATION_TYPE.'_'.$index, $locationType);
|
||||
}
|
||||
|
||||
$manager->flush();
|
||||
|
||||
41
src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUserJob.php
Normal file
41
src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUserJob.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\DataFixtures\ORM;
|
||||
|
||||
use Chill\MainBundle\Entity\UserJob;
|
||||
use Doctrine\Common\DataFixtures\AbstractFixture;
|
||||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
|
||||
class LoadUserJob extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
final public const USER_JOB = 'user_job';
|
||||
private array $socialWorker = ['en' => 'social worker', 'fr' => 'travailleur social'];
|
||||
|
||||
public function getOrder(): int
|
||||
{
|
||||
return 9000;
|
||||
}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
$o = new UserJob();
|
||||
$o->setLabel($this->socialWorker);
|
||||
|
||||
$manager->persist($o);
|
||||
|
||||
$this->addReference(self::USER_JOB, $o);
|
||||
echo "Adding one AccompanyingPeriod User Job\n";
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,12 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, nullable: false, options: ['default' => '[]', 'jsonb' => true])]
|
||||
private array $notificationFlags = [];
|
||||
|
||||
/**
|
||||
* User's preferred locale.
|
||||
*/
|
||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 5, nullable: false, options: ['default' => 'fr'])]
|
||||
private string $locale = 'fr';
|
||||
|
||||
/**
|
||||
* User constructor.
|
||||
*/
|
||||
@@ -716,7 +722,14 @@ class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInter
|
||||
|
||||
public function getLocale(): string
|
||||
{
|
||||
return 'fr';
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
public function setLocale(string $locale): self
|
||||
{
|
||||
$this->locale = $locale;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Assert\Callback]
|
||||
|
||||
@@ -37,4 +37,9 @@ class ChillDateTimeType extends AbstractType
|
||||
{
|
||||
return DateTimeType::class;
|
||||
}
|
||||
|
||||
public function getBlockPrefix(): string
|
||||
{
|
||||
return 'chill_datetime';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\DataMapper\ScopePickerDataMapper;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
@@ -32,65 +33,84 @@ use Symfony\Component\Security\Core\Security;
|
||||
* Allow to pick amongst available scope for the current
|
||||
* user.
|
||||
*
|
||||
* options :
|
||||
*
|
||||
* - `center`: the center of the entity
|
||||
* - `role` : the role of the user
|
||||
* Options:
|
||||
* - `role`: string, the role to check permissions for
|
||||
* - Either `subject`: object, entity to resolve centers from
|
||||
* - Or `center`: Center|array|null, the center(s) to check
|
||||
*/
|
||||
class ScopePickerType extends AbstractType
|
||||
{
|
||||
public function __construct(
|
||||
private readonly TranslatableStringHelperInterface $translatableStringHelper,
|
||||
private readonly AuthorizationHelperInterface $authorizationHelper,
|
||||
private readonly Security $security,
|
||||
private readonly TranslatableStringHelperInterface $translatableStringHelper,
|
||||
private readonly CenterResolverManagerInterface $centerResolverManager,
|
||||
) {}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$items = array_values(
|
||||
// Compute centers from subject
|
||||
$centers = $options['center'] ?? null;
|
||||
if (null === $centers && isset($options['subject'])) {
|
||||
$centers = $this->centerResolverManager->resolveCenters($options['subject']);
|
||||
}
|
||||
|
||||
if (null === $centers) {
|
||||
throw new \RuntimeException('Either "center" or "subject" must be provided');
|
||||
}
|
||||
|
||||
$reachableScopes = array_values(
|
||||
array_filter(
|
||||
$this->authorizationHelper->getReachableScopes(
|
||||
$this->security->getUser(),
|
||||
$options['role'],
|
||||
$options['center']
|
||||
$centers
|
||||
),
|
||||
static fn (Scope $s) => $s->isActive()
|
||||
)
|
||||
);
|
||||
|
||||
if (0 === \count($items)) {
|
||||
throw new \RuntimeException('no scopes are reachable. This form should not be shown to user');
|
||||
$builder->setAttribute('reachable_scopes_count', count($reachableScopes));
|
||||
|
||||
if (0 === count($reachableScopes)) {
|
||||
$builder->setAttribute('has_scopes', false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (1 !== \count($items)) {
|
||||
$builder->setAttribute('has_scopes', true);
|
||||
|
||||
if (1 !== count($reachableScopes)) {
|
||||
$builder->add('scope', EntityType::class, [
|
||||
'class' => Scope::class,
|
||||
'placeholder' => 'Choose the circle',
|
||||
'choice_label' => fn (Scope $c) => $this->translatableStringHelper->localize($c->getName()),
|
||||
'choices' => $items,
|
||||
'choices' => $reachableScopes,
|
||||
]);
|
||||
$builder->setDataMapper(new ScopePickerDataMapper());
|
||||
} else {
|
||||
$builder->add('scope', HiddenType::class, [
|
||||
'data' => $items[0]->getId(),
|
||||
'data' => $reachableScopes[0]->getId(),
|
||||
]);
|
||||
$builder->setDataMapper(new ScopePickerDataMapper($items[0]));
|
||||
$builder->setDataMapper(new ScopePickerDataMapper($reachableScopes[0]));
|
||||
}
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form, array $options)
|
||||
{
|
||||
$view->vars['fullWidth'] = true;
|
||||
// display of label is handled by the EntityType
|
||||
$view->vars['label'] = false;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver
|
||||
// create `center` option
|
||||
->setRequired('center')
|
||||
->setAllowedTypes('center', [Center::class, 'array', 'null'])
|
||||
// create ``role` option
|
||||
->setRequired('role')
|
||||
->setAllowedTypes('role', ['string']);
|
||||
->setAllowedTypes('role', ['string'])
|
||||
->setDefined('subject')
|
||||
->setAllowedTypes('subject', ['object'])
|
||||
->setDefined('center')
|
||||
->setAllowedTypes('center', [Center::class, 'array', 'null']);
|
||||
}
|
||||
}
|
||||
|
||||
43
src/Bundle/ChillMainBundle/Form/Type/UserLocaleType.php
Normal file
43
src/Bundle/ChillMainBundle/Form/Type/UserLocaleType.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Intl\Languages;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class UserLocaleType extends AbstractType
|
||||
{
|
||||
public function __construct(private readonly array $availableLanguages) {}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$choices = [];
|
||||
foreach ($this->availableLanguages as $languageCode) {
|
||||
$choices[Languages::getName($languageCode)] = $languageCode;
|
||||
}
|
||||
|
||||
$resolver->setDefaults([
|
||||
'choices' => $choices,
|
||||
'placeholder' => 'user.locale.placeholder',
|
||||
'required' => true,
|
||||
'label' => 'user.locale.label',
|
||||
'help' => 'user.locale.help',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getParent(): string
|
||||
{
|
||||
return ChoiceType::class;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Form;
|
||||
use Chill\MainBundle\Action\User\UpdateProfile\UpdateProfileCommand;
|
||||
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||
use Chill\MainBundle\Form\Type\NotificationFlagsType;
|
||||
use Chill\MainBundle\Form\Type\UserLocaleType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
@@ -26,6 +27,7 @@ class UpdateProfileType extends AbstractType
|
||||
->add('phonenumber', ChillPhoneNumberType::class, [
|
||||
'required' => false,
|
||||
])
|
||||
->add('locale', UserLocaleType::class)
|
||||
->add('notificationFlags', NotificationFlagsType::class)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Chill\MainBundle\Entity\UserJob;
|
||||
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||
use Chill\MainBundle\Form\Type\ChillPhoneNumberType;
|
||||
use Chill\MainBundle\Form\Type\PickCivilityType;
|
||||
use Chill\MainBundle\Repository\UserJobRepository;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
@@ -36,7 +37,7 @@ use Symfony\Component\Validator\Constraints\Regex;
|
||||
|
||||
class UserType extends AbstractType
|
||||
{
|
||||
public function __construct(private readonly TranslatableStringHelper $translatableStringHelper, protected ParameterBagInterface $parameterBag) {}
|
||||
public function __construct(private readonly TranslatableStringHelper $translatableStringHelper, protected ParameterBagInterface $parameterBag, private readonly UserJobRepository $userJobRepository) {}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
@@ -80,12 +81,7 @@ class UserType extends AbstractType
|
||||
'placeholder' => 'choose a job',
|
||||
'class' => UserJob::class,
|
||||
'choice_label' => fn (UserJob $c) => $this->translatableStringHelper->localize($c->getLabel()),
|
||||
'query_builder' => static function (EntityRepository $er) {
|
||||
$qb = $er->createQueryBuilder('uj');
|
||||
$qb->where('uj.active = TRUE');
|
||||
|
||||
return $qb;
|
||||
},
|
||||
'choices' => $this->loadAndSortUserJobs(),
|
||||
])
|
||||
->add('mainLocation', EntityType::class, [
|
||||
'label' => 'Main location',
|
||||
@@ -96,6 +92,7 @@ class UserType extends AbstractType
|
||||
'query_builder' => static function (EntityRepository $er) {
|
||||
$qb = $er->createQueryBuilder('l');
|
||||
$qb->orderBy('l.locationType');
|
||||
$qb->orderBy('l.name', 'ASC');
|
||||
$qb->where('l.availableForUsers = TRUE');
|
||||
|
||||
return $qb;
|
||||
@@ -155,6 +152,20 @@ class UserType extends AbstractType
|
||||
}
|
||||
}
|
||||
|
||||
private function loadAndSortUserJobs(): array
|
||||
{
|
||||
$items = $this->userJobRepository->findBy(['active' => true]);
|
||||
|
||||
usort(
|
||||
$items,
|
||||
fn ($a, $b) => mb_strtolower((string) $this->translatableStringHelper->localize($a->getLabel()))
|
||||
<=>
|
||||
mb_strtolower((string) $this->translatableStringHelper->localize($b->getLabel()))
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OptionsResolverInterface $resolver
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,8 @@ use Symfony\Component\Mime\Email;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
// use Symfony\Component\Translation\LocaleSwitcher;
|
||||
|
||||
readonly class NotificationMailer
|
||||
{
|
||||
public function __construct(
|
||||
@@ -31,6 +33,7 @@ readonly class NotificationMailer
|
||||
private LoggerInterface $logger,
|
||||
private MessageBusInterface $messageBus,
|
||||
private TranslatorInterface $translator,
|
||||
// private LocaleSwitcher $localeSwitcher,
|
||||
) {}
|
||||
|
||||
public function postPersistComment(NotificationComment $comment, PostPersistEventArgs $eventArgs): void
|
||||
@@ -56,7 +59,7 @@ readonly class NotificationMailer
|
||||
$email
|
||||
->to($dest->getEmail())
|
||||
->subject('Re: '.$comment->getNotification()->getTitle())
|
||||
->textTemplate('@ChillMain/Notification/email_notification_comment_persist.fr.md.twig')
|
||||
->textTemplate('@ChillMain/Notification/email_notification_comment_persist.md.twig')
|
||||
->context([
|
||||
'comment' => $comment,
|
||||
'dest' => $dest,
|
||||
@@ -137,13 +140,53 @@ readonly class NotificationMailer
|
||||
return;
|
||||
}
|
||||
|
||||
// Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2):
|
||||
/*
|
||||
$this->localeSwitcher->runWithLocale($addressee->getLocale(), function () use ($notification, $addressee) {
|
||||
if ($notification->isSystem()) {
|
||||
$email = new Email();
|
||||
$email->text($notification->getMessage());
|
||||
} else {
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content.md.twig')
|
||||
->context([
|
||||
'notification' => $notification,
|
||||
'dest' => $addressee,
|
||||
]);
|
||||
}
|
||||
|
||||
$email
|
||||
->subject($notification->getTitle())
|
||||
->to($addressee->getEmail());
|
||||
|
||||
try {
|
||||
$this->mailer->send($email);
|
||||
$this->logger->info('[NotificationMailer] Email sent successfully', [
|
||||
'notification_id' => $notification->getId(),
|
||||
'addressee_email' => $addressee->getEmail(),
|
||||
'locale' => $addressee->getLocale(),
|
||||
]);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->warning('[NotificationMailer] Could not send an email notification', [
|
||||
'to' => $addressee->getEmail(),
|
||||
'notification_id' => $notification->getId(),
|
||||
'error_message' => $e->getMessage(),
|
||||
'error_trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
// Current implementation:
|
||||
if ($notification->isSystem()) {
|
||||
$email = new Email();
|
||||
$email->text($notification->getMessage());
|
||||
} else {
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content.fr.md.twig')
|
||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content.md.twig')
|
||||
->context([
|
||||
'notification' => $notification,
|
||||
'dest' => $addressee,
|
||||
@@ -182,9 +225,43 @@ readonly class NotificationMailer
|
||||
return;
|
||||
}
|
||||
|
||||
// Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2):
|
||||
/*
|
||||
$this->localeSwitcher->runWithLocale($user->getLocale(), function () use ($user, $notifications) {
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->htmlTemplate('@ChillMain/Notification/email_daily_digest.md.twig')
|
||||
->context([
|
||||
'user' => $user,
|
||||
'notifications' => $notifications,
|
||||
'notification_count' => count($notifications),
|
||||
])
|
||||
->subject($this->translator->trans('notification.Daily Notification Digest'))
|
||||
->to($user->getEmail());
|
||||
|
||||
try {
|
||||
$this->mailer->send($email);
|
||||
$this->logger->info('[NotificationMailer] Daily digest email sent successfully', [
|
||||
'user_email' => $user->getEmail(),
|
||||
'notification_count' => count($notifications),
|
||||
'locale' => $user->getLocale(),
|
||||
]);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->warning('[NotificationMailer] Could not send daily digest email', [
|
||||
'to' => $user->getEmail(),
|
||||
'notification_count' => count($notifications),
|
||||
'error_message' => $e->getMessage(),
|
||||
'error_trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
// Current implementation:
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->htmlTemplate('@ChillMain/Notification/email_daily_digest.fr.md.twig')
|
||||
->htmlTemplate('@ChillMain/Notification/email_daily_digest.md.twig')
|
||||
->context([
|
||||
'user' => $user,
|
||||
'notifications' => $notifications,
|
||||
@@ -222,7 +299,7 @@ readonly class NotificationMailer
|
||||
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content_to_email.fr.md.twig')
|
||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content_to_email.md.twig')
|
||||
->context([
|
||||
'notification' => $notification,
|
||||
'dest' => $emailAddress,
|
||||
|
||||
@@ -311,3 +311,32 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chill_datetime_label %}
|
||||
<label for="{{ form.date.vars.id }}" class="col-form-label col-sm-4 required">
|
||||
{{ "Date"|trans }}
|
||||
</label>
|
||||
{% endblock %}
|
||||
|
||||
{% block chill_datetime_widget %}
|
||||
<div class="col-sm-8 d-flex align-items-start gap-2">
|
||||
{#date#}
|
||||
{{ form_widget(form.date, {
|
||||
attr: { class: 'form-control', style: 'flex: 1 1 auto;' }
|
||||
}) }}
|
||||
{#time#}
|
||||
{{ form_widget(form.time, {
|
||||
attr: {
|
||||
class: 'form-select',
|
||||
style: 'flex: 0 0 200px; max-width: 200px; white-space: nowrap; padding:0;'
|
||||
}
|
||||
}) }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block chill_datetime_row %}
|
||||
<div class="mb-3 row">
|
||||
{{ block('chill_datetime_label') }}
|
||||
{{ block('chill_datetime_widget') }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<img class="logo" src="{{ asset('build/images/logo-chill-outil-accompagnement_white.png') }}">
|
||||
<img class="logo" alt="{{ 'login_page.logo_alt'|trans }}" src="{{ asset('build/images/logo-chill-outil-accompagnement_white.png') }}">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="{{ app.request.locale }}">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>
|
||||
@@ -35,10 +35,10 @@
|
||||
|
||||
<form method="POST" action="{{ path('login_check') }}">
|
||||
<label for="_username">{{ 'Username'|trans }}</label>
|
||||
<input type="text" name="_username" value="{{ last_username }}" />
|
||||
<input type="text" name="_username" value="{{ last_username }}" id="_username" />
|
||||
<br/>
|
||||
<label for="_password">{{ 'Password'|trans }}</label>
|
||||
<input type="password" name="_password" />
|
||||
<input type="password" name="_password" id="_password" />
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}" />
|
||||
<br/>
|
||||
<button type="submit" name="login">{{ 'Login'|trans }}</button>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
Vous pouvez visualiser la notification et y répondre ici:
|
||||
|
||||
{{ absolute_url(path('chill_main_notification_show', {'_locale': 'fr', 'id': notification.id }, false)) }}
|
||||
{{ absolute_url(path('chill_main_notification_show', {'_locale': dest.locale, 'id': notification.id }, false)) }}
|
||||
|
||||
--
|
||||
Le logiciel Chill
|
||||
@@ -13,7 +13,7 @@ Commentaire:
|
||||
|
||||
Vous pouvez visualiser la notification et y répondre ici:
|
||||
|
||||
{{ absolute_url(path('chill_main_notification_show', {'_locale': 'fr', 'id': comment.notification.id }, false)) }}
|
||||
{{ absolute_url(path('chill_main_notification_show', {'_locale': dest.locale, 'id': comment.notification.id }, false)) }}
|
||||
|
||||
--
|
||||
Le logiciel Chill
|
||||
@@ -44,6 +44,7 @@
|
||||
<div>
|
||||
{{ form_start(form) }}
|
||||
{{ form_row(form.phonenumber) }}
|
||||
{{ form_row(form.locale) }}
|
||||
|
||||
<h2 class="mb-4">{{ 'user.profile.notification_preferences'|trans }}</h2>
|
||||
<table class="table table-striped align-middle">
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{{ dest.label }},
|
||||
|
||||
Un suivi "{{ workflow.text }}" a atteint une nouvelle étape: {{ workflow.text }}
|
||||
{{ 'workflow.notification.content.new_step_reached'|trans({'%workflow%': workflow.text}) }}
|
||||
|
||||
Titre du workflow: "{{ title }}".
|
||||
{{ 'workflow.notification.content.workflow_title'|trans({'%title%': title}) }}
|
||||
{% if is_dest %}
|
||||
|
||||
Vous êtes invités à valider cette étape au plus tôt.
|
||||
{{ 'workflow.notification.content.validation_needed'|trans }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
Vous pouvez visualiser le workflow sur cette page:
|
||||
{{ 'workflow.notification.content.view_workflow'|trans }}
|
||||
|
||||
{{ absolute_url(path('chill_main_workflow_show', {'id': entity_workflow.id, '_locale': 'fr'})) }}
|
||||
{{ absolute_url(path('chill_main_workflow_show', {'id': entity_workflow.id, '_locale': dest.locale|default('fr')})) }}
|
||||
|
||||
Cordialement,
|
||||
{{ 'workflow.notification.content.regards'|trans }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{%- if is_dest -%}
|
||||
Un suivi {{ workflow.text }} demande votre attention: {{ title }}
|
||||
{{ 'workflow.notification.title.attention_needed'|trans({'%workflow%': workflow.text, '%title%': title}) }}
|
||||
{%- else -%}
|
||||
Un suivi {{ workflow.text }} a atteint une nouvelle étape: {{ place.text }}: {{ title }}
|
||||
{{ 'workflow.notification.title.new_step'|trans({'%workflow%': workflow.text, '%place%': place.text, '%title%': title}) }}
|
||||
{%- endif -%}
|
||||
|
||||
@@ -16,11 +16,13 @@ use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
// use Symfony\Component\Translation\LocaleSwitcher;
|
||||
|
||||
class RecoverPasswordHelper
|
||||
{
|
||||
final public const RECOVER_PASSWORD_ROUTE = 'password_recover';
|
||||
|
||||
public function __construct(private readonly TokenManager $tokenManager, private readonly UrlGeneratorInterface $urlGenerator, private readonly MailerInterface $mailer) {}
|
||||
public function __construct(private readonly TokenManager $tokenManager, private readonly UrlGeneratorInterface $urlGenerator, private readonly MailerInterface $mailer/* , private readonly LocaleSwitcher $localeSwitcher */) {}
|
||||
|
||||
/**
|
||||
* @param bool $absolute
|
||||
@@ -53,6 +55,24 @@ class RecoverPasswordHelper
|
||||
throw new \UnexpectedValueException('No emaail associated to the user');
|
||||
}
|
||||
|
||||
// Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2):
|
||||
/*
|
||||
$this->localeSwitcher->runWithLocale($user->getLocale(), function () use ($user, $expiration, $template, $templateParameters, $emailSubject, $additionalUrlParameters) {
|
||||
$email = (new TemplatedEmail())
|
||||
->subject($emailSubject)
|
||||
->to($user->getEmail())
|
||||
->textTemplate($template)
|
||||
->context([
|
||||
'user' => $user,
|
||||
'url' => $this->generateUrl($user, $expiration, true, $additionalUrlParameters),
|
||||
...$templateParameters,
|
||||
]);
|
||||
|
||||
$this->mailer->send($email);
|
||||
});
|
||||
*/
|
||||
|
||||
// Current implementation:
|
||||
$email = (new TemplatedEmail())
|
||||
->subject($emailSubject)
|
||||
->to($user->getEmail())
|
||||
|
||||
@@ -41,6 +41,7 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
|
||||
'isAbsent' => false,
|
||||
'absenceStart' => null,
|
||||
'absenceEnd' => null,
|
||||
'enabled' => true,
|
||||
];
|
||||
|
||||
public function __construct(private readonly UserRender $userRender, private readonly ClockInterface $clock) {}
|
||||
@@ -108,6 +109,7 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
|
||||
'isAbsent' => $object->isAbsent(),
|
||||
'absenceStart' => $this->normalizer->normalize($object->getAbsenceStart(), $format, $absenceDatesContext),
|
||||
'absenceEnd' => $this->normalizer->normalize($object->getAbsenceEnd(), $format, $absenceDatesContext),
|
||||
'enabled' => $object->isEnabled(),
|
||||
];
|
||||
|
||||
if ('docgen' === $format) {
|
||||
|
||||
@@ -26,6 +26,7 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
'with_delimiter' => false,
|
||||
'has_no_address' => false,
|
||||
'multiline' => true,
|
||||
'separator' => ' — ',
|
||||
/* deprecated */
|
||||
'extended_infos' => false,
|
||||
];
|
||||
@@ -114,7 +115,9 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
|
||||
public function renderString($addr, array $options): string
|
||||
{
|
||||
return implode(' — ', $this->renderLines($addr));
|
||||
$opts = [...self::DEFAULT_OPTIONS, ...$options];
|
||||
|
||||
return implode($opts['separator'], $this->renderLines($addr));
|
||||
}
|
||||
|
||||
public function supports($entity, array $options): bool
|
||||
|
||||
@@ -52,7 +52,7 @@ class CommentRender implements ChillEntityRenderInterface
|
||||
|
||||
public function renderString($entity, array $options): string
|
||||
{
|
||||
return $entity->getComment();
|
||||
return (string) $entity->getComment();
|
||||
}
|
||||
|
||||
public function supports($entity, array $options): bool
|
||||
|
||||
@@ -11,11 +11,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace Form\Type;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
|
||||
@@ -39,11 +39,11 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function estBuildOneScopeIsSuccessful()
|
||||
public function testBuildOneScopeIsSuccessful()
|
||||
{
|
||||
$form = $this->factory->create(ScopePickerType::class, null, [
|
||||
'center' => new Center(),
|
||||
'role' => 'ONE_SCOPE',
|
||||
'center' => [],
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
@@ -54,8 +54,8 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
public function testBuildThreeScopesIsSuccessful()
|
||||
{
|
||||
$form = $this->factory->create(ScopePickerType::class, null, [
|
||||
'center' => new Center(),
|
||||
'role' => 'THREE_SCOPE',
|
||||
'center' => [],
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
@@ -66,8 +66,8 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
public function testBuildTwoScopesIsSuccessful()
|
||||
{
|
||||
$form = $this->factory->create(ScopePickerType::class, null, [
|
||||
'center' => new Center(),
|
||||
'role' => 'TWO_SCOPE',
|
||||
'center' => [],
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
@@ -101,10 +101,13 @@ final class ScopePickerTypeTest extends TypeTestCase
|
||||
static fn ($args) => $args[0]['fr']
|
||||
);
|
||||
|
||||
$centerResolverManager = $this->prophesize(CenterResolverManagerInterface::class);
|
||||
|
||||
$type = new ScopePickerType(
|
||||
$translatableStringHelper->reveal(),
|
||||
$authorizationHelper->reveal(),
|
||||
$security->reveal(),
|
||||
$translatableStringHelper->reveal()
|
||||
$centerResolverManager->reveal()
|
||||
);
|
||||
|
||||
// add the mocks for creating EntityType
|
||||
|
||||
@@ -103,6 +103,7 @@ final class UserNormalizerTest extends TestCase
|
||||
'main_center' => ['context' => Center::class],
|
||||
'absenceStart' => ['context' => \DateTimeImmutable::class],
|
||||
'absenceEnd' => ['context' => \DateTimeImmutable::class],
|
||||
'enabled' => true,
|
||||
]];
|
||||
|
||||
yield [$userNoPhone, 'docgen', ['docgen:expects' => User::class],
|
||||
@@ -124,6 +125,7 @@ final class UserNormalizerTest extends TestCase
|
||||
'main_center' => ['context' => Center::class],
|
||||
'absenceStart' => ['context' => \DateTimeImmutable::class],
|
||||
'absenceEnd' => ['context' => \DateTimeImmutable::class],
|
||||
'enabled' => true,
|
||||
]];
|
||||
|
||||
yield [null, 'docgen', ['docgen:expects' => User::class], [
|
||||
@@ -144,6 +146,7 @@ final class UserNormalizerTest extends TestCase
|
||||
'main_center' => ['context' => Center::class],
|
||||
'absenceStart' => null,
|
||||
'absenceEnd' => null,
|
||||
'enabled' => true,
|
||||
]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Workflow\Event\Event;
|
||||
use Symfony\Component\Workflow\Registry;
|
||||
|
||||
// use Symfony\Component\Translation\LocaleSwitcher;
|
||||
|
||||
final readonly class NotificationToUserGroupsOnTransition implements EventSubscriberInterface
|
||||
{
|
||||
public function __construct(
|
||||
@@ -31,6 +33,7 @@ final readonly class NotificationToUserGroupsOnTransition implements EventSubscr
|
||||
private MailerInterface $mailer,
|
||||
private EntityManagerInterface $entityManager,
|
||||
private EntityWorkflowManager $entityWorkflowManager,
|
||||
// private LocaleSwitcher $localeSwitcher,
|
||||
) {}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
@@ -87,6 +90,24 @@ final readonly class NotificationToUserGroupsOnTransition implements EventSubscr
|
||||
'title' => $title,
|
||||
];
|
||||
|
||||
// Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2):
|
||||
// Note: This sends emails to user groups, not individual users, so locale switching may use default locale
|
||||
/*
|
||||
$this->localeSwitcher->runWithLocale('fr', function () use ($context, $userGroup) {
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->htmlTemplate('@ChillMain/Workflow/workflow_notification_on_transition_completed_content_to_user_group.fr.txt.twig')
|
||||
->context($context)
|
||||
->subject(
|
||||
$this->engine->render('@ChillMain/Workflow/workflow_notification_on_transition_completed_title.fr.txt.twig', $context)
|
||||
)
|
||||
->to($userGroup->getEmail());
|
||||
|
||||
$this->mailer->send($email);
|
||||
});
|
||||
*/
|
||||
|
||||
// Current implementation:
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->htmlTemplate('@ChillMain/Workflow/workflow_notification_on_transition_completed_content_to_user_group.fr.txt.twig')
|
||||
|
||||
@@ -12,6 +12,12 @@ services:
|
||||
tags:
|
||||
- { name: form.type, alias: translatable_string }
|
||||
|
||||
Chill\MainBundle\Form\Type\UserLocaleType:
|
||||
arguments:
|
||||
- "%chill_main.available_languages%"
|
||||
tags:
|
||||
- { name: form.type }
|
||||
|
||||
chill.main.form.type.select2choice:
|
||||
class: Chill\MainBundle\Form\Type\Select2ChoiceType
|
||||
tags:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20251022140718 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add locale field to users table for user language preferences';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE users ADD locale VARCHAR(5) DEFAULT \'fr\' NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE users DROP locale');
|
||||
}
|
||||
}
|
||||
7
src/Bundle/ChillMainBundle/translations/date.nl.yml
Normal file
7
src/Bundle/ChillMainBundle/translations/date.nl.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
#diff ago. See doc here : http://twig.sensiolabs.org/doc/extensions/date.html
|
||||
diff.ago.second: '{0} Nu | {1} Een seconde geleden | ]1,Inf] %count% seconden geleden'
|
||||
diff.ago.minute: '{0} Nu | {1} Een minuut geleden | ]1,Inf] %count% minuten geleden'
|
||||
diff.ago.hour: '{1} Een uur geleden | ]1,Inf] %count% uur geleden'
|
||||
diff.ago.day: '{1} Gisteren | ]1,Inf] %count% dagen geleden'
|
||||
diff.ago.month: '{1} Vorige maand | ]1,Inf] %count% maanden geleden'
|
||||
diff.ago.year: '{1} Een jaar geleden | ]1,Inf] %count% jaar geleden'
|
||||
@@ -0,0 +1,155 @@
|
||||
years_old: >-
|
||||
{age, plural,
|
||||
one {# jaar}
|
||||
many {# jaar}
|
||||
other {# jaar}
|
||||
}
|
||||
|
||||
user_group:
|
||||
with_count_users: >-
|
||||
{count, plural,
|
||||
=0 {Geen lid}
|
||||
one {1 gebruiker}
|
||||
many {# gebruikers}
|
||||
other {# gebruikers}
|
||||
}
|
||||
user_removed: Gebruiker {user} is succesvol verwijderd uit groep {user_group}
|
||||
user_added: Gebruiker {user} is succesvol toegevoegd aan groep {user_group}
|
||||
label_related_to_user_job: Groep {job} (Beroepsgroep)
|
||||
|
||||
notification:
|
||||
My notifications with counter: >-
|
||||
{nb, plural,
|
||||
=0 {Mijn meldingen}
|
||||
one {# melding}
|
||||
few {# meldingen}
|
||||
other {# meldingen}
|
||||
}
|
||||
|
||||
counter total notifications: >-
|
||||
{total, plural,
|
||||
=0 {Geen melding}
|
||||
one {# melding}
|
||||
few {# meldingen}
|
||||
other {# meldingen}
|
||||
}
|
||||
|
||||
counter unread notifications: >-
|
||||
{unread, plural,
|
||||
=0 {Geen ongelezen}
|
||||
one {# ongelezen}
|
||||
few {# ongelezen}
|
||||
other {# ongelezen}
|
||||
}
|
||||
counter comments: >-
|
||||
{nb, plural,
|
||||
=0 {Geen opmerking}
|
||||
one {# opmerking}
|
||||
few {# opmerkingen}
|
||||
other {# opmerkingen}
|
||||
}
|
||||
|
||||
daily_notifications: >-
|
||||
{notification_count, plural,
|
||||
=1 {Hier is uw melding van de dag:}
|
||||
other {Hier zijn uw # meldingen van de dag:}
|
||||
}
|
||||
|
||||
workflow:
|
||||
My workflows with counter: >-
|
||||
{wc, plural,
|
||||
=0 {Mijn workflows}
|
||||
one {# workflow}
|
||||
few {# workflows}
|
||||
other {# workflows}
|
||||
}
|
||||
signature:
|
||||
signed_statement: 'Handtekening toegepast op {datetime, date, short} om {datetime, time, short}'
|
||||
rejected_statement: 'Handtekening geweigerd op {datetime, date, short} om {datetime, time, short}'
|
||||
canceled_statement: 'Handtekening geannuleerd op {datetime, date, short} om {datetime, time, short}'
|
||||
On hold by: In afwachting door {by}
|
||||
signature_required_title: >-
|
||||
{nb_signatures, plural,
|
||||
=0 {Geen handtekening gevraagd}
|
||||
one {Handtekening gevraagd}
|
||||
other {Handtekeningen gevraagd}
|
||||
}
|
||||
signatures_title: >-
|
||||
{nb_signatures, plural,
|
||||
=0 {Geen handtekening}
|
||||
one {Handtekening}
|
||||
other {Handtekeningen}
|
||||
}
|
||||
pending_signatures: >-
|
||||
{nb_signatures, plural,
|
||||
=0 {Geen handtekening gevraagd}
|
||||
one {Eén handtekening gevraagd}
|
||||
other {# handtekeningen gevraagd}
|
||||
}
|
||||
send_external_message:
|
||||
document_available_until: De link is geldig tot {expiration, date, long} om {expiration, time, short}.
|
||||
explanation: '{sender} stuurt u documenten.'
|
||||
button_content: 'Documenten bekijken die zijn verzonden door {sender}'
|
||||
confidentiality: Wij vestigen uw aandacht op het feit dat deze documenten vertrouwelijk zijn.
|
||||
see_doc_action_description: 'Vertrouwelijke documenten bekijken die zijn verzonden door {sender}'
|
||||
|
||||
external_views:
|
||||
title: >-
|
||||
{numberOfSends, plural,
|
||||
=0 {In afwachting van raadpleging}
|
||||
=1 {In afwachting van raadpleging}
|
||||
other {In afwachting van raadplegingen}
|
||||
}
|
||||
last_view_at: Laatst bekeken op {at, date, long} om {at, time, short}
|
||||
number_of_views: >-
|
||||
{numberOfViews, plural,
|
||||
=0 {De deling is nooit bekeken}
|
||||
=1 {De deling is één keer bekeken}
|
||||
other {De deling is # keer bekeken}
|
||||
}
|
||||
public_link:
|
||||
shared_explanation_until_remaining: >-
|
||||
Deze deling is actief tot {expireAt, date, long} om {expireAt, time, short}. {viewsCount, plural,
|
||||
=0 {Deze deling is nog niet bekeken}
|
||||
one {Deze deling is één keer bekeken}
|
||||
other {Deze deling is # keer bekeken}
|
||||
}, {viewsRemaining, plural,
|
||||
=0 {er zijn geen weergaven meer mogelijk.}
|
||||
one {er is nog één weergave mogelijk.}
|
||||
other {er zijn nog # weergaven mogelijk.}
|
||||
}
|
||||
|
||||
duration:
|
||||
minute: >-
|
||||
{m, plural,
|
||||
=0 {Geen duur}
|
||||
one {# minuut}
|
||||
few {# minuten}
|
||||
other {# minuten}
|
||||
}
|
||||
hour: >-
|
||||
{h, plural,
|
||||
=0 {Geen duur}
|
||||
one {# uur}
|
||||
few {# uur}
|
||||
other {# uur}
|
||||
}
|
||||
day: >-
|
||||
{d, plural,
|
||||
=0 {Geen duur}
|
||||
one {# dag}
|
||||
few {# dagen}
|
||||
other {# dagen}
|
||||
}
|
||||
|
||||
filter_order:
|
||||
by_date:
|
||||
From: Vanaf {from_date, date, long}
|
||||
To: Tot {to_date, date, long}
|
||||
By: Filteren op
|
||||
Search: Zoeken in de lijst
|
||||
By date: Filteren op datum
|
||||
search_box: Filteren op inhoud
|
||||
|
||||
absence:
|
||||
You are listed as absent, as of {date, date, short}: Uw afwezigheid is aangegeven vanaf {date, date, short}
|
||||
@@ -56,6 +56,10 @@ user:
|
||||
no job: Pas de métier assigné
|
||||
no scope: Pas de service assigné
|
||||
notification_preferences: Préférences pour mes notifications
|
||||
locale:
|
||||
label: Langue de communication
|
||||
help: Langue utilisée pour les notifications par email et autres communications.
|
||||
placeholder: Choisissez une langue
|
||||
|
||||
user_group:
|
||||
inactive: Inactif
|
||||
@@ -668,6 +672,17 @@ workflow:
|
||||
reject_are_you_sure: Êtes-vous sûr de vouloir rejeter la signature de %signer%
|
||||
waiting_for: En attente de modification de l'état de la signature
|
||||
|
||||
notification:
|
||||
title:
|
||||
attention_needed: "Attention requise dans le workflow %workflow% pour %title%"
|
||||
new_step: "Nouvelle étape dans le workflow %workflow% (%place%) pour %title%"
|
||||
content:
|
||||
new_step_reached: "Une nouvelle étape a été atteinte dans le workflow %workflow%."
|
||||
workflow_title: "Titre du workflow : %title%"
|
||||
validation_needed: "Votre validation est nécessaire pour cette étape."
|
||||
view_workflow: "Vous pouvez consulter le workflow ici :"
|
||||
regards: "Cordialement,"
|
||||
|
||||
attachments:
|
||||
title: Pièces jointes
|
||||
no_attachment: Aucune pièce jointe
|
||||
@@ -747,7 +762,22 @@ notification:
|
||||
greeting: "Bonjour %user%"
|
||||
intro: "Vous avez reçu %notification_count% nouvelle(s) notification(s)."
|
||||
view_notification: "Vous pouvez visualiser la notification et y répondre ici:"
|
||||
signature: "Le logiciel Chill"
|
||||
signature: "L'équipe Chill"
|
||||
|
||||
daily_notifications: "{1}Vous avez 1 nouvelle notification.|]1,Inf[Vous avez %notification_count% nouvelles notifications."
|
||||
|
||||
docgen:
|
||||
failure_email:
|
||||
"The generation of a document failed": "La génération d'un document a échoué"
|
||||
"The generation of the document %template_name% failed": "La génération du document %template_name% a échoué"
|
||||
"Forward this email to your administrator for solving": "Transmettez cet email à votre administrateur pour résolution"
|
||||
"References": "Références"
|
||||
"The following errors were encoutered": "Les erreurs suivantes ont été rencontrées"
|
||||
data_dump_email:
|
||||
subject: "Export de données disponible"
|
||||
"Dear": "Cher utilisateur,"
|
||||
"data_dump_ready_and_attached": "Votre export de données est prêt et joint à cet email."
|
||||
"filename": "Nom du fichier : %filename%"
|
||||
|
||||
CHILL_MAIN_COMPOSE_EXPORT: Exécuter des exports et les sauvegarder
|
||||
CHILL_MAIN_GENERATE_SAVED_EXPORT: Exécuter et modifier des exports préalablement sauvegardés
|
||||
@@ -1006,3 +1036,6 @@ nav:
|
||||
bottom: "Bas"
|
||||
|
||||
|
||||
|
||||
login_page:
|
||||
logo_alt: "Logo de Chill"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
45
src/Bundle/ChillMainBundle/translations/validators.nl.yml
Normal file
45
src/Bundle/ChillMainBundle/translations/validators.nl.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
# role_scope constraint
|
||||
# scope presence
|
||||
The role "%role%" require to be associated with a scope.: De rol "%role%" moet gekoppeld zijn aan een dienst.
|
||||
The role "%role%" should not be associated with a scope.: De rol "%role%" mag niet gekoppeld zijn aan een dienst.
|
||||
"The password must contains one letter, one capitalized letter, one number and one special character as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed.": "Het wachtwoord moet een hoofdletter, een kleine letter en ten minste één speciaal teken bevatten uit *[@#$%!,;:+\"'-/{}~=µ()£]). Andere tekens zijn toegestaan."
|
||||
The password fields must match: De wachtwoorden moeten overeenkomen
|
||||
The password must be greater than {{ limit }} characters: "[1,Inf] Het wachtwoord moet minstens {{ limit }} tekens bevatten"
|
||||
|
||||
A permission is already present for the same role and scope: Er bestaat al een toestemming voor dezelfde rol en dienst.
|
||||
|
||||
#UserCircleConsistency
|
||||
"{{ username }} is not allowed to see entities published in this circle": "{{ username }} is niet bevoegd om het element te zien dat in deze dienst is gepubliceerd."
|
||||
|
||||
The user in cc cannot be a dest user in the same workflow step: Een gebruiker in Cc kan geen gebruiker zijn die valideert.
|
||||
|
||||
#password request
|
||||
This username or email does not exists: Deze gebruikersnaam of e-mail bestaat niet in de database
|
||||
|
||||
#phonenumber
|
||||
This is not a landline phonenumber: Dit nummer is geen geldig vast telefoonnummer
|
||||
This is not a mobile phonenumber: Dit nummer is geen geldig mobiel nummer
|
||||
This is not a valid phonenumber: Dit telefoonnummer is niet geldig
|
||||
|
||||
address:
|
||||
street1-should-be-set: Er moet een adresregel aanwezig zijn
|
||||
date-should-be-set: De begindatum van geldigheid moet aanwezig zijn
|
||||
postcode-should-be-set: De postcode moet worden ingevuld
|
||||
|
||||
notification:
|
||||
At least one addressee: Geef ten minste één geadresseerde op
|
||||
Title must be defined: Er moet een titel worden aangegeven
|
||||
Comment content might not be blank: De opmerking kan niet leeg zijn
|
||||
|
||||
workflow:
|
||||
You must add at least one dest user or email: Geef ten minste één geadresseerde of een e-mailadres op
|
||||
The user in cc cannot be a dest user in the same workflow step: De gebruiker in kopie kan niet aanwezig zijn in de gebruikers die de volgende stap zullen valideren
|
||||
transition_has_destinee_if_sent_external: Geef een geadresseerde van de externe verzending op
|
||||
transition_destinee_not_necessary: Voor deze transitie kunt u geen externe geadresseerden opgeven
|
||||
You must add a destinee for signing: Geef een gebruiker of een gebruiker op voor ondertekening
|
||||
|
||||
rolling_date:
|
||||
When fixed date is selected, you must provide a date: Geef de gekozen vaste datum op
|
||||
|
||||
user:
|
||||
absence_end_requires_start: U kunt geen einddatum van afwezigheid invullen zonder begindatum.
|
||||
Reference in New Issue
Block a user