Codeigniter i18n - Hide default_controller language Segment in URL - php

Everything with my i18n library is perfect except 1 little issue:
I want to make 1 home page to choose a language with links (lead to: en, fr, bg, ...):
Example: BG, EN
But always my default_uri is for an example: /bg and opens: www.mysite.com/bg
I want just to load plain URL up there as: www.mysite.com, load my START.PHP controller (no matter what name is, but not to be www.mysite.com/start) and after this to redirect with links to somewhere (bg/, en/, fr/)
Seems to be not so hard but don't know how to fix it
In MY_Lang.php:
// languages
var $languages = array(
'bg' => 'bulgarian',
'en' => 'english',
'fr' => 'french'
);
// special URIs (not localized)
var $special = array (
"admin", "start"
);
// where to redirect if no language in URI
var $default_uri = '';
In my routes.php:
$route['default_controller'] = "start";
$route['404_override'] = '';
// URI like '/en/about' -> use controller 'about'
//$route['(\w{2})/(.*)'] = '$2';
//$route['(\w{2})'] = $route['default_controller'];
$route['^(bulgarian|english|french)/(.+)$'] = "$2";
// '/en', '/de', '/fr' and '/nl' URIs -> use default controller
$route['^(bulgarian|english|french)$'] = $route['default_controller'];

I had a similar situation. For me the solution was that:
https://github.com/oleurud/Codeigniter_Multi-language_Package

Related

how to make codeigniter route support small and big for first letter without running 2 difference loop

All my controller file is start w 1st Big letter.
my code below if i link to Project/Admin/Career it link to my Career.php
but if f i link to Project/Admin/career it link to my Admin.php
my question is how do it make $route support both small and big for 1st letter
or i need to duplicated my method_arr to another method_arr1 and run foreach again (with array start small letter ) ?
Ex: Career, career
$method_arr=array(
'Career',
'Contact',
'Googlemap',
'Introduction',
'Slideshow'
);
$route['default_controller'] = "home";
foreach($method_arr as $method_arr){
$route['Admin/'.$method_arr] = 'backend/'.$method_arr;
}
In URL's uppercase is distinct from lowercase in millions of ways because of the way it was meant to be unique.
Well you can go about it this way:
$route['default_controller'] = "home";
foreach($method_arr as $method_arr){
$route['Admin/'.strtolower($method_arr)] = 'backend/'.$method_arr;
$route['Admin/'.$method_arr] = 'backend/'.$method_arr;
}
Without going into the oddity of doing it this way, a simple fix would be to define your routes twice. Using the example you provided you can do this to operate on lowercase or upper case.
$route['default_controller'] = "home";
$method_arr=array(
'Career',
'Contact',
'Googlemap',
'Introduction',
'Slideshow'
);
foreach($method_arr as $method_arr){
$route['Admin/'.$method_arr] = 'backend/'.$method_arr;
}
$method_arr=array(
'career',
'contact',
'googlemap',
'introduction',
'slideshow'
);
foreach($method_arr as $method_arr){
$route['Admin/'.$method_arr] = 'backend/'.$method_arr;
}

Zend Framework - setting up user-friendly URLs with routes and regex

