强制小枝区域设置


Forcing the Twig Locale

我想使用Twig模板系统来模板我的电子邮件。电子邮件的语言环境应该基于用户设置,而不是会话或请求语言环境。如何在呈现Twig模板时强制使用区域设置?

手册确实提到了如何为Translator强制设置语言环境。但是我想把这个语言环境传递给render()方法,以便在twig模板内的翻译在这个语言环境中渲染。

这与在模板中使用转换为不同,因为我认为这会在模板中强制转换为特定的语言环境。

那么,以Symfony为例,我正在寻找这样的东西:

public function indexAction($name)
{
    $message = 'Swift_Message::newInstance()
        ->setSubject('Hello Email')
        ->setFrom('send@example.com')
        ->setTo('recipient@example.com')
        ->setBody(
            $this->renderView(
                'HelloBundle:Hello:email.txt.twig',
                array('name' => $name),
                'nl_NL' // <-- This would be nice!
            )
        )
    ;
    $this->get('mailer')->send($message);
    return $this->render(...);
}

您可以在使用trans过滤器时将区域设置作为参数传递(参见diff: https://github.com/symfony/symfony/commit/3ea31a02630412b1c732ee1647a0724378f67665)。

所以你可以在控制器的渲染方法中传递另一个user_locale变量(或者传递整个user对象,而不是单独传递name和user_locale),或者在你的模板中使用app.user,如果用户将登录,等等。(显然取决于你的应用程序)),然后在你的电子邮件模板中,你可以有这样的东西:

{{ 'greeting' | trans({}, "messages", user_locale) }} {{ name | title }}
{# rest of email template with more translation strings #}

然后在该语言环境的翻译文件中(假设您使用yaml),只需这样做,翻译将很好地为您工作:

# messages.fr.yml    
greeting: 'Bonjour'

获取Translator组件并在呈现模板之前更改其区域设置。这个解决方案不需要传递一个额外的值给render()方法的参数数组,并且痛苦地重构你所有的Twig文件。

public function indexAction($name)
{
    $translator = $this->get('translator');
    // Save the current session locale
    // before overwriting it. Suppose its 'en_US'
    $sessionLocale = $translator->getLocale();
    $translator->setLocale('nl_NL');
    $message = 'Swift_Message::newInstance()
        ->setSubject('Hello Email')
        ->setFrom('send@example.com')
        ->setTo('recipient@example.com')
        ->setBody(
            $this->renderView(
                'HelloBundle:Hello:email.txt.twig',
                array('name' => $name)
            )
        )
    ;
    $this->get('mailer')->send($message);
    // Otherwise subsequent templates would also
    // be rendered in Dutch instead of English
    $translator->setLocale($sessionLocale);
    return $this->render(...);
}

发送用户邮件的一种常用方法是将用户的语言环境存储在user实体中,并将其直接传递给转换器,如以下代码片段所示:

$translator->setLocale($recipientUser->getLocale());

这是一个解决方案(它运行良好,除了子模板(Twig: render(controller('AppBundle:Invoice/Index:productTotalPartial')))

<?php
namespace Main'BoBundle'Service;
use Symfony'Component'Translation'TranslatorInterface;
/**
 * Class LocaleSwitcher
 *
 * @package Main'BoBundle'Service
 */
class LocaleSwitcher
{
    /**
     * @var TranslatorInterface
     */
    private $translator;
    /**
     * @var string
     */
    private $previousLocale;
    /**
     * @param TranslatorInterface $translator
     */
    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }
    /**
     * Change the locale
     *
     * @param string $locale
     */
    public function setLocale($locale)
    {
        $this->previousLocale = $this->translator->getLocale();
        $this->translator->setLocale($locale);
        $this->setPhpDefaultLocale($locale);
    }
    /**
     * Revert the locale
     */
    public function revertLocale()
    {
        if ($this->previousLocale === null) {
            return;
        }
        $this->translator->setLocale($this->previousLocale);
        $this->setPhpDefaultLocale($this->previousLocale);
        $this->previousLocale = null;
    }
    /**
     * Use temporary locale in closure function
     *
     * @param string $locale
     * @param 'Closure $c
     */
    public function temporaryLocale($locale, 'Closure $c)
    {
        $this->setLocale($locale);
        $c();
        $this->revertLocale();
    }
    /**
     * Sets the default PHP locale.
     * Copied from Symfony/Component/HttpFoundation/Request.php
     *
     * @param string $locale
     */
    private function setPhpDefaultLocale($locale)
    {
        // if either the class Locale doesn't exist, or an exception is thrown when
        // setting the default locale, the intl module is not installed, and
        // the call can be ignored:
        try {
            if (class_exists('Locale', false)) {
                /** @noinspection PhpUndefinedClassInspection */
                'Locale::setDefault($locale);
            }
        } catch ('Exception $e) {
        }
    }
}

的例子:

if ($this->getLocale()) {
    $this->localeSwitcher->setLocale($this->getLocale());
}
$html = $this->templating->render($templatePath);
if ($this->getLocale()) {
    $this->localeSwitcher->revertLocale();
}

你可以这样做:发送一个参数(例如locale)到模板

public function indexAction($name)
{
    $message = 'Swift_Message::newInstance()
        ->setSubject('Hello Email')
        ->setFrom('send@example.com')
        ->setTo('recipient@example.com')
        ->setBody(
            $this->renderView(
                'HelloBundle:Hello:email.txt.twig',
                array('name' => $name, 'locale' => 'nl_NL'),
            )
        )
    ;
    $this->get('mailer')->send($message);
    return $this->render(...);
}