Translating navigation breadcrumbs - zend-framework2

I'm trying to translate the breadcrumbs sitting in the module/Application/config/module.config.php configuration file like:
'navigation' => array(
'default' => array(
array(
'label' => \Application\Util\Translator::translate('Home'),
'route' => 'home',
'resource' => 'route/home',
'pages' => array(
),
),
The breadcrumb Home should display as Accueil in french.
The translator works just fine for the rest of the application. But none of the breadcrumbs are translated. The language resource file has been verified and poedit-ed again and again.
In the very same configuration file, is the translator
configuration:
'service_manager' => array(
'factories' => array(
'account_navigation' => 'Application\Navigation\Service\AccountNavigationFactory',
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
'Application\Collector\RouteCollector' => 'Application\Service\RouteCollectorServiceFactory',
),
),
'translator' => array(
'locale' => 'fr_FR', // langue par défaut
'translation_file_patterns' => array(
array(
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
),
),
'translation_files' => array(
array(
'type' => 'phpArray',
'filename' => __DIR__ . '/../../../vendor/zendframework/zendframework/resources/languages/fr/Zend_Validate.php',
'locale' => 'fr_FR'
),
array(
'type' => 'gettext',
'filename' => __DIR__ . '/../../../vendor/zf-commons/zfc-user/src/ZfcUser/language/fr_FR.mo',
'locale' => 'fr_FR'
),
array(
'type' => 'phpArray',
'filename' => __DIR__ . '/../language/fr_FR.php',
'locale' => 'fr_FR'
)
)
),
My application bootstrap looks like:
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$sm = $e->getParam('application')->getServiceManager();
// Add ACL information to the Navigation view helper
$authorize = $sm->get('BjyAuthorize\Service\Authorize');
$acl = $authorize->getAcl();
$role = $authorize->getIdentity();
\Zend\View\Helper\Navigation::setDefaultAcl($acl);
\Zend\View\Helper\Navigation::setDefaultRole($role);
$id = $sm->get('zfcuser_auth_service')->getIdentity();
if (! is_null($id)) {
$em = $sm->get('Doctrine\ORM\EntityManager');
$usr = $em->find('Application\Entity\User', $id->getId());
$blameableListener = new \Gedmo\Blameable\BlameableListener();
$blameableListener->setUserValue($usr);
$em->getEventManager()->addEventSubscriber($blameableListener);
} else {
// redirection
if (isset($_SERVER['SERVER_NAME']) && preg_match('/monxxxxx/', $_SERVER['SERVER_NAME'])) {
$strategy = new RedirectionStrategy();
$strategy->setRedirectRoute('driver/login');
$eventManager->attach($strategy);
}
}
if ($sm->has('MvcTranslator')) {
\Zend\Validator\AbstractValidator::setDefaultTranslator($sm->get('MvcTranslator'));
}
Locale::setDefault('fr_FR');
// custom layout
$e->getApplication()->getEventManager()->getSharedManager()->attach('Zend\Mvc\Controller\AbstractController', 'dispatch', function($e) {
$route = $e->getRouteMatch();
$controller = $e->getTarget();
// change layout for login
if($route->getParam('controller') == 'zfcuser' && $route->getParam('action') == 'login'){
$controller->layout('layout/login');
}
}, 100);
// Log the exceptions
$application = $e->getApplication();
$sm = $application->getServiceManager();
$sharedManager = $application->getEventManager()->getSharedManager();
$sharedManager->attach('Zend\Mvc\Application', 'dispatch.error',
function($e) use ($sm) {
if ($e->getParam('exception') && strpos($e->getParam('exception'), 'are not authorized') === false) {
$sm->get('Zend\Log\Logger')->crit($e->getParam('exception'));
$toEmail = "xxxxx#xxxxx.com";
$toName = "Service IT";
$subject = "Exception error";
$body = $e->getParam('exception');
\Application\Util\Common::sendMail($toEmail, $toName, $subject, $body);
}
}
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__
)
)
);
}
public function init($moduleManager)
{
$moduleManager->loadModule('ZfcUser');
}
}
I'm on ZF2 2.2.5.