I have two issues with user-friendly URLs.
I have a router set up as follows:
The actual URL is http://www.example.com/course/view-batch/course_id/19
I want a friendlier URL http://www.example.com/java-training/19
I have setup the following route in application.ini:
resources.router.routes.viewbatchcourse.route = "/:title/:course_id/"
resources.router.routes.viewbatchcourse.defaults.controller = course
resources.router.routes.viewbatchcourse.defaults.action = view-batch
resources.router.routes.viewbatchcourse.reqs.course_id = "\d+"
This works perfectly well.
Now I have a new page - which contains user reviews for Java
The actual URL is http://www.example.com/course/view-reviews/course_id/19
I want a friendlier URL http://www.example.com/java-reviews/19
I realize its not possible because one route is already setup to match that format.
So I was thinking if its possible to use regex and check if title contains "reviews" then use this route.
I tried this approach, but it doesn't work. Instead, it opens the view-batch page:
resources.router.routes.viewreviews.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.viewreviews.route = "/:title/:course_id"
resources.router.routes.viewreviews.defaults.controller = "course"
resources.router.routes.viewreviews.defaults.action = "view-reviews"
resources.router.routes.viewreviews.reqs.course_id = "\d+"
resources.router.routes.viewreviews.reqs.title = "\breviews\b"
The closest I have got this to work is
resources.router.routes.viewreviews.route = "/:title/:course_id"
resources.router.routes.viewreviews.defaults.controller = "course"
resources.router.routes.viewreviews.defaults.action = "view-reviews"
resources.router.routes.viewreviews.reqs.course_id = "\d+"
resources.router.routes.viewreviews.reqs.title = "reviews"
Now if I enter the URL http://www.example.com/reviews/19, then the view-reviews action gets called.
Is it possible - to check if title contains the word "reviews" - then this route should be invoked?
Going back to my earlier working route for http://www.example.com/java-training/19:
resources.router.routes.viewbatchcourse.route = "/:title/:course_id/"
resources.router.routes.viewbatchcourse.defaults.controller = course
resources.router.routes.viewbatchcourse.defaults.action = view-batch
resources.router.routes.viewbatchcourse.reqs.course_id = "\d+"
The number 19 is the course id, which I need in the action to pull the details from the database.
But when the page is displayed, I dont want the number 19 visible.
I just want the URL to be http://www.example.com/java-training
Is this possible?
1) You can use Route_Regex to achieve what you want
protected function _initRoutes()
{
$router = Zend_Controller_Front::getInstance()->getRouter();
$route = new Zend_Controller_Router_Route_Regex(
'([a-zA-Z]+)-reviews/(\d+)',
array(
'module' => 'default',
'controller' => 'course',
'action' => 'view-reviews'
),
array(
1 => 'language',
2 => 'course_id',
)
);
$router->addRoute('review', $route);
$route = new Zend_Controller_Router_Route_Regex(
'([a-zA-Z]+)-training/(\d+)',
array(
'module' => 'default',
'controller' => 'course',
'action' => 'view-batch'
),
array(
1 => 'language',
2 => 'course_id',
)
);
$router->addRoute('training', $route);
}
2) For the second point I can't see how it can be possible as is.
One thing you could do though is to use the name of the course, if you have one, to display an url like :
www.xyz.com/java-training/my-awesome-course-19
www.xyz.com/java-training/19/my-awesome-course
It would be pretty easy using the routes i mentionned above.
for question 1. I think you can solve this problem quite simply by altering the route. You don't need to have :title as part of the route, instead it can be hard coded in your case. I would recommend the following configuration.
resources.router.routes.viewbatchcourse.route = "/java-training/:course_id/"
resources.router.routes.viewbatchcourse.defaults.controller = course
resources.router.routes.viewbatchcourse.defaults.action = view-batch
resources.router.routes.viewbatchcourse.defaults.title = java-training
resources.router.routes.viewbatchcourse.reqs.course_id = "\d+"
resources.router.routes.viewreviews.route = "/java-reviews/:course_id/"
resources.router.routes.viewreviews.defaults.controller = course
resources.router.routes.viewreviews.defaults.action = view-reviews
resources.router.routes.viewreviews.defaults.title = java-reviews
resources.router.routes.viewreviews.reqs.course_id = "\d+"
For question 2. As you describe it, simply no.
Re: Q1. I haven’t tested this, but hopefully it is pointing you in the direction you want to go.
resources.router.routes.viewreviews.type = "Zend_Controller_Router_Route_Regex"
resources.router.routes.viewreviews.route = "(.+)-reviews/(\d+)"
resources.router.routes.viewreviews.defaults.controller = "course"
resources.router.routes.viewreviews.defaults.action = "view-reviews"
resources.router.routes.viewreviews.map.1 = "title"
resources.router.routes.viewreviews.map.2 = "course_id"
Re: Q2. I think you'd need to either forward the user to another (parameterless) URL or handle this via javascript. See Modify the URL without reloading the page.

