I have a site in zend framework . Now I am making site in multiple language. For it I need to modify the url.
For example if sitename is www.example.com then i want to make it like
www.example.com/ch
www.example.com/fr
There can be some work around it that you can ask me to create a folder name ch and put a copy of code inside it. But for it I have to manage multiple folder when updating files on server.
What is the best or correct way to do it ?
My routs code is
public function _initRouter() {
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$routes = array(
'page' => new Zend_Controller_Router_Route('page/:slug', array('controller' => 'staticpage', 'action' => 'page', 'slug' => ''))
);
$router->addRoutes($routes);
}
Thanks
You have to add the language as parameter in your route(s). Here is an example: http://devzone.zend.com/1765/chaining-language-with-default-route/
You need a function to get a user choice of a language and a default language used if a user just starts with example.com.
You may want to get the current browser and Language Header from the users HTTP request.
Take a look at Zend_Locale and Zend_Translate.
You can use something like $locale = new Zend_Locale('browser'); to detect the users browser language.
Then look if Zend_Translate or your translation engine has the language available and set it to a cookie or session to store the date.
If the user then navigate to some language change site like example.com/?language=en you may want to set the locale based on the user choice and recheck if available in your translations.
If not, get back to original default language and present an error page or something like that.
If you want to get your Zend_Router urls to be language dependent, which might be a bad choice because of copy paste, backlinks or forum posts of your links, you need to add something before each route.
In my Applications i use something like the following in my main bootstrap.php file. I've cut some parts of to keep it simple.
protected function _initTranslate() {
$session = new Zend_Session_Namespace("globals");
// Get current registry
$registry = Zend_Registry::getInstance();
/**
* Set application wide source string language
* i.e. $this->translate('Hallo ich bin ein deutscher String!');
*/
if(!$session->current_language) {
try {
$locale = new Zend_Locale('browser'); //detect browser language
}
catch (Zend_Locale_Exception $e) {
//FIXME: get from db or application.ini
$locale = new Zend_Locale('en_GB'); //use the default language
}
}
else {
$locale = new Zend_Locale($session->current_language);
}
$translate = new Zend_Translate(
array(
'adapter' => 'array',
'content' => realpath(APPLICATION_PATH . '/../data/i18n/'),
'locale' => $locale,
'scan' => Zend_Translate::LOCALE_DIRECTORY,
'reload' => false,
'disableNotices' => true, //dont get exception if language is not available
'logUntranslated' => false //log untranslated values
)
);
if(!$translate->isAvailable($locale->getLanguage())) {
$locale = new Zend_Locale('en_GB'); //default
}
$translate->setLocale($locale);
$session->current_language = $locale->getLanguage();
//Set validation messages
Zend_Validate_Abstract::setDefaultTranslator($translate);
//Max lenght of Zend_Form Error Messages (truncated with ... ending)
Zend_Validate::setMessageLength(100);
//Zend_Form Validation messages get translated into the user language
Zend_Form::setDefaultTranslator($translate);
/**
* Both of these registry keys are magical and makes do automagical things.
*/
$registry->set('Zend_Locale', $locale);
$registry->set('Zend_Translate', $translate);
return $translate;
}
This is for the default translation setup of each visitor.
To set a user language depending on some HTTP parameters, I decided to create a Plugin, which will run on each request, see if the global language parameter is set (key=_language) and try setting the new language.
I then redirect the user to the new route, depending on his choice.
So, if the user click on the link for english language (example.com/de/test/123?_language=en) he will get redirected to example.com/en/test/123.
class Application_Plugin_Translate extends Core_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$frontController = Zend_Controller_Front::getInstance();
// Get the registry object (global vars)
$registry = Zend_Registry::getInstance();
// Get our translate object from registry (set in bootstrap)
$translate = $registry->get('Zend_Translate');
// Get our locale object from registry (set in bootstrap)
$locale = $registry->get('Zend_Locale');
// Create Session block and save the current_language
$session = new Zend_Session_Namespace('globals');
//get the current language param from request object ($_REQUEST)
$language = $request->getParam('_language',$session->current_language);
// see if a language file is available for translate (scan auto)
if($translate->isAvailable($language)) {
//update global locale
$locale = $registry->get('Zend_Locale');
$locale->setLocale($language);
$registry->set('Zend_Locale', $locale);
//update global translate
$translate = $registry->get('Zend_Translate');
$translate->setLocale($locale);
$registry->set('Zend_Translate', $translate);
//language changed
if($language!=$session->current_language) {
//update session
$session->current_language = $language;
$redirector = new Zend_Controller_Action_Helper_Redirector;
$redirector->gotoRouteAndExit(array());
}
}
else {
$request->setParam('_language', '');
unset($session->current_language);
$redirector = new Zend_Controller_Action_Helper_Redirector;
$redirector->gotoRouteAndExit(array());
}
}
}
And finally, to prepare your router with the new language routes, you need to setup a base language route and chain your other language depending routes.
public function _initRouter() {
$frontController = Zend_Controller_Front::getInstance();
$router = $frontController->getRouter();
$languageRoute = new Zend_Controller_Router_Route(
':language',
array(
'language' => "de"
),
array('language' => '[a-z]{2}')
);
$defaultRoute = new Zend_Controller_Router_Route(
':#controller/:#action/*',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index'
)
);
$router->addRoute(
'default',
$defaultRoute
);
$languageDefaultRoute = $languageRoute->chain($defaultRoute);
$router->addRoute(
'language',
$languageDefaultRoute
);
}
Good luck with your project, hope it will help you and others!
Related
I'm using Yii2 and I want to create a web application with the ability to perform fast searches.
For example, when I type characters in a textbox, results displayed.
It's easy with ajax when we have only one language but how about in multilingual mode?
First set up multi language for your site there is doc for this.
Best way of auto support multi language for your site is using cookies variable for language. You can set up language cookies from any action as
public function actionLanguage()
{
if (isset($_POST['lang'])) {
$language = $_POST['lang'];
if (($langaugeModel = \app\models\Langauge::findOne(['name' => $language])) !== null) {
$varLang = [
'id' => $langaugeModel->id,
'name' => $langaugeModel->name,
'iso1' => $langaugeModel->iso1,
'iso2' => $langaugeModel->iso2
];
$cookies = new Cookie([
'name' => 'lang',
'value' => json_encode($varLang),
]);
yii::$app->getResponse()->getCookies()->add($cookies);
return $this->goBack((!empty(Yii::$app->request->referrer) ? Yii::$app->request->referrer : null));
} else {
throw new NotFoundHttpException('The requested langauge does not exist.');
}
} else {
return $this->goBack((!empty(Yii::$app->request->referrer) ? Yii::$app->request->referrer : null));
}
}
Here what I did was i placed all the language support of site in database and generate necessary cookies variable and placed it on client browser.
Next set up be before request event of your yii2 site in config/web.php file as
'as beforeRequest' => [
'class' => 'app\components\MyBehavior',
],
then create components\Mybehaviou.php file and place this code
namespace app\components;
use yii;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public function events(){
return [
\yii\web\Application::EVENT_BEFORE_REQUEST => 'myBehavior',
];
}
public function myBehavior(){
if (\yii::$app->getRequest()->getCookies()->has('lang')) {
$langIso = 'sdn';
\yii::$app->language = $langIso;
$langaugeVar = \yii::$app->getRequest()->getCookies()->getValue('lang');
$langauge = json_decode($langaugeVar);
$langIso = $langauge->iso2;
\yii::$app->language = $langIso;
}
}
}
This create your site language which depends on client because it depends on cookies of client.
Then create your search controller according to site language(\yii::$app->language)
for ajax search you can use select2 Widget. you can find demo and configuration on this link
Hi I'm new to the php world.
I'm wondering What is the best way to handle multilingual routing ?
I'm starting to create a website with Phalcon php.
I have the following routing structure.
$router->add('/{language:[a-z]{2}}/:controller/:action/:params', array(
'controller' => 2,
'action' => 3,
'params' => 4,
));
$router->add('/{language:[a-z]{2}}/:controller/:action', array(
'controller' => 2,
'action' => 3,
));
$router->add('/{language:[a-z]{2}}/:controller', array(
'controller' => 2,
'action' => 'index',
));
$router->add('/{language:[a-z]{2}}', array(
'controller' => 'index',
'action' => 'index',
));
My problem is for instance when I go on mywebsite.com/ I want to change my url in the dispatcher like mywebsite.com/en/ or other language. Is it a good practise to handle it in the beforeDispatchLoop ? I seek the best solutions.
/**Triggered before entering in the dispatch loop.
* At this point the dispatcher don't know if the controller or the actions to be executed exist.
* The Dispatcher only knows the information passed by the Router.
* #param Event $event
* #param Dispatcher $dispatcher
*/
public function beforeDispatchLoop(Event $event, Dispatcher $dispatcher)
{
//$params = $dispatcher->getParams();
$params = array('language' => 'en');
$dispatcher->setParams($params);
return $dispatcher;
}
This code doesn't work at all, my url is not change. The url stay mywebsite.com/ and not mywebsite.com/en/
Thanks in advance.
I try one solution above.
The redirect doesn't seems to work. I even try to hard-coded it for test.
use Phalcon\Http\Response;
//Obtain the standard eventsManager from the DI
$eventsManager = $di->getShared('eventsManager');
$dispatcher = new Phalcon\Mvc\Dispatcher();
$eventsManager->attach("dispatch:beforeDispatchLoop",function($event, $dispatcher)
{
$dispatcher->getDI->get('response')->redirect('/name/en/index/index/');
}
I think you are confusing something. If I understand correctly: you want to redirect users to a valid url if they open a page without specifying a language.
If that's the case you should verify in your event handler whether the language parameter is specified and redirect user to the same url + the default language if its missing. I am also assuming that your beforeDispatchLoop is located in your controller, which is also part of the problem, because your route without a language never matches and you never get into that controller. Instead you need to use it as an event handler with the event manager as per the documentation. Here is how you do the whole thing.
$di->get('eventsManager')->attach("dispatch:beforeDispatchLoop", function(Event $event, Dispatcher $dispatcher)
{
$params = $dispatcher->getParams();
// Be careful here, if it matches a valid route without a language it may go into a massive
// recursion. Really, you probably want to use `beforeExecuteRoute` event or explicitly
// check if `$_SERVER['REQUEST_URI']` contains the language part before redirecting here.
if (!isset($params['language']) {
$dispatcher->getDI->get('response')->redirect('/en' . $_SERVER['REQUEST_URI']);
return false;
}
return $dispatcher;
});
I have two modules (default and mobile) the module mobile is a rewrite the default portal in jquery mobile but with much less controllers and actions!
I thought of write a controller plugin that check if controller and action exist in module mobile, if not I would like overwrite the module mobile to default.
I try this:
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
$dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
if ($request->getModuleName() == 'mobile') {
if (!$dispatcher->isDispatchable($request)) {
// Controller or action not exists
$request->setModuleName('default');
}
}
return $request;
}
but $dispatcher->isDispatchable($request) return always true though the action not exist! :S
and i receive "Action foo does not exist and was not trapped in __call()"
How can I do?
Thanks
Have you ever wondered how to check if a controller/action exist in zend FM from any side of app ? Here is the code
$front = Zend_Controller_Front::getInstance();
$dispatcher = $front->getDispatcher();
$test = new Zend_Controller_Request_Http();
$test->setParams(array(
'action' => 'index',
'controller' => 'content',
)
);
if($dispatcher->isDispatchable($test)) {
echo "yes-its a controller";
//$this->_forward('about-us', 'content'); // Do whatever you want
} else {
echo "NO- its not a Controller";
}
EDIT
Check like this way
$classMethods = get_class_methods($className);
if(!in_array("__call", $classMethods) &&
!in_array($this->getActionMethod($request), $classMethods))
return false;
and also please see detail link
I would suggest you make a static or dynamic routes either via config resource manager, bootstrap or via front controller plugin:
Example of defining static routes in Bootstrap.php:
public function _initRoutes()
{
$front = Zend_Controller_Front::getInstance();
$router = $front->getRouter(); // default Zend MVC routing will be preserved
// create first route that will point from nonexistent action in mobile module to existing action in default module
$route = new Zend_Controller_Router_Route_Static(
'mobile/some-controller/some-action', // specify url to controller and action that dont exist in "mobile" module
array(
'module' => 'default', // redirect to "default" module
'controller' => 'some-controller',
'action' => 'some-action', // this action exists in "some-controller" in "default" module
)
);
$router->addRoute('mobile-redirect-1', $route); // first param is the name of route, not url, this allows you to override existing routes like default route
// repeat process for another route
}
This would effectively route request for /mobile/some-controller/some-action to /default/some-controller/some-action
some-controller and some-action should be replaced with proper controller and action names.
I was using static routing which is ok if you route to exact urls, but since most applications use additional params in url for controller actions to use, it is better to use dynamic routes.
In above example simply change route creation class to Zend_Controller_Router_Route and route url to "mobile/some-controller/some-action/*" and every request will be routed dynamically like in example:
/mobile/some-contoller/some-action/param1/55/param2/66
will point to
/default/some-controller/some-action/param1/55/param2/66
For more info about routing in ZF1 check this link
I'm new to Zend, so pls help me out on this one, since I have searched a lot and tried a lot, I really did.
here is the very old question:
this is my current url:
www.sample.com/blog/detail/index/id/5
wanted:
www.sample.com/url-rewrite-tips
well, I put following code in the bootstrap.php
$router = Zend_Controller_Front::getInstance()->getRouter();
$route = new Zend_Controller_Router_Route(
'url-rewrite-tips',
array(
'module' => 'blog',
'controller' => 'detail',
'action' => 'index',
'id' => '5'
)
);
$router->addRoute('url-rewrite-tips', $route);
it was working, but it also is a hardcode. i tried to get param in bootstrap.php, but failed.
Now, I have more than 100 ids. However, I tried to put it in index.pthml, in a foreach(){} , then it fails.
I have rewrite names in the DB for every article, how am I supposed to it?
better not use configs or .htaccess
Thanks In advanced.
What I always do is I add the routes.ini execution in bootstrap:
protected function _initRoutes()
{
$this->bootstrap('FrontController');
$front = $this->getResource('FrontController');
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/routes.ini', 'production');
$router = $front->getRouter();
$router->addConfig($config, 'routes');
}
Then in routes.ini:
[production]
routes.content.route = "/s/:permalink"
routes.content.defaults.controller = "content"
routes.content.defaults.action = "show"
routes.content.reqs.permalink = "[a-z0-9-]+"
So now when someone access http://mydomain.com/s/some-nice-permalink routing goes to ContentController ShowAction() method, which takes permalink as param and finds it in database.
Of course you'll have to also write methods for creating unique permalinks in database.
Lets say I have a simple form:
class Form_Simple extends Zend_Dojo_Form
{
public function init() {
$this->addElements(array(
new Zend_Dojo_Form_Element_ValidationTextBox('name', array(
'required' => true,
'label' => 'Name:'
))
}
}
"name" element is required so error message will be "this field is required". How change this message?
You can localize the form labels just like in any other part of your application.
In your bootstrap file you have to setup the Zend_Locale and Zend_Translate object. It will be avialable in your entire application.
E.g in your boostrap:
//init locale
$translate = new Zend_Translate('gettext',
APPLICATION_PATH.'/languages',null,
array('scan' => Zend_Translate::LOCALE_FILENAME));
$locale = new Zend_Locale();
$locale->setLocale(Zend_Locale::BROWSER);
$requestedLanguage = key($locale->getBrowser());
if(in_array($requestedLanguage, $translate->getList())){
$language = $requestedLanguage;
}else{
$language = 'en';
}
$translate->setLocale($language);
$view->translate = $translate;
Since the setup is really detailed and maybe complex I recommend you to watch this tutorial http://www.youtube.com/watch?v=FwPgqla-cRk