diff --git a/config/packages/chill.yaml b/config/packages/chill.yaml index 0f5aa08b7..26f91feb5 100644 --- a/config/packages/chill.yaml +++ b/config/packages/chill.yaml @@ -1,5 +1,5 @@ chill_main: - available_languages: [ '%env(resolve:LOCALE)%', 'en' ] + available_languages: [ '%env(resolve:LOCALE)%', 'en', 'nl' ] available_countries: ['BE', 'FR'] top_banner: visible: false diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/OnGenerationFails.php b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/OnGenerationFails.php index b9d538a63..a950b88c0 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/OnGenerationFails.php +++ b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/OnGenerationFails.php @@ -25,6 +25,8 @@ use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Contracts\Translation\TranslatorInterface; +// use Symfony\Component\Translation\LocaleSwitcher; + /** * @see OnGenerationFailsTest for test suite */ @@ -40,6 +42,7 @@ final readonly class OnGenerationFails implements EventSubscriberInterface private StoredObjectRepositoryInterface $storedObjectRepository, private TranslatorInterface $translator, private UserRepositoryInterface $userRepository, + // private LocaleSwitcher $localeSwitcher, ) {} public static function getSubscribedEvents() @@ -118,6 +121,25 @@ final readonly class OnGenerationFails implements EventSubscriberInterface return; } + // Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2): + /* + $this->localeSwitcher->runWithLocale($creator->getLocale(), function () use ($message, $errors, $template, $creator) { + $email = (new TemplatedEmail()) + ->to($message->getSendResultToEmail()) + ->subject($this->translator->trans('docgen.failure_email.The generation of a document failed')) + ->textTemplate('@ChillDocGenerator/Email/on_generation_failed_email.txt.twig') + ->context([ + 'errors' => $errors, + 'template' => $template, + 'creator' => $creator, + 'stored_object_id' => $message->getDestinationStoredObjectId(), + ]); + + $this->mailer->send($email); + }); + */ + + // Current implementation: $email = (new TemplatedEmail()) ->to($message->getSendResultToEmail()) ->subject($this->translator->trans('docgen.failure_email.The generation of a document failed')) diff --git a/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php index 9dd20af91..a67f5a68f 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php +++ b/src/Bundle/ChillDocGeneratorBundle/Service/Messenger/RequestGenerationHandler.php @@ -27,6 +27,8 @@ use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Contracts\Translation\TranslatorInterface; +// use Symfony\Component\Translation\LocaleSwitcher; + /** * Handle the request of document generation. */ @@ -46,6 +48,7 @@ class RequestGenerationHandler implements MessageHandlerInterface private readonly MailerInterface $mailer, private readonly TranslatorInterface $translator, private readonly StoredObjectManagerInterface $storedObjectManager, + // private readonly LocaleSwitcher $localeSwitcher, ) {} public function __invoke(RequestGenerationMessage $message) @@ -122,6 +125,30 @@ class RequestGenerationHandler implements MessageHandlerInterface private function sendDataDump(StoredObject $destinationStoredObject, RequestGenerationMessage $message): void { + // Implementation with LocaleSwitcher (commented out - to be activated after migration to sf7.2): + // Note: This method sends emails to admin addresses, not user addresses, so locale switching may not be needed + /* + $this->localeSwitcher->runWithLocale('fr', function () use ($destinationStoredObject, $message) { + // Get the content of the document + $content = $this->storedObjectManager->read($destinationStoredObject); + $filename = $destinationStoredObject->getFilename(); + $contentType = $destinationStoredObject->getType(); + + // Create the email with the document as an attachment + $email = (new TemplatedEmail()) + ->to($message->getSendResultToEmail()) + ->textTemplate('@ChillDocGenerator/Email/send_data_dump_to_admin.txt.twig') + ->context([ + 'filename' => $filename, + ]) + ->subject($this->translator->trans('docgen.data_dump_email.subject')) + ->attach($content, $filename, $contentType); + + $this->mailer->send($email); + }); + */ + + // Current implementation: // Get the content of the document $content = $this->storedObjectManager->read($destinationStoredObject); $filename = $destinationStoredObject->getFilename(); diff --git a/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommand.php b/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommand.php index f0751cb58..061f8e55a 100644 --- a/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommand.php +++ b/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommand.php @@ -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( diff --git a/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommandHandler.php b/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommandHandler.php index 4c46e686e..08684b8c6 100644 --- a/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommandHandler.php +++ b/src/Bundle/ChillMainBundle/Action/User/UpdateProfile/UpdateProfileCommandHandler.php @@ -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']); diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 70b032238..b5539aa83 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -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] diff --git a/src/Bundle/ChillMainBundle/Form/Type/UserLocaleType.php b/src/Bundle/ChillMainBundle/Form/Type/UserLocaleType.php new file mode 100644 index 000000000..8e9c7fa62 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/Type/UserLocaleType.php @@ -0,0 +1,43 @@ +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; + } +} diff --git a/src/Bundle/ChillMainBundle/Form/UpdateProfileType.php b/src/Bundle/ChillMainBundle/Form/UpdateProfileType.php index 6aa8f0943..3806facb9 100644 --- a/src/Bundle/ChillMainBundle/Form/UpdateProfileType.php +++ b/src/Bundle/ChillMainBundle/Form/UpdateProfileType.php @@ -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) ; } diff --git a/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php b/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php index 2f888ffd5..1cb64ff4a 100644 --- a/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php +++ b/src/Bundle/ChillMainBundle/Notification/Email/NotificationMailer.php @@ -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, diff --git a/src/Bundle/ChillMainBundle/Resources/views/Notification/email_daily_digest.fr.md.twig b/src/Bundle/ChillMainBundle/Resources/views/Notification/email_daily_digest.md.twig similarity index 100% rename from src/Bundle/ChillMainBundle/Resources/views/Notification/email_daily_digest.fr.md.twig rename to src/Bundle/ChillMainBundle/Resources/views/Notification/email_daily_digest.md.twig diff --git a/src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content.fr.md.twig b/src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content.md.twig similarity index 88% rename from src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content.fr.md.twig rename to src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content.md.twig index 62e41860b..023f2901a 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content.fr.md.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content.md.twig @@ -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 diff --git a/src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content_to_email.fr.md.twig b/src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content_to_email.md.twig similarity index 100% rename from src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content_to_email.fr.md.twig rename to src/Bundle/ChillMainBundle/Resources/views/Notification/email_non_system_notification_content_to_email.md.twig diff --git a/src/Bundle/ChillMainBundle/Resources/views/Notification/email_notification_comment_persist.fr.md.twig b/src/Bundle/ChillMainBundle/Resources/views/Notification/email_notification_comment_persist.md.twig similarity index 87% rename from src/Bundle/ChillMainBundle/Resources/views/Notification/email_notification_comment_persist.fr.md.twig rename to src/Bundle/ChillMainBundle/Resources/views/Notification/email_notification_comment_persist.md.twig index b1244da39..e7e212492 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Notification/email_notification_comment_persist.fr.md.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Notification/email_notification_comment_persist.md.twig @@ -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 diff --git a/src/Bundle/ChillMainBundle/Resources/views/User/profile.html.twig b/src/Bundle/ChillMainBundle/Resources/views/User/profile.html.twig index 0b268af03..266f75115 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/User/profile.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/User/profile.html.twig @@ -44,6 +44,7 @@