4

I am trying to override the Symfony translator to have some translations from my database. I am first checking if the translation is not in a catalogue and if not load it from the database

<?php

namespace Competitive\TranslationBundle\Translation;

use Competitive\TranslationBundle\Entity\TranslationManager;
use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Translator as BaseTranslator;

class Translator extends BaseTranslator
{
    /**
     * @var TranslationManager
     */
    private $translationManager;

    public function __construct($locale, TranslationManager $translationManager, MessageSelector $selector = null, $cacheDir = null, $debug = false)
    {
        parent::__construct($locale, $selector, $cacheDir, $debug);
        $this->translationManager = $translationManager;
    }

    /**
     * {@inheritdoc}
     */
    public function trans($id, array $parameters = array(), $domain = null, $locale = null)
    {
        $catalogueDomain = $domain;
        if (null === $catalogueDomain) {
            $catalogueDomain = 'messages';
        }

        $locale = $locale === null ? $this->getLocale() : $locale;

        if ($this->getCatalogue($locale)->has($id, $domain)) {
            return parent::trans($id, $parameters, $catalogueDomain, $locale);
        }

        $translations = $this->translationManager->findTranslationsBy([
            'key' => $id,
            'locale' => $locale
        ]);

        if (empty($translations)) {
            $translation = $this->translationManager->create($id, $id, $locale);
        } elseif (null === $domain) {
            $translation = $translations[0];
        } else {
            foreach ($translations as $trans) {
                if ($trans->getDomain() == $domain) {
                    $translation = $trans;
                    break;
                }
            }

            if (!isset($translation)) {
                $translation = $translations[0];
            }
        }

        return strtr($translation->getValue(), $parameters);
    }

    /**
     * {@inheritdoc}
     */
    public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
    {
        return $this->trans($id, $parameters, $domain, $locale);
    }
}

translation.yml

services:
    translator:
        class: Competitive\TranslationBundle\Translation\Translator
        arguments:
            - %locale%
            - @competitive_translation.translation_manager

The translation is loaded from the database without problem.

But $this->getCatalogue($locale)->has($id, $domain) always returns false (the translations from the catalogue were working before the override)

And my cache translation folder app/cache/dev/translations is not generated

Ajouve
  • 9,735
  • 26
  • 90
  • 137
  • The reason why your translations are missing is because there are a `loader ids` that are passed to default translation class. Moreover currently you're trying to override the wrong class. I've tried to do that, but I had problems figuring out how to pass as an argument those loader ids, since they are marked as `collection` type in their xml configuration. Normally I can write an answer, but I doubt it wont be a complete one. – Artamiel Jul 08 '15 at 11:09
  • Which class should I extends ? I need the parent trans. Can I provide a kind of loader id in the new service or something like that ? – Ajouve Jul 09 '15 at 09:48
  • `Symfony\Bundle\FrameworkBundle\Translation\Translator` this is the one you need to look over. It extends the one you're trying to override now. Take a look at it's definition in `Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml`. By injecting `service_container` to your service you can pass almost every dependency to that class except the loaders which are defined in that same `xml` file. From there you can override `trans` and `transChoice` as well. – Artamiel Jul 09 '15 at 09:58
  • Did you ever find the solution to your question? If you still need help, the accepted answer to this question helped me a lot: https://stackoverflow.com/questions/15550002/advanced-customization-of-translations-in-symfony2 – Cave Johnson Jun 14 '17 at 07:35

1 Answers1

0

You can use a compiler pass to override the default translator class and use a setter to inject the translation manager.

Also you should extend \Symfony\Bundle\FrameworkBundle\Translation\Translator, not \Symfony\Component\Translation\Translator

TranslatorPass.php:

<?php

namespace Competitive\TranslationBundle\DependencyInjection\Compiler;

use Competitive\TranslationBundle\Translation\Translator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class TranslatorPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition('translator.default')) {
            return;
        }

        $definition = $container->getDefinition('translator.default');
        $definition->setClass(Translator::class);
        $definition->addMethodCall('setTranslationManager', array(new Reference('competitive_translation.translation_manager')));
    }
}

TranslationBundle.php:

<?php

namespace Competitive\TranslationBundle;

use Competitive\TranslationBundle\DependencyInjection\Compiler\TranslatorPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class TranslationBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        parent::build($container);

        $container->addCompilerPass(new TranslatorPass());
    }
}

Translator.php:

<?php

namespace Competitive\TranslationBundle\Translation;

use Competitive\TranslationBundle\Entity\TranslationManager;
use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator;

class Translator extends BaseTranslator
{
    /**
     * @var TranslationManager
     */
    private $translationManager;


    public function setTranslationManager(TranslationManager $translationManager){
        $this->translationManager = $translationManager;
    }

    public function trans($id, array $parameters = array(), $domain = null, $locale = null){
        // custom logic

        return parent::trans($id, $parameters, $domain, $locale);
    }
}
user2535540
  • 385
  • 5
  • 9