zf3 change locale depending on user selection

1.8k Views Asked by At

I have Zend Framework 3 Application with working translator using po files.

I have configured it like this in my \config\global.php file:

'translator' => [
    'locale' => 'en_US',
    'translation_file_patterns' => [
        [
            'type'     => 'gettext',
            'base_dir' => getcwd() .  '/data/language/',
            'pattern'  => '/%s/general.mo',
        ],
    ],
],

When i change the value of the "locale" it works ok and finds the proper .po file. I need to be able to set the locale depending on a user profile's value saved in the database.

I have checked the documentation from here http://zendframework.github.io/zend-i18n/translation/ and the tutorial from here https://docs.zendframework.com/tutorials/i18n/ but they just mention the setLocale() method with no explanation or example. There is similar thread here Zend framework 2 : How to set locale globaly? but it's for ZF2 and it doesn't provide working solution just some suggestions.

To summarize my question - how and where should i use the setLocale() method so it would be effective in the whole application and $this->translate($message) in all view files will use the new locale instead the default one used in the configuration file?

1

There are 1 best solutions below

3
On

You just need to set the PHP locale. To do so, use \Locale::setDefault('en-GB');.

Have a look at SlmLocale, this specific file is where it's done.


While that was the easiest way, you could also use the setLocale function on the MvcTranslator I guess. For that, you would need to override the existing factory with your own factory, therefore decorating the original one.

If you look at the ConfigProvider file in zend-mvc-i18n, you can see that aliases and factories are used here to create the MVC translator. Then you can see how the factory in question works, it basically creates a decorate translator, as stated in the doc.

By default, the service manager always provide the same instance (shared service), just like a singleton.

What we will therefore do is override this configuration (ie. make sure your own module is after the Zend\Mvc\I18n in modules.config.php). Then, in the module configuration, we can provide our own translator.

Our translator basically consist of the translator from the documentation, on which the setLocale is called. In order to do so, we can use a delegator.

return [
    'factories' => [
        TranslatorInterface::class => TranslatorServiceFactory::class,
    ],
    'delegators' => [
        TranslatorInterface::class => [
            \Application\Factory\TranslatorFactory::class,
        ],
    ],
];

And then the TranslatorFactory:

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\DelegatorFactoryInterface;

class TranslatorFactory implements DelegatorFactoryInterface
{
    public function __invoke(ContainerInterface $container, $name, callable $callback, array $options = null)
    {
        $translator = call_user_func($callback);
        $translator->setLocale('en-GB');
        return $translator;
    }
}

That would be one way to do it (you get the container in that factory, so you could get some user data probably).


Another solution is to use the event system, and only declare the locale in the event listener where you retrieve your user details.