Might be a silly question, but do you have the PHP gettext module (verified via your phpinfo())? If yes, you could much easier use _('Translatable string') for strings needing translation. You'd have a .mo and .po file in a language folder (next to src, public, etc.).
(Asking the above because you seem to be putting a lot of effort into this, even though your code shows you use gettext as a translator, which should allow you to already translate static strings, such as home in a config file)
As an example the picture below, it is the basic setup for one of my own ZF2 vendor modules:
Next, you'd need Poedit (Free version should be plenty.).
NOTE: Make sure to always use Poedit to edit the .mo/.po files.
Use Poedit to open the files in the language folder, no need to "translate" strings that are the same string as the language they should be, unless you're using shortcuts for strings (ie. "index" string should display "Show overview", but please don't :p)
Within Poedit you have a few options to add additional strings that it searches for in your files and you can also add additional file extensions. I would suggest you have it look for these strings:
$this->translate()
_()
and these file extensions:
.php
.phtml
That way you've covered the basics. Of course your setup may be different, so modify as needed.
Lastly, you need to register the usage of gettext PHP extensions in you module config. You need to do this for every module, as you need to give a language folder path, as that is where your module 'should' be translated (though feel free to make it global and have a huge translation file if you must, not recommended).
Add the following bit to your module.config.php file:
'translator' => [
'locale' => 'en_US', // This line needs to be in the "root" config, feel free to override with/per module settings and/or user settings
'translation_file_patterns' => [
[
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
],
],
],
With all of the above, translating your breadcrumbs should be done like so:
'navigation' => array(
'default' => array(
array(
'label' => _('Home'),
'route' => 'home',
'resource' => 'route/home',
'pages' => array(
),
),

It seems that namespace Zend\View\Helper\Navigation\Breadcrumbs; is not instanciated correctly in your service manager. Therefore, the translator will not work because it also provided by the service manager as a dependancy
What you should do is to verify if Zend\View\Helper\Navigation\Breadcrumbs::line#113 is actually parsed when you load your breadcrumbs. At least this one.
You can also check the method htmlify of AbstractHelper to test if the translator is enabled.

Related

zend 2 including custom library old style

I have custom libs in old style zend. I mean:
/home/my/libs/StandardTypes/UF.php
class StandardTypes_UF{
...
}
I've tried use this in Zend 2
I tried this codes:
//init_autoloader.php
...
include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
Zend\Loader\AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'prefixes' => array(
'StantardTypes' => '/home/my/libs/StandardTypes',
),
)
));
...
//controller
$st = new \StantardTypes_UF();
I have this error: Fatal error: Class 'Beneficio\Controller\StantardTypes_UF' not found
I tried this way too:
//Module.php
...
public function getAutoloaderConfig(){
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
'prefixes' => array(
'StantardTypes' => '/home/my/libs/StandardTypes',
),
),
);
}
...
I have the same error.
I cant change the libs to new style, first cuz it is too big, secund cuz it's used in old projects too.
Any ideia how to solve this?
The problem is that I can't use a path out of the project. I put the lib StandardTypes in vendor path and it works!
...
'prefixes' => array(
'StantardTypes' => '/home/my/project/vendor/StandardTypes',
),
....

ZF2 I would like to pass json string

