directory
directory

Reputation: 3169

ZF2 use translator in controller

For a url redirection I need to translate something in the controller.

How can I acces $this->translate(); in the controller?

Thanks! Nick

Upvotes: 9

Views: 15385

Answers (7)

Carles
Carles

Reputation: 11

An invokable is a class that can be constructed without any arguments. Since our MyModule\Controller\FooController now has a required argument, we need to change this. A factory is a class that creates instances of another class. We’ll now create one for our FooController. Let’s modify our module.config.php file like this:

return array(
     'view_manager' => array( /** ViewManager Config */ ),
     'controllers'  => array(
         'invokables' => array(
             //'MyModule\Controller\Foo' => 'MyModule\Controller\FooController'
         ),
         'factories' => array(
            'MyModule\Controller\Foo' => 'MyModule\Factory\FooControllerFactory',
        )
     ),
     'router' => array( /** Router Config */ )
 );

Let’s implement our factory class, for this create a new folder in \module\MyModule\src\MyModule\Factory and new file called FooControllerFactory.php:

<?php
namespace MyModule\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use MyModule\Controller\FooController;

class FooControllerFactory implements FactoryInterface
{

    public function __construct()
    {}

    /**
     * Create service
     *
     * @param ServiceLocatorInterface $serviceLocator
     *
     * @return mixed
     */    
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $realServiceLocator = $serviceLocator->getServiceLocator();
        $translator         = $realServiceLocator->get('translator');

        return new FooController($translator);
    }
}

Let’s now use the $translator within our FooController. For this we will need to overwrite the default __contruct():

<?php
namespace MyModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\Mvc\I18n\Translator;

class FooController extends AbstractActionController
{
    protected $translator;

    public function __construct(Translator $translator)
    {
        $this->translator = $translator;
    }

    public function FooAction()
    {
      ...
      $msg = $this->translator->translate('Blah blah blah');
      ...
    }
}

In my case works fine!!!

Upvotes: 0

In my case works perfectly this solution:

namespace MyNS;
class MyCtrlr
{
    protected $translator;

    public function getTranslator()
    {
        if (!$this->translator)
        {
            $sm = $this->getServiceLocator();
            $this->translator = $sm->get('translator');
        }
        return $this->translator;
    }

    public function myAction()
    {
        $sTrHello = $this->getTranslator()->translate('Hello');
        /*
         * More code here
         */
    }

}

Upvotes: 0

BlueberrySourRaspberry
BlueberrySourRaspberry

Reputation: 963

$translator = $this->getServiceManager()->get('MVCTranslator');

Upvotes: 0

Pervaiz Iqbal
Pervaiz Iqbal

Reputation: 326

You may do it this way:

$translate = $this->getServiceLocator()->get('viewhelpermanager')->get('translate');

Upvotes: -1

Athlan
Athlan

Reputation: 6619

If you want to use the translator in controller like in view, just like that:

$this->translate('Hello')

instead of ugly:

$this->getServiceLocator()->get('translator')->translate('Hello')

you can also write the translate plugin for controller, just like view helper Zend\I18n\View\Helper\Translate.

Of course, you can invoke the plugin with the same signature:

__invoke($message, $textDomain = null, $locale = null)

Just register:

'controller_plugins' => array(
    'factories' => array(
        'translate' => 'Application\Controller\Plugin\Translate',
    ),
),

And write plugin:

<?php

namespace Application\Controller\Plugin;

use Zend\Mvc\Controller\Plugin\AbstractPlugin;

use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;

use Zend\I18n\Translator\Translator;

class Translate implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $serviceLocator = $serviceLocator->getController()->getServiceLocator();
        $serviceFactory = new TranslatorServiceFactory();
        $translator = $serviceFactory->createService($serviceLocator);

        return new TranslatorProxy($translator);
    }
}

final class TranslatorProxy extends AbstractPlugin
{
    private $translator;

    public function __construct(Translator $translator)
    {
        $this->translator = $translator;
    }

    public function __invoke($message, $textDomain = 'default', $locale = null)
    {
        return $this->translator->translate($message, $textDomain, $locale);
    }

    public function __call($method, $args)
    {
        return call_user_func_array([$this->translator, $method], $args);
    }

    public static function __callstatic($method, $args)
    {
        return call_user_func_array([$this->translator, $method], $args);
    }
}

How it works? You see, the ServiceLocator passed in

createService(ServiceLocatorInterface $serviceLocator)

factory in configuration space controller_plugins, does have no access to the Config service in ServiceLocator in controller. So you cannot get the configuration and create the Translate object via TranslatorServiceFactory.

Instead of that, you can access to the ServiceLocator assigned to the controller for which our helper has been invoked, by typing $serviceLocator->getController().

Of course, $serviceLocator passed in createService method is instance of Zend\Mvc\Controller\PluginManager.

Why proxy? The object returned via plugin factory has to implement

Zend\Mvc\Controller\Plugin\PluginInterface

which is abstractly implemented in

Zend\Mvc\Controller\Plugin\AbstractPlugin

so we created proxy object to forward all calls from our plugin to the Translate object.

Hope it helped!

I have published an article in my own blog.

Upvotes: 11

Clawfire
Clawfire

Reputation: 499

I guess there's a nicest way to do it :

$translator = $this->getServiceLocator()->get('translator');
$translator->translate('__your_key');

Upvotes: 1

Jurian Sluiman
Jurian Sluiman

Reputation: 13558

Translation is done via a Translator. The translator is an object and injected for example in a view helper, so if you call that view helper, it uses the translator to translate your strings. For this answer I assume you have configured the translator just the same as the skeleton application.

The best way is to use the factory to inject this as a dependency into your controller. The controller config:

'controllers' => array(
  'factories' => array(
    'my-controller' => function($sm) {
      $translator = $sm->getServiceLocator()->get('translator');
      $controller = new MyModule\Controller\FooController($translator);
    }
  )
)

And the controller itself:

namespace MyModule;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\I18n\Translator\Translator;

class FooController extends AbstractActionController
{
  protected $translator;

  public function __construct(Translator $translator)
  {
    $this->translator = $translator;
  }
}

An alternative is to pull the translator from the service manager in your action, but this is less flexible, less testable and harder to maintain:

public function fooAction()
{
  $translator = $this->getServiceManager()->get('translator');
}

In both cases you can use $translator->translate('foo bar baz') to translate your strings.

Upvotes: 18

Related Questions