Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing the Translator service in Symfony 3

Tags:

php

symfony

In my Symfony 2.8 project I have an extension that adds some extra logic to the trans method:

parameters:
    translator.class: MyBundle\Twig\TranslationExtension

The class looks like this:

namespace MyBundle\Twig\TranslationExtension;

use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator;

class TranslationExtension extends BaseTranslator
{
    private $currentLocale;

    public function trans($id, array $parameters = array(), $domain = null, $locale = null)
    {
            $translation = parent::trans($id, $parameters, $domain, $locale);

            // Some extra logic here

            return $translation;
    }

    public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
    {
        return parent::transChoice($id, $number, $parameters, $domain, $locale);
    }
}

Now, I'm migrating to Symfony 3, where those class parameters are deprecated, but how can I implement this by overwriting the translator service?

like image 311
Evdv Avatar asked Sep 13 '16 12:09

Evdv


2 Answers

Instead of extending, it would be better to decorate the translator service. Right now you overriding the class name, which will also override other bundles that want to decorate the service. And I see you made it an extension because of Twig, the original Twig {{ trans() }} filter will use the decorated service too.

services:
  app.decorating_translator:
    class:     AppBundle\DecoratingTranslator
    decorates: translator
    arguments: ['@app.decorating_translator.inner'] # original translator
    public:    false

See documentation about decorating here: http://symfony.com/doc/current/service_container/service_decoration.html

like image 105
Rvanlaak Avatar answered Sep 17 '22 15:09

Rvanlaak


Here is full working example how to decorate translator service in symfony 3 and replace parameter in all translated strings.

Decorate service in config:

# app/config/services.yml
app.decorating_translator:
    class:     AppBundle\Translation\Translator
    decorates: translator
    arguments:
        - '@app.decorating_translator.inner'
        # passing custom parameters
        - {'%%app_name%%': '%app_name%', '%%PRETTY_ERROR%%': 'This is not nice:'}
    public:    false

Create new translator that reuses original translator and adds parameters defined in service config. The only new code is updateParameters() method and call to it:

# AppBundle/Translation/Translator.php
namespace AppBundle\Translation;

use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Component\Translation\TranslatorInterface;

class Translator implements TranslatorInterface, TranslatorBagInterface
{
    /** @var TranslatorBagInterface|TranslatorInterface */
    protected $translator;
    /** @var array */
    private $parameters;

    /**
     * @param TranslatorInterface|TranslatorBagInterface $translator
     * @param array                                      $parameters
     */
    public function __construct($translator, $parameters)
    {
        $this->translator = $translator;
        $this->parameters = $parameters;
    }

    /**
     * @param string $id
     * @param array  $parameters
     * @param null   $domain
     * @param null   $locale
     *
     * @return string
     */
    public function trans($id, array $parameters = [], $domain = null, $locale = null)
    {
        $parameters = $this->updateParameters($parameters);

        return $this->translator->trans($id, $parameters, $domain, $locale);
    }

    /**
     * @param string $id
     * @param int    $number
     * @param array  $parameters
     * @param null   $domain
     * @param null   $locale
     *
     * @return string
     */
    public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
    {
        $parameters = $this->updateParameters($parameters);

        return $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
    }

    /**
     * @param string $locale
     */
    public function setLocale($locale)
    {
        $this->translator->setLocale($locale);
    }

    /**
     * @return string
     */
    public function getLocale()
    {
        return $this->translator->getLocale();
    }

    /**
     * @param string|null $locale
     *
     * @return \Symfony\Component\Translation\MessageCatalogueInterface
     */
    public function getCatalogue($locale = null)
    {
        return $this->translator->getCatalogue($locale);
    }

    /**
     * @param array $parameters
     *
     * @return array
     */
    protected function updateParameters($parameters)
    {
        return array_merge($this->parameters, $parameters);
    }
}

Now every time you translate message %app_config% will replaced with parameter from config (e.g. parameters.yml) and %PRETTY_ERROR% will be replace with static string. If needed it is possible to override same parameters when calling trans:

{{ 'layout.title.home'|trans({'%app_name%': 'Real App No. 1'}) }}

Read about service decoration here

like image 32
Aurelijus Rozenas Avatar answered Sep 18 '22 15:09

Aurelijus Rozenas