KnpPaginatorBundle icon indicating copy to clipboard operation
KnpPaginatorBundle copied to clipboard

Synfony 4.3 translator decorates failure in prod mode, work great in dev

Open lbraconnier2 opened this issue 5 years ago • 4 comments

For our stuff, we need to decorate the symfony translator. it works very well in "dev" mode, but when symfony app is configured in "prod" mode we have this message :

_Argument 2 passed to Knp\Bundle\PaginatorBundle\Helper\Processor::_construct() must implement interface Symfony\Component\Translation\TranslatorInterface, instance of App\Services\CustomTranslator given

below the service.yaml configuration image

and the decorator code :

<?php
namespace App\Services;

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

/**
 * Class Translator
 * To handle translation identifier formated like that : '|CodeJournal|symfony.great'
 * Pipe at the beginning to avoid searching all string for the 1% of translation outside 'messages' domain.
 *
 * How to use ?
 * Add it in service.yml :
 *    app_decorating_translator:
 *        class:     App\Services\CustomTranslator
 *        decorates: translator
 *        arguments:
 *            - '@app_decorating_translator.inner'
 *        public: false
 */
class CustomTranslator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
{
    /** @var TranslatorBagInterface|TranslatorInterface */
    protected $translator;

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

    /**
     * Custom function
     * use of references parameters to limit variables usages.
     *
     * @param $id
     * @param $domain
     */
    private function applyCustomPipe(&$id, &$domain)
    {
        // if pipe at the start of the received translation identifier
        if (is_string($id) && substr($id, 0, 1) === '|') {
            // search for the second pipe
            $pos = strpos($id, '|', 1); // faster than regex
            if ($pos > 1) {
                $domain = substr($id, 1, $pos - 1);
                $id = substr($id, $pos + 1); // real identifier without |domain|
            }
        }
    }

    /**
     * Override Symfony function trans(), used for simple translation.
     *
     * @param string $id
     * @param array  $parameters
     * @param null   $domain
     * @param null   $locale
     *
     * @return string
     */
    public function trans($id, array $parameters = [], $domain = null, $locale = null)
    {
        $this->applyCustomPipe($id, $domain);

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

    /**
     * Override Symfony function transChoice(), used for pluralized translation.
     *
     * @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)
    {
        $this->applyCustomPipe($id, $domain);

        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);
    }
}

lbraconnier2 avatar Aug 19 '19 15:08 lbraconnier2

I see your service is not implementing Symfony\Component\Translation\TranslatorInterface

garak avatar Aug 19 '19 17:08 garak

That's right, we implement, Symfony\Contracts\Translation\LocaleAwareInterface and Symfony\Contracts\Translation\TranslatorInterface because Symfony\Component\Translation\TranslatorInterface is deprecated since 4.2

lbraconnier2 avatar Aug 20 '19 07:08 lbraconnier2

I'm afraid you need to keep the deprecated class for now. A possible alternate solution is to write your own helper and use it instead of bundle's one. Another possible solution is to change bundle's helper to be flexible and accept new Symfony translator (PR is welcome)

garak avatar Aug 20 '19 07:08 garak

Thanks a lot, we will try this.

lbraconnier2 avatar Aug 20 '19 07:08 lbraconnier2