Multilingual site with database and PHP

I am trying to come up with an efficient way to implement language selection in my site.
I have some flags at the top right which when clicked I want all the text to change into the selected language, where the translations are stored in my database.
Should I do this with a parameter in the url like:
www.myside.com?lang=3
The only issue I have with this, is that it might things complicated as far as the way I route urls and it doesn't make the url look clean either.
Would a better way, be to have it stored in a session and the translations are only fetched from the database when the language is changed. The translations would be kept in a session array, so users don't hit the database on every page load if you know what I mean.
I was wondering if something like the following would be a good way of achieving what I want:
Session::set('langarray', array(
'id' => $languageId,
'cake' => $this->model->getLanguagesNavigation('cake', $languageId),
'login' => $this->model->getLanguagesNavigation('login', $languageId),
'register' => $this->model->getLanguagesNavigation('register', $languageId),
'share' => $this->model->getLanguagesNavigation('share', $languageId),
'galleries' => $this->model->getLanguagesNavigation('galleries', $languageId),
'decorator' => $this->model->getLanguagesNavigation('decorator', $languageId),
'find' => $this->model->getLanguagesContent('find', $languageId),
'headertext' => $this->model->getLanguagesContent('headerText', $languageId),
));
header('Location: ' . $_SERVER['HTTP_REFERER']);
and in my view:
...
public function render($viewFile, $data = NULL) {
if(!Session::get('langarray'))
{
$this->Language = new Language;
$this->Language->setLanguage(1);
}
if (is_array($data)) {
extract($data);
}
include Vs . $viewFile . '.php';
}
...
Which is simply set the language to 1 (English) if the session var hasn't been set i.e. a language hasn't been picked.
In my HTML I would just echo the corresponding element in the array to get the word:
...
<p><?PHP echo $_SESSION['langarray']['headertext'];?></p>
...
Is this a good method? Or is there a standard way of implementing languages into a site?
My old site currently uses an url method like the one I mentioned (?lang=3) and the foreign variants do quite well in the SEs. I like the idea of using subdomains, but how would I get it to display the correct content on my pages based on whatever come before the first . in the url? E.g. fr. de. etc
Maybe I'm old fashioned but I've always had a lang folder with files for each languages (lang.en.php, lang.fr.php, lang.es.php, and so on).
In each file I've got an array, like this one:
$langarray = array("login" => "...", "connect" => "...", "logout" => "...");
Eventually with real stuff in them... works better :}
And then, depending on the $_SESSION variable, I include the right file. You can even stock "en" and include lang.'.$_SESSION['lang'].'.php.
It seems slightly better not having to query SQL for that kind of thing but less easy to maintain. I think this is the type of problem where nobody's wrong.
Yes, saving the language code in the session is better than constantly passing around a parameter.
No, storing the translated text in the session doesn't make sense because then you are storing the same text over and over in memory per user. Better to implement database caching or have a PHP file to include for the translation table than to store it in the session.
Instead of making up numeric codes for languages, you really should use the standard letter abbreviations that are part of the HTML spec. Browsers send preferred languages in order of preference as a header called Accept-Language. To avoid making the user click a language choice, you could read that list from the header and iterate through it until you find the first language you support. But always good to give the user some manual way to change it.
Zend framework has some functions for dealing with languages but I've never used it.
As I mentioned in my comment above, I would recommend putting the language in the URL mainly for search engine optimization. Admittedly, it can take a bit more work to set up, but I feel the benefits outweigh the cost.
For example, I have a hotel website with English, Spanish, Chinese and French. The URL structure is like this:
/ <- Main page in English
/es/ <- Main page in Spanish
/zh/ <- Main page in Chinese
/fr/ <- Main page in French
Then for sub-pages I do similarly:
/pagename/
/es/pagename/
/zh/pagename/
/fr/pagename/
Then, this is how I redirect the other languages to the correct scripts:
# Spanish
RewriteRule ^es/(.*/)?$ $1/index.php?lang=es [NC,L]
# French
RewriteRule ^fr/(.*/)?$ $1/index.php?lang=fr [NC,L]
# Chinese
RewriteRule ^zh/(.*/)?$ $1/index.php?lang=zh [NC,L]
This works for rewriting the index.php. For other things, I specify them explicitly, usually using a "friendly" URL. For example the "thank you" page for our Contact Us page:
# Contact Us thank you page
RewriteRule ^([a-z_]+)?/?contact/thankyou$ /contact/thankyou.php?lang=$1 [L]
I also used to do the following to rewrite URLs that contained parameters, but I think doing it like this might be deprecated, not too sure (I have it in the code, but since I don't use parameters, it doesn't get triggered):
RewriteCond %{query_string} ([^=]*)=(.*)
RewriteRule ^es/(.*)$ $1/index.php?lang=es&%1=%2 [NC,L]
However, the hotel offers tours and we have a main /tours/ page and I wanted to have a friendly URL for each of the individual tours, like /tours/56/waterfall-hike (with the tour ID and a slug from the tour name), so this handles the rewriting of the tours:
# Rewrite tours
RewriteRule ^([a-z_]+)?/?tours/([0-9]+)/reserve$ /tours/tour_reserve.php?lang=$1&id=$2 [L]
RewriteRule ^([a-z_]+)?/?tours/([0-9]+)/(.*) /tours/tour_text.php?lang=$1&id=$2&urlstr=$3 [L]
# Tours thank you page
RewriteRule ^([a-z_]+)?/?tours/thankyou$ /tours/thankyou.php?lang=$1 [L]
I just need to verify with PHP that the slug string provided is correct and if not do a 301 redirect to the correct URL based on the ID. I use this to calculate it:
function getTourURL($tour_name) {
// Transliterate non-ascii characters to ascii
$str = trim(strtolower($tour_name));
$str = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
// Do other search and replace
$searches = array(' ', '&', '/');
$replaces = array('-', 'and', '-');
$str = str_replace($searches, $replaces, $str);
// Make sure we don't have more than one dash together
$str = preg_replace("/(-{2,})/", "-", $str );
// Remove all invalid characters
$str = preg_replace("/[^A-Za-z0-9-]/", "", $str );
// Done!
return $str;
}
Then the only other difficult thing is switching languages without just redirecting them back to the home page for that language (yuck!). This is how I did it:
// First define the languages used:
$langs = array(
'en' => array(
'lang_code' => 'en_US',
'locale' => 'en_US.UTF-8',
'base_url' => '/',
'name' => 'English',
),
'es' => array(
'lang_code' => 'es_MX',
'locale' => 'es_MX.UTF-8',
'base_url' => '/es/',
'name' => 'Español',
),
'fr' => array(
'lang_code' => 'fr_FR',
'locale' => 'fr_FR.UTF-8',
'base_url' => '/fr/',
'name' => 'Français',
),
'zh' => array(
'lang_code' => 'zh_CN',
'locale' => 'zh_CN.UTF-8',
'base_url' => '/zh/',
'name' => '中国的',
),
);
define('LOCALE', $_GET['lang']);
// Then get the path to the current script after the language code
$path = (LOCALE == 'en') ? '' : LOCALE.'/';
$parsed_url = parse_url($_SERVER['REQUEST_URI']);
$path = ltrim(str_replace('/'.LOCALE , '', $parsed_url['path']), '/');
define('REDIRECT_SCRIPT', $path);
// Then I put all the links into an array to be displayed in the menu
foreach ($langs as $lang => $arr) {
if ($lang == LOCALE) {
continue;
}
$link = (isset($lang_override[$lang]))
? $lang_override[$lang]
: $arr['base_url'] . REDIRECT_SCRIPT;
$lang_subs[] = array(
'name' => '<div class="'.$lang.'"></div> '.$langs[$lang]['name'],
'link' => $link,
'lang' => $lang,
);
}
This probably won't work for you out of the box, but should at least give you a starting point. Try a print_r($lang_subs); to see what it contains and adapt it to your site's design.

