diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index bb342c44ded49..89f3b00a74e3a 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -4,7 +4,8 @@ CHANGELOG 6.4 --- -* Allow an array to be passed as the first argument to the `importmap()` Twig function + * Allow an array to be passed as the first argument to the `importmap()` Twig function + * Add `TemplatedEmail::locale()` to set the locale for the email rendering 6.3 --- diff --git a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php index d418ee2f38634..18e0eb1f86693 100644 --- a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php +++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php @@ -18,6 +18,7 @@ use Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface; use Symfony\Component\Mime\HtmlToTextConverter\LeagueHtmlToMarkdownConverter; use Symfony\Component\Mime\Message; +use Symfony\Component\Translation\LocaleSwitcher; use Twig\Environment; /** @@ -28,12 +29,14 @@ final class BodyRenderer implements BodyRendererInterface private Environment $twig; private array $context; private HtmlToTextConverterInterface $converter; + private ?LocaleSwitcher $localeSwitcher = null; - public function __construct(Environment $twig, array $context = [], HtmlToTextConverterInterface $converter = null) + public function __construct(Environment $twig, array $context = [], HtmlToTextConverterInterface $converter = null, LocaleSwitcher $localeSwitcher = null) { $this->twig = $twig; $this->context = $context; $this->converter = $converter ?: (interface_exists(HtmlConverterInterface::class) ? new LeagueHtmlToMarkdownConverter() : new DefaultHtmlToTextConverter()); + $this->localeSwitcher = $localeSwitcher; } public function render(Message $message): void @@ -47,30 +50,42 @@ public function render(Message $message): void return; } - $messageContext = $message->getContext(); + $callback = function () use ($message) { + $messageContext = $message->getContext(); - if (isset($messageContext['email'])) { - throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', get_debug_type($message))); - } + if (isset($messageContext['email'])) { + throw new InvalidArgumentException(sprintf('A "%s" context cannot have an "email" entry as this is a reserved variable.', get_debug_type($message))); + } - $vars = array_merge($this->context, $messageContext, [ - 'email' => new WrappedTemplatedEmail($this->twig, $message), - ]); + $vars = array_merge($this->context, $messageContext, [ + 'email' => new WrappedTemplatedEmail($this->twig, $message), + ]); - if ($template = $message->getTextTemplate()) { - $message->text($this->twig->render($template, $vars)); - } + if ($template = $message->getTextTemplate()) { + $message->text($this->twig->render($template, $vars)); + } - if ($template = $message->getHtmlTemplate()) { - $message->html($this->twig->render($template, $vars)); - } + if ($template = $message->getHtmlTemplate()) { + $message->html($this->twig->render($template, $vars)); + } + + $message->markAsRendered(); - $message->markAsRendered(); + // if text body is empty, compute one from the HTML body + if (!$message->getTextBody() && null !== $html = $message->getHtmlBody()) { + $text = $this->converter->convert(\is_resource($html) ? stream_get_contents($html) : $html, $message->getHtmlCharset()); + $message->text($text, $message->getHtmlCharset()); + } + }; - // if text body is empty, compute one from the HTML body - if (!$message->getTextBody() && null !== $html = $message->getHtmlBody()) { - $text = $this->converter->convert(\is_resource($html) ? stream_get_contents($html) : $html, $message->getHtmlCharset()); - $message->text($text, $message->getHtmlCharset()); + $locale = $message->getLocale(); + + if ($locale && $this->localeSwitcher) { + $this->localeSwitcher->runWithLocale($locale, $callback); + + return; } + + $callback(); } } diff --git a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php index 777cc06b58984..e5c990f3ba733 100644 --- a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php +++ b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php @@ -20,6 +20,7 @@ class TemplatedEmail extends Email { private ?string $htmlTemplate = null; private ?string $textTemplate = null; + private ?string $locale = null; private array $context = []; /** @@ -42,6 +43,16 @@ public function htmlTemplate(?string $template): static return $this; } + /** + * @return $this + */ + public function locale(?string $locale): static + { + $this->locale = $locale; + + return $this; + } + public function getTextTemplate(): ?string { return $this->textTemplate; @@ -52,6 +63,11 @@ public function getHtmlTemplate(): ?string return $this->htmlTemplate; } + public function getLocale(): ?string + { + return $this->locale; + } + /** * @return $this */ diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php index 6af152dad6c5e..ddc6f46d19873 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php @@ -18,8 +18,10 @@ use Symfony\Component\Mime\HtmlToTextConverter\DefaultHtmlToTextConverter; use Symfony\Component\Mime\HtmlToTextConverter\HtmlToTextConverterInterface; use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Translation\LocaleSwitcher; use Twig\Environment; use Twig\Loader\ArrayLoader; +use Twig\TwigFunction; class BodyRendererTest extends TestCase { @@ -131,7 +133,16 @@ public function testRenderedOnceUnserializableContext() $this->assertEquals('Text', $email->getTextBody()); } - private function prepareEmail(?string $text, ?string $html, array $context = [], HtmlToTextConverterInterface $converter = null): TemplatedEmail + public function testRenderWithLocale() + { + $localeSwitcher = new LocaleSwitcher('en', []); + $email = $this->prepareEmail(null, 'Locale: {{ locale_switcher_locale() }}', [], new DefaultHtmlToTextConverter(), $localeSwitcher, 'fr'); + + $this->assertEquals('Locale: fr', $email->getTextBody()); + $this->assertEquals('Locale: fr', $email->getHtmlBody()); + } + + private function prepareEmail(?string $text, ?string $html, array $context = [], HtmlToTextConverterInterface $converter = null, LocaleSwitcher $localeSwitcher = null, string $locale = null): TemplatedEmail { $twig = new Environment(new ArrayLoader([ 'text' => $text, @@ -139,12 +150,19 @@ private function prepareEmail(?string $text, ?string $html, array $context = [], 'document.txt' => 'Some text document...', 'image.jpg' => 'Some image data', ])); - $renderer = new BodyRenderer($twig, [], $converter); + + if ($localeSwitcher instanceof LocaleSwitcher) { + $twig->addFunction(new TwigFunction('locale_switcher_locale', [$localeSwitcher, 'getLocale'])); + } + + $renderer = new BodyRenderer($twig, [], $converter, $localeSwitcher); $email = (new TemplatedEmail()) ->to('fabien@symfony.com') ->from('helene@symfony.com') + ->locale($locale) ->context($context) ; + if (null !== $text) { $email->textTemplate('text'); } diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php index 019be16ff4bcf..f796c7a05db7e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php @@ -58,6 +58,7 @@ public function testSymfonySerialize() $e->to('you@example.com'); $e->textTemplate('email.txt.twig'); $e->htmlTemplate('email.html.twig'); + $e->locale('en'); $e->context(['foo' => 'bar']); $e->addPart(new DataPart('Some Text file', 'test.txt')); $expected = clone $e; @@ -66,6 +67,7 @@ public function testSymfonySerialize() { "htmlTemplate": "email.html.twig", "textTemplate": "email.txt.twig", + "locale": "en", "context": { "foo": "bar" }, diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index deac87b8b62ce..546afd55f499c 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -22,6 +22,7 @@ use Symfony\Component\Form\Form; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Mailer\Mailer; +use Symfony\Component\Translation\LocaleSwitcher; use Symfony\Component\Translation\Translator; use Symfony\Contracts\Service\ResetInterface; use Twig\Extension\ExtensionInterface; @@ -85,6 +86,10 @@ public function load(array $configs, ContainerBuilder $container) if ($htmlToTextConverter = $config['mailer']['html_to_text_converter'] ?? null) { $container->getDefinition('twig.mime_body_renderer')->setArgument('$converter', new Reference($htmlToTextConverter)); } + + if (ContainerBuilder::willBeAvailable('symfony/translation', LocaleSwitcher::class, ['symfony/framework-bundle'])) { + $container->getDefinition('twig.mime_body_renderer')->setArgument('$localeSwitcher', new Reference('translation.locale_switcher')); + } } if ($container::willBeAvailable('symfony/asset-mapper', AssetMapper::class, ['symfony/twig-bundle'])) { diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 602fa21ee7981..835ccc219e940 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -20,7 +20,7 @@ "composer-runtime-api": ">=2.1", "symfony/config": "^6.1|^7.0", "symfony/dependency-injection": "^6.1|^7.0", - "symfony/twig-bridge": "^6.3|^7.0", + "symfony/twig-bridge": "^6.4|^7.0", "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.2|^7.0", "twig/twig": "^2.13|^3.0.4"