Принудительное использование локали Twig

Я хотел бы использовать систему шаблонов Twig для создания шаблонов своих электронных писем. Языковой стандарт электронной почты должен основываться на пользовательских настройках, а не на языковых стандартах сеанса или запроса. Как я могу принудительно установить языковой стандарт при рендеринге шаблона Twig?

В руководстве упоминается, как принудительно установить языковой стандарт для переводчика. Но я бы хотел передать этот языковой стандарт методу render (), чтобы переводы внутри шаблона веточки отображались в этом языковом стандарте.

Это отличается от использования в в шаблоне, потому что я думаю, что это заставляет перевод внутри шаблона в определенную локаль.

Итак, взяв пример из Symfony, я ищу что-то вроде этого:

public function indexAction($name)
{
    $message = \Swift_Message::newInstance()
        ->setSubject('Hello Email')
        ->setFrom('[email protected]')
        ->setTo('[email protected]')
        ->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(...);
}

person rolandow    schedule 07.03.2013    source источник


Ответы (4)


Вы можете передать языковой стандарт в качестве аргумента при использовании фильтра трансформации (см. Diff: https://github.com/symfony/symfony/commit/3ea31a02630412b1c732ee1647a0724378f67665).

Таким образом, вы можете передать другую переменную user_locale в свой метод рендеринга в вашем контроллере (или пройти через весь объект пользователя вместо передачи имени и 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'
person Mark    schedule 14.03.2013

Возьмите компонент 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('[email protected]')
        ->setTo('[email protected]')
        ->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());
person Marcel Hernandez    schedule 26.05.2015
comment
включенные подшаблоны не затрагиваются - person Jacky Chan; 03.11.2015
comment
Это должен быть ответ по умолчанию, поскольку он меняет языковой стандарт в одном месте вместо того, чтобы менять сотни (в нашем случае) шаблонов. - person Serhii Polishchuk; 23.10.2020

Вот решение (оно работает хорошо, за исключением подшаблонов (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();
}
person Osoian Marcel    schedule 16.09.2016

вы можете сделать это: отправить параметр (например, локаль) в шаблон

public function indexAction($name)
{
    $message = \Swift_Message::newInstance()
        ->setSubject('Hello Email')
        ->setFrom('[email protected]')
        ->setTo('[email protected]')
        ->setBody(
            $this->renderView(
                'HelloBundle:Hello:email.txt.twig',
                array('name' => $name, 'locale' => 'nl_NL'),
            )
        )
    ;
    $this->get('mailer')->send($message);

    return $this->render(...);
}
person Lhassan Baazzi    schedule 07.03.2013
comment
Да, но я не думаю, что шаблон будет использовать этот языковой стандарт автоматически для блоков {% trans%}, не так ли? - person rolandow; 08.03.2013
comment
нет, вы можете заставить транс-фильтр использовать языковой стандарт, который вы хотите {{ "Hello"|trans({}, "messages", locale) }}, компонент переводчика автоматически использует языковой стандарт, указанный в запросе, если вы хотите его изменить $this->get('translator')->setLocale($locale); - person Lhassan Baazzi; 25.03.2013