Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Advanced customization of translations in Symfony2

I have a Symfony2 project and I am using Translation component for translating text. I have all translations in yml file like so

translation-identifier: Translated text here

Translating text looks like this from Twig

'translation-identifier'|trans({}, 'domain')

The thing is, in some cases I would like to have two different texts for same translation (not for pluralization). Here's how I would like it to work:

  1. Define two texts in yml file for translations that need to have different texts. Each would have it's own unique suffix

    translation-identifier-suffix1
    
    translation-identifier-suffix2
    
  2. Define a global rule that would define which suffix should be choosen. Psuedocode below:

     public function getSuffix() {
       return rand(0, 10) < 5 ? '-suffix1' : '-suffix2';
     }
    
  3. Twig (and PHP) would look the same - I would still specify just the identifier without suffix. Translator would then append suffix to the identifier and try to find a match. If there would be no match it would try to find a match again without suffix.

like image 622
Žan Kusterle Avatar asked Mar 21 '13 14:03

Žan Kusterle


3 Answers

AFAIK, Translator component doesn't support it.

But if you want same kind of behavior, you could do by overriding the translator service.

1) Override the service

# app/config/config.yml
parameters:
    translator.class:      Acme\HelloBundle\Translation\Translator

First, you can set the parameter holding the service's class name to your own class by setting it in app/config/config.yml. FYI: https://github.com/symfony/FrameworkBundle/blob/master/Resources/config/translation.xml

2) Extend the translator class provided symfony framework bundle. FYI: https://github.com/symfony/FrameworkBundle/blob/master/Translation/Translator.php

3) Overwrite the trans function which is provider by translator component. https://github.com/symfony/Translation/blob/master/Translator.php

Hope this helps!

like image 110
Venu Avatar answered Nov 17 '22 05:11

Venu


Here is the extended translator class in case anyone ever needs it

<?php

    namespace Acme\HelloBundle\Translation;

    use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator;
    use Symfony\Component\Translation\MessageSelector;
    use Symfony\Component\DependencyInjection\ContainerInterface;

    class Translator extends BaseTranslator {

        const SUFFIX_1 = '_suffix1';
        const SUFFIX_2 = '_suffix2';

        private $suffix;

        public function __construct(ContainerInterface $container, MessageSelector $selector, $loaderIds = array(), array $options = array()) {
            parent::__construct($container, $selector, $loaderIds, $options);
            $this->suffix = $this->getSuffix($container);
        }

        public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null) {     
            if ($locale === null)
                $locale = $this->getLocale();

            if (!isset($this->catalogues[$locale]))
                $this->loadCatalogue($locale);

            if($this->suffix !== null && $this->catalogues[$locale]->has((string) ($id . $this->suffix), $domain))
                $id .= $this->suffix;

            return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters);
        }

        private function getSuffix($container) {
            return rand(0, 10) < 5 ? self::SUFFIX_1 : self::SUFFIX_2;
        }

    }

?>
like image 40
Žan Kusterle Avatar answered Nov 17 '22 04:11

Žan Kusterle


As of Symfony 3, Venu's answer no longer works completely, as the translator.class parameter is no longer used.

To load your custom translator class, you now need to create a compiler pass.

<?php

namespace Acme\HelloBundle\DependencyInjection\Compiler;

use Acme\HelloBundle\Translation\Translator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class TranslatorOverridePass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $container->getDefinition('translator.default')->setClass(Translator::class);
    }
}

And this compiler pass needs to be added to the container.

<?php

namespace Acme\HelloBundle;

use Acme\HelloBundle\DependencyInjection\Compiler\TranslatorOverridePass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class AcmeHelloBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new TranslatorOverridePass());
    }
}
like image 30
Brecht Avatar answered Nov 17 '22 04:11

Brecht