Basic use of TranslationServiceProvider in Silex - translation

I'm trying to use the Silex TranslationServiceProvider in the most straighforward way i.e.
<?php
// web/index.php
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
$app->register(new Silex\Provider\TranslationServiceProvider(), array(
'locale' => 'fr',
'locale_fallbacks' => array('en')
));
$app['translator.domains'] = array(
'messages' => array(
'en' => array('message_1' => 'Hello!'),
'fr' => array('message_1' => 'Bonjour')
));
echo $app['translator']->trans('message_1');
// I get 'Hello!' (why ?)
It seems that the 'locale' => 'fr' line when initializing the TranslationServiceProvider is not taken into account and that the only parameter that counts is locale_fallbacks (when I change locale_fallbacks to 'fr', the message is displayed in french)
Is there something very simple I am missing here ?
Thanks in advance
Edit
When I use the the setLocale function, it still doesn't work and seems to override the locale_fallbacks:
$app->register(new Silex\Provider\TranslationServiceProvider(), array(
'locale_fallbacks' => array('en')
));
$app['translator']->setLocale('fr');
echo $app['translator']->getLocale(); // returns 'fr' as expected
$app['translator.domains'] = array(
'messages' => array(
'en' => array('message_1' => 'Hello!'),
'fr' => array('message_1' => 'Bonjour')
));
echo $app['translator']->trans('message_1');
// now returns 'message_1' (??)
What's wrong with the way I use the provider ?

You must set the locale, otherwise the fallback is used:
$app['translator']->setLocale('fr');
I'm setting the locale in a $app->before() handler:
$app->before(function(Request $request) use ($app) {
// default language
$locale = 'en';
// quick and dirty ... try to detect the favorised language - to be improved!
if (!is_null($request->server->get('HTTP_ACCEPT_LANGUAGE'))) {
$langs = array();
// break up string into pieces (languages and q factors)
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$request->server->get('HTTP_ACCEPT_LANGUAGE'), $lang_parse);
if (count($lang_parse[1]) > 0) {
foreach ($lang_parse[1] as $lang) {
if (false === (strpos($lang, '-'))) {
// only the country sign like 'de'
$locale = strtolower($lang);
} else {
// perhaps something like 'de-DE'
$locale = strtolower(substr($lang, 0, strpos($lang, '-')));
}
break;
}
}
$app['translator']->setLocale($locale);
$app['monolog']->addDebug('Set locale to '.$locale);
}
});

Two remarks on Ralf’s answer:
Almost all that is done in the before() middleware in unnecessary, as the Request class provides a convenience method for determining the “best” language based on the “Accept-Language” header. So basically, nothing more than this is required:
$app->before(
function (Request $request) use ($app) {
$app['translator']->setLocale($request->getPreferredLanguage(['en', 'fr']));
}
);
Silex uses the “magic” variable “{_locale}” in a route’s definition to set the locale accordingly. This means you do neither need to declare the locale when instantiating TranslationServiceProvider, nor call setLocale(), but simply declare the route like this:
$app->get('/{_locale}/path', ...);
Now, Twig and $app['translator'] (inside the Closure or controller method) will automatically be set to the correct locale.

Related

How can i have different translations for action controller in TYPO3?

Is it possible to have a localization based on RealURL's valueMap static table ?
For example, in Deutsch language, I have www.example.com/de/account/produktinfos/
de/ is language
account/ page
produktinfos/ controller action
And what I need is to translate the produktinfos/part to English, i.e., www.example.com/en/account/productinfo/.
Is there a way to translate the controller action in RealURL?
I don't know if this help for you.
You can use some realurl post/pre Procs.
for example:
// realurl Hook for replacing some path
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'] = array(
'encodeSpURL_postProc' => array('user_encodeSpURL_postProc'),
'decodeSpURL_preProc' => array('user_decodeSpURL_preProc')
);
and replace controller action in URL
function user_encodeSpURL_postProc(&$params, &$ref) {
$params['URL'] = str_replace('job/job/Job/show/', 'job/', $params['URL']);
}
function user_decodeSpURL_preProc(&$params, &$ref) {
$params['URL'] = str_replace('job/', 'job/job/Job/show/', $params['URL']);
}
the blog post
https://www.kartolo.de/2014/11/21/extbase-and-realurl/
An other solution can be like that?
// news pagebrowser
'my-action' => array(
array(
'GETvar' => 'tx_myext[action]',
'valueMap' => array(
preg_match('%/de/%',$_SERVER['REQUEST_URI'])==1?'anzeigen':'show' => 'show',
)
),
),