Cannot get rid of default controller in URL with multilingual codeigniter

When I land on my home page www.domain.com (with default controller 'home') the browser redirects to www.domain.com/en/home. What I would like to see is www.domain.com/en (google will see these pages as duplicate content I think?)
Is it possible to leave the default controller out of the URL so that only the language follows the domain i.e. www.domain.com/en?
Here is my code below:
$route['default_controller'] = "Home";
$route['404_override'] = '';
// '/en', '/es' URIs -> use default controller
$route['^(en|es)$'] = 'home'; //$route['default_controller']; //'home'
// route es translation of girls to girls
$route['es/chicas'] = "girls";
$route['es/chicas/chica/(:num)/(:any)'] = "girls/girl/$1/$2";
$route['es/chicas/etiquetas/(:num)/(:any)'] = "girls/tags/$1/$2";
// movies es routes
$route['es/peliculas'] = "movies";
$route['es/peliculas/pelicula/(:num)/(:any)'] = "movies/movie/$1/$2";
$route['es/fotos/galeria/pelicula/(:num)/(:any)'] = 'photos/gallery/movie/$1/$2';
$route['es/peliculas/etiquetas/(:num)/(:any)'] = "movies/tags/$1/$2";
$route['es/unirse'] = "join";
// general catch all for anything that doesn't fit rules above, but doesn't have a
// language prefix e.g. en/girls -> girls controller
$route['^(en|es)/(.+)$'] = "$2";
It's about your config/route.php file. Update your routes as you want exactly.