I would like to pass json to action, something similar to passing simple variable:
/** module.config.php
'mobileapplication-topup' => array(
'type' => 'segment',
'options' => array(
'route' => '/mob/topup[/:voucherID]',
'constraints' => array(
'voucherID' => '[a-zA-Z][a-zA-Z0-9_-]*',
),
'defaults' => array(
'controller' => 'Mob\Controller\Topup',
'action' => 'index',
),
),
and TopupController.php
public function indexAction()
{
echo ($this->params('voucherID'));
$result = new ViewModel();
$result->setTerminal(true);
return $result;
}
//** no layout //
$response = $this->getResponse();
$response->setStatusCode(200);
$response->setContent("Error");
return $response;
}
something similar to this, but just a json string instead of voucherID. What kind of constraints should be added to this json variable?
** Is there any way how to POST the form from other domain to ZF2?
I have found solution, but I don't think it is a perfect one...
What I was thinking that there is some way of passing variables using route
mvc.com/controller/param1/param2
and into this for example just pass a json and decode it in one of the controllers...
but at the moment I'm using basing _GET method
mvc.com/controller/param1/param2?"Json"={"p1":"value1","p2":"value2"}

How to call on view on dyanmic actions in zf2

Hello friends I am new in zf2. I stuck at one place. In my project I want to to call one view on many action.
My url is "baseurl/g/any-thing-from-from-database"
I want to call a view on "any-thing-from-from-database" action from another module or same.
My G module have this code on module.config.php
return array(
'controllers' => array(
'invokables' => array(
'G\Controller\G' => 'G\Controller\GController',
),
),
'router' => array(
'routes' => array(
'g' => array(
'type' => 'segment',
'options' => array(
'route' => '/g[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'G\Controller\G',
'action' => 'g',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'g' => __DIR__ . '/../view',
),
),
);
on GController.php
namespace G\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Stdlib\ResponseInterface as Response;
use Zend\View\Renderer\PhpRenderer;
use Students\Form\StudentsForm;
use Students\Model\Students;
class GController extends AbstractActionController
{
public function dispatch(Request $request, Response $response = null)
{
$controller = $this->params('controller');
$nicname = $this->params('action');
if($nicname !== false){
$hosts = $this->getServiceLocator()->get('Manager\Model\HostsTable');
if(($data = $hosts->findByNicname($nicname)) !== null){
$captchaService = $this->getServiceLocator()->get('SanCaptcha');
$form = new StudentsForm($captchaService);
return array('from'=>$form);
}
}
return $this->redirect()->toRoute('home',array('controller'=>'application','action'=>'index'));
}
public function gAction()
{
return new ViewModel();
}
}
To get different actions from url I have used dispatch function that is working correctly. When i get this action from database I want to show a form with some content from different module named Students or G. But this code only showing header and footer and nothing else without any error.Please help me out.Thanks in advance.
I think overwriting dispatch method cannot be very good.
I'm sure you don't see anything, because you don't ever render a ViewModel, so no data are there. This is because you disabled default dispatch behaviour and overwrite the action argument in your route. So if you open http://my.website/g/foobar then foobarAction() would be called - if your dispatch will work correctly.
So what you could do is simple rename your action param to (for example) foo, take your logic to gAction() and do what ever you have to do with $this->param('foo').

Where to put custom settings in Zend Framework 2?

I have some custom application specific settings, I want to put in a configuration file. Where would I put these? I considered /config/autoload/global.php and/or local.php. But I'm not sure which key(s) I should use in the config array to be sure not to override any system settings.
I was thinking of something like this (e.g. in global.php):
return array(
'settings' => array(
'settingA' => 'foo',
'settingB' => 'bar',
),
);
Is that an agreeable way? If so, how can I access the settings e.g. from within a controller?
Tips are highly appreciated.
In case you need to create custom config file for specific module, you can create additional config file in module/CustomModule/config folder, something like this:
module.config.php
module.customconfig.php
This is content of your module.customconfig.php file:
return array(
'settings' => array(
'settingA' => 'foo',
'settingB' => 'bar',
),
);
Then you need to change getConfig() method in CustomModule/module.php file:
public function getConfig() {
$config = array();
$configFiles = array(
include __DIR__ . '/config/module.config.php',
include __DIR__ . '/config/module.customconfig.php',
);
foreach ($configFiles as $file) {
$config = \Zend\Stdlib\ArrayUtils::merge($config, $file);
}
return $config;
}
Then you can use custom settings in controller:
$config = $this->getServiceLocator()->get('config');
$settings = $config["settings"];
it is work for me and hope it help you.
You use your module.config.php
return array(
'foo' => array(
'bar' => 'baz'
)
//all default ZF Stuff
);
Inside your *Controller.php you'd call your settings via
$config = $this->getServiceLocator()->get('config');
$config['foo'];
It's as simple as that :)
You can use any option from the following.
Option 1
Create one file called config/autoload/custom.global.php. In custom.global.php
return array(
'settings' => array(
'settingA' => 'foo',
'settingB' => 'bar'
)
)
And in controller,
$config = $this->getServiceLocator()->get('Config');
echo $config['settings']['settingA'];
Option 2
In config\autoload\global.php or config\autoload\local.php
return array(
// Predefined settings if any
'customsetting' => array(
'settings' => array(
'settingA' => 'foo',
'settingB' => 'bar'
)
)
)
And in controller,
$config = $this->getServiceLocator()->get('Config');
echo $config['customsetting']['settings']['settingA'];
Option 3
In module.config.php
return array(
'settings' => array(
'settingA' => 'foo',
'settingB' => 'bar'
)
)
And in controller,
$config = $this->getServiceLocator()->get('Config');
echo $config['settings']['settingA'];
If you look in config/application.config.php it says:
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
So ZF2 by default will autoload configuration files from config/autoload/ - so for example you could have myapplication.global.php it would get picked up and added into the configuration.
Evan.pro wrote a blog post that touches on this: https://web.archive.org/web/20140531023328/http://blog.evan.pro/environment-specific-configuration-in-zend-framework-2

Zend Framework 2 Di creates class without parameters

I have the following code in config:
<?php
return array(
'di' => array(
'instance' => array(
'alias' => array(
'sms_message' => 'Sms\Message',
),
'sms_message' => array(
'parameters' => array(
'from' => 'SENDER',
),
),
),
),
);
And in Message.php class I have a setter (I dont want to use contructor):
/**
* From
* #var string
*/
protected $from;
/**
* #param string $from
*/
public function setFrom($from)
{
$this->from = $from;
}
But when I try to load it I get unconfigured object:
var_dump($this->getLocator()->get('Sms\Message'));exit;
object(Sms\Message)[596]
protected 'to' => null
protected 'from' => null
protected 'body' => null
How do I can make it work?
For setter-injection you have to use the injections keyword:
array(
'di' => array(
'instance' => array(
'alias' => array(
'sms_message' => 'Sms\Message'
),
'Sms\Message' => array(
'injections' => array(
'setFrom' => array(
'from' => 'SENDER'
),
),
),
),
),
);
I'm not sure if the instance configuration is supposed to work with aliases. Better use the FQCN instead.
I also discovered that currently injections are not executed when requesting an alias while reproducing your example:
// The will call setFrom(...)
$di->get('Sms\Message);
// This will not call setFrom(...)
$di->get('sms_message');
I don't know if this behavior is intended or not. (I'll report this test which is currently failing)

Resources