ZF2 get url param and redirect on dispatch_error event

I have the code to change the language of site. I would like to extend this functional. I want to make sure that the language parameter in the url is correct when I get the 404 page (or dispatch_error event).
My route example
'about' => array(
'type' => 'Segment',
'options' => array(
'route' => '/[:lang/]about',
'constraints' => array(
'lang' => '[a-zA-Z]{2}?',
),
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'about',
'lang' => 'en',
),
),
),
If url param isn't correct (example.com/e/about or exampleDotcom//about), then makes redirect to the specific page (for example, example.com/why_did_it_happen). To make this, I create a function checkRedirect and attach it to EVENT_DISPATCH_ERROR . But how to get the LANG parameter from the url and then make a redirect, I don't know. I tried to do this many times, but could not. I've got - Call to a member function getParam () on a non-object. What code would I append to the checkRedirect function to get the LANG parameter from the url and then make a redirect in this function?
My code in Module.php
class Module implements
AutoloaderProviderInterface,
ConfigProviderInterface,
ViewHelperProviderInterface {
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager->attach(MvcEvent::EVENT_ROUTE, array($this, 'initLocale'), -100);
$eventManager->attach(MvcEvent::EVENT_DISPATCH_ERROR, array($this, 'checkRedirect'), -101);
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'preDispatch'), 100);
}
public function initLocale(MvcEvent $e) {
$translator = $e->getApplication()->getServiceManager()->get('translator');
$config = $e->getApplication()->getServiceManager()->get('Config');
$shotLang = $e->getRouteMatch()->getParam('lang'); //or $e->getApplication()->getMvcEvent()->getRouteMatch();
if (isset($config['languages'][$shotLang])) {
$translator->setLocale($config['languages'][$shotLang]['locale']);
} else {
$lang = array_shift($config['languages']);
$translator->setLocale($lang['locale']);
}
}
public function checkRedirect(MvcEvent $e) {
//code here
}
$e->getRouteMatch()->getParam('NAME')
This does work, but 'NAME', but be the name given in the routes.
'route' => '/[:lang/]about',
However, the above route does not match the route *example.com/why_did_it_happen*
Try changing your route to
'route' => '[/:lang]/about',
And you could always default, if a lang is not supplied, i.e.
$e->getRouteMatch()->getParam('lang', 'en');

Dynamically set SELECT attribute in zend2

What I am actually doing is, fetching a list of companies from the database and passing that to the form SELECT element.
So I created a Model file, which returns an array
//=== return an array of $ID => $name of companies to use in dropdown in reports form
public function getTotalResult($table, $type, $id) {
$this->table = $table;
$select = new Select();
$spec = new Where();
$spec->equalTo('status', 1);
if ($type == 'name') {
$spec->equalTo('id', $id);
}
$select->from($this->table);
$select->where($spec);
$resultSet = $this->selectWith($select);
//$resultSet->buffer();
return $resultSet;
}
public function resultList($table){
$results = $this->getTotalResult($table, '', '');
foreach ($results as $result) {
$this->id[] = $result->id;
$this->name[] = $result->name;
}
$result = array_combine($this->id, $this->name);
return $result;
}
Then I tested this in my Controller, which returned exactly what I wanted:
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use SpangelLogin\Model\Register; // <-- Add this import
use SpangelLogin\Model\companyList; // <-- Add this import
class RegisterController extends AbstractActionController
{
protected $registerTable;
protected $companyList;
public function getcompanyList()
{
if (!$this->companyList) {
$sm = $this->getServiceLocator();
$this->companyList = $sm->get('SpangelLogin\Model\companyList');
}
return $this->companyList;
}
public function indexAction()
{
//== get list of companies
$company_table = 'rs_company';
$sector_table = 'rs_sector';
$companiesList = $this->getcompanyList()->getName($company_table, 2);
}
}
So now I want this companiesList array passed in my form's Select Element. How can I achieve that. Here is my form in which I am using select.
use Zend\Form\Form;
use Zend\Form\Element;
class SectorReportForm extends Form
{
public function __construct($name = null)
{
// we want to ignore the name passed
parent::__construct('sectorreport');
$companiesArray = $this->companiesList();
$sectorsArray = $this->sectorsList();
$this->setAttribute('method', 'post');
$this->setAttribute('enctype','multipart/form-data');
$this->add(array(
'type' => 'Zend\Form\Element\Select',
'name' => 'company',
'attributes' => array(
'id' => 'company',
'multiple' => true,
'options' => $companiesArray,
),
'options' => array(
'label' => 'Company',
),
));
$this->add(array(
'name' => 'submit',
'attributes' => array(
'type' => 'submit',
'value' => 'Upload',
'id' => 'submitbutton',
'class' => 'button violet right'
),
));
}
}
From a Design-Perspective, the best approach would be to handle this via Dependency-Injection. That sneaky little buzzword that confuses people so much, but actually is nothing more but to forward data between objects :P
General Dependency-Injection for Forms can be seen looking at the following answer, as well as my Blog article
How to get data from different model for select?
Zend\Form\Element\Select and Database-Values
If you do not want to go this approach, you can handle this at the Controller level, too.
$form = new My\Form();
$select = $form->get('selectCountries');
$model = new My\Countries();
$listData = $model->getCountriesAsArray();
$select->setValueOptions($listData);
I still advise you to go the different approach ;) Keeps the controllers more clean, too, which is always a good thing. Separation of concern!