How to createe a URL string based on a named route and keep parameters

I need to create urls for category switching, switching category should reset page to 1st and change cat name but keep rest of url params.
Example of url:
http://example.com/cat/fruits/page/3/q/testquery/s/date/t/kcal/mine/26/maxe/844/minb/9/mint/4/maxt/93/minw/7/minbl/6/maxbl/96
Urls can contain many different params but category name and page should be always first, category without page should work too and show 1st page.
Currently I have defined two routes and I'm using Zend's url helper with named route but it resets params and as end resuls I have /cat/cat_name/page/1 url.
$category_url = $view->url(array('category'=>$list_item['url'],'page'=>1),'category',FALSE)
resources.router.routes.category_main.route = "/cat/:category/*"
resources.router.routes.category_main.defaults.module = "ilewazy"
resources.router.routes.category_main.defaults.controller = "index"
resources.router.routes.category_main.defaults.action = "results"
resources.router.routes.category_main.defaults.category =
resources.router.routes.category_main.defaults.page = 1
resources.router.routes.category.route = "/cat/:category/page/:page/*"
resources.router.routes.category.defaults.module = "ilewazy"
resources.router.routes.category.defaults.controller = "index"
resources.router.routes.category.defaults.action = "results"
resources.router.routes.category.defaults.category =
resources.router.routes.category.defaults.page = 1
Do I need to create custom method for assembling url in this case?
Things I would try:
Add module, controller and action params in $urlOptions (it's the
first array you pass to the view helper)
instead of 'category' route name try null and see what that does for
you.
Try removing this line
"resources.router.routes.category.defaults.category = "
Please specify what version are of zf are you using.
Solution is very simple, one just have to pass all current request params to url helper
(and optionaly overwrite/add some of them, page and category in my case), last variable is set to FALSE to prevent route resetting.
$view->url(
array_merge(
$params,
array('category' => $list_item['url'],
'page' => 1)
),
'category_main',
FALSE
);

Categories