Global and module config interaction

Let's imagine I have global application configuration
return array(
'languages' => array(
'allowed' => array('de', 'en'),
),
);
And I have module configuration with the routes description. I need routes, based on global configuration, so I need to read global application config within the module to compose my routes according to languages->allowed values (constraints for the segment type route)
What is the best way to get global configuration values from the module configuration script? is it correct at all to manipulate data in configuration file instead of simple array return?
You should think a bit more ahead of your problem. You want to create a route structure based on your configuration. The configuration could come from everywhere: module config, local config and global config. It is therefore quite hard to base your module's config on a global one.
What you can do, is create the routes later. For example, you create in your module Foo the config like this:
'routes_foo' => array(
'bar' => array(
'type' => 'segment',
'options' => array(
'route' => ':locale/foo/bar',
'constraints' => array(
'locale' => '%LOCALE%',
),
),
),
),
And in your module class:
namespace Foo;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$config = $sm->get('config');
$routes = $config['routes_foo');
$locales = $config['languages']['allowed'];
$routes = $this->replace($routes, array(
'%LOCALE%' => sprintf('(%s)', implode('|', $locales)
);
$router = $sm->get('router');
$router->routeFromArray($routes);
}
public function replace($array, $variables)
{
foreach ($array as $key => $value) {
if (is_array($value)) {
$array[$name] = $this->replace($value, $variables);
}
if (array_key_exists($value, $variables)) {
$array[$name] = $variables[$value];
}
}
return $array;
}
}
What happens is you grab the routes from your config (those are not automatically injected in the router). There you also load all languages from your global config. Then your "custom" routes have (at several places) a "magic" configuration key, which will be replaced by a regex constraint for the locales: (en|de). That parsed config is then injected into the router.

cakePHP passing URLs as a param

I have an ImportController with a function admin_getcontents.
function admin_getcontents($url = null)
{
$contents = json_decode(file_get_contents(($url)),true);
//some stuff
}
Through ajax I call /admin/import/getcontents/ with:
$.get('/admin/import/getcontents/'+ encodeURIComponent($('#urlcheck').val()) ,function(data) {
$('#importtable').html(data);
$('#busy-indicator').fadeOut('high');
});
so I call the page: /admin/import/getcontents/http%3A%2F%2Flocalhost%2Feclipse%2Fanarxeio%2Fexport%2Fcontents%2F
Apache gives me an 404 error. If I call /admin/import/getcontents/1 the page loads correctly. So I figured to pass a ? before the parameter like:
admin/import/getcontents/?http%3A%2F%2Flocalhost%2Feclipse%2Fanarxeio%2Fexport%2Fcontents%2F
Now I don't get a 404 error but $url param in admin_getcontents() is empty. How can I achieve the above?
Thanks
A quick fix would be to triple url encode your url:
// javascript
$.get('/admin/import/getcontents/'+ encodeURIComponent(encodeURIComponent(encodeURIComponent($('#urlcheck').val()))) ,function(data) {
$('#importtable').html(data);
$('#busy-indicator').fadeOut('high');
});
Then url decode it in your php before you use it:
// php
function admin_getcontents($url = null)
{
$url = urldecode(urldecode($url));
$contents = json_decode(file_get_contents(($url)),true);
//some stuff
}
EDIT following comments:
You will need to set up your routing to pass the url parameter. Looking at your setup, it should looking something like:
Router::connect('/admin/import/getcontents/:url', array(
'controller' => 'import',
'action' => 'getcontents',
'admin' => true),
array(
'url' => '(.*)',
'pass' => array('url')
)
);

Resources