I adjusted app.php as per instruction:
'locale' => 'ru',
'fallback_locale' => 'en',
But on first visiting the site it always shows an english version. Thus russia based user always needs to click "Russian" button to view russian version of the site.(language switching was created with Session::put('lang', $lang) and redirect to /).
I also tried using handling session language in App::before filter but no luck: it shows in russian all the database content but all that in trans('message.<word>') remains in english (the code is now commented in filter.php).
The project is available on github (to look through files where you may suspect a reason).
The site address www.izutov.com (there are "English" and "Russian" buttons in the left top corner)
Thnx in advance!
This is what I have done to set language selection in Laravel 4 :
in app/filters.php
App::before(function($request) {
Route::matched(function($route, $request) {
if($route->getName() != 'admin') { // don't do it for admin area, (for example)
$language = $_ENV['FALLBACK_LOCALE'];
$lgs = explode(',', $_ENV['LANGUAGES']); // your set of languages
// get the default browser language with the $request object
$browserLg = substr($request->server->get('HTTP_ACCEPT_LANGUAGE'), 0, 2);
// language set from route (for example /en/some-url)
$requestLg = $request->segment(1);
# if the language called in url request matches your set of languages
if (null !== $requestLg && in_array($requestLg, $lgs)) {
$language = $requestLg;
# default browser lg
} else {
if(in_array($browserLg, $lgs)) {
$language = $browserLg;
}
}
// set the validated language
$_ENV['LOCALE'] = $language;
Config::set('locale',$language);
App::setLocale($language);
// share it with views if you want
View::share('locale', $language);
});
});
Related
I'm using CodeIgniter to build a multilanguage web application. I have English and other languages under /system/languages/ folder and I've created a model responsible for changing the working language at run-time.
By default CodeIgniter is working in French as defined in /application/config/config.php
$config['language'] = 'french';
Later, according to a URI segment the model changes the language accordingly, simplified example bellow:
class multilang extends CI_Model {
public function __construct() {
parent::__construct();
if ($this->uri->segment(1) == 'en') {
$this->config->set_item('language', 'english');
}
}
}
This model is the first model listed under the auto load settings in /application/config/autoload.php and I can confirm that the language is indeed changed dynamically by calling:
echo $this->config->item('language');
However the built in form validation library does not take into account the changed language, instead only shows error messages from the language hard coded in the settings file /application/config/config.php in this case French.
At first I assumed this was because the form validation was loaded before the multilang model. To make sure the model was loaded first, I modified the form validation constructor to load the model before anything else like this:
public function __construct($rules = array())
{
$this->CI =& get_instance();
$this->CI->load->model('multilang');
// normal code after....
}
This made sure the model loaded before the form validation. Unfortunately this wasn't enough and the form validation still ignores the language when changed during run-time. Anyone knows why this happens?
Thank you.
The problem was that I was doing AJAX requests that didn't took into account the URI segment that contained the language abbreviation, because the URI for AJAX requests didn't needed the language segment in the first place, so I totally forgot about it.
Therefore I used the session cookie to store the language. Changing the multilang constructor to:
class multilang extends CI_Model {
public function __construct() {
parent::__construct();
# store lang between session
$data = $this->session->all_userdata();
if (isset($data['language'])) {
$lang = $data['language'];
# if lang was changed between sessions
if ($this->uri->segment(1) == 'fr'){
$lang = 'french';
} else if ($this->uri->segment(1) == 'en'){
$lang = 'english';
}
# if lang was changed using one of the lang abbreviations
# overule session setting
if ($this->uri->segment(1) == 'en') {
$lang = 'english';
} else if ($this->uri->segment(1) == 'fr') {
$lang = 'french';
}
$this->config->set_item('language', $lang);
$this->session->set_userdata('language', $lang);
} else {
if ($this->uri->segment(1) == 'en') {
$this->config->set_item('language', 'english');
$this->session->set_userdata('language', 'english');
} else if ($this->uri->segment(1) == 'fr') {
$this->config->set_item('language', 'french');
$this->session->set_userdata('language', 'french');
}
}
}
}
Note: The change to the form_validation constructor wasn't required.
Answer provided for future reference, and to remind people of little things we miss. It was so obvious right! Well this might help the next one who forgets.
Closing question.
My code in laravel to handle multiple language is:
$languages = array('it-IT','en-GB','fr-FR');
$lingua = Request::segment(1);
if(in_array($lingua, $languages)){
\App::setLocale($lingua);
}else{
$lingua = 'it-IT';
}
Route::group(array('prefix' => $lingua), function()
{
Route::get('/', array('as' => 'home', 'uses' => 'ItemController#menu'));
Route::get('/{idcampo}','ItemController#show');
});
How can i:
1)Make the page start always with it-IT as default. (i need it because I use $lingua to fetch from a database) so i can't have that null. Should I use a redirect::to / to /it-IT?
2) change url and language(app:locale) on he fly with a link in the upper section of every pages. withouth returning to the home.
3) to link pages I learn to use:
URL::route('home')
but how to do it when the link change with the entry of a database (for example my link is {{ URL::to($lingua. '/'. $campo[1].'/') }}) I need to use
URL::action('ItemController#show', ($lingua. '/'. $campo[1].'/'))
EDIT:
OK at the top of my pages there is a link to change language on the fly.
Italian //
English //
French
I create a controller clled LanguageController
<?php
class LanguageController extends BaseController {
public function select($lingua)
{
// Store the current language in the session
Session::put('lingua', $lingua);
return Redirect::back(); // redirect to the same page, nothing changes, just the language
}
}
I create a route:
Route::get('lingua/{lingua}', 'LanguageController#select');
Route::get('/', array('as' => 'home', 'uses' => 'ItemController#menu'));
Route::get('/mondo/','ItemController#mondo');
Route::get('/{idcampo}','ItemController#show');
I have my ItemController#menu
public function menu()
{ $linguadefault='it-IT';
$lingua = Session::get('lingua',$linguadefault);
$data = DB::table('campo')->lists('id');
return View::make('index')->with('campo',$data)->with('lingua',$lingua);
}
1) I don't understand why i need to route at lingua/{lingua} if i never route there but i use a url:action to a controller directly.
2) now i need to add
$linguadefault='it-IT';
$lingua = Session::get('lingua',$linguadefault);
at the beginning of every function to have a lingua variable in my page right?
3) now my language seems stucked to french and i can't change it anymore.
I would not use the language in the URL all the time, you can just switch languages when you need and persist it:
1) Use Session to persist the language chosen:
// Set the default language to the current user language
// If user is not logged, defaults to Italian
$linguaDefault = Auth::check()
? Auth::user()->lingua
: 'it-IT';
/// If not stored in Session, current language will be the default one
\App::setLocale(Session::get('lingua', $linguaDefault));
To have the language always set in your application, you can put this code in your file
app/start/global.php
And you don't need to add this anywhere else. So it will use it in this order:
a) Language stored in Session (selected online)
b) Language user has in database
c) Italian
2) To change the language you create a route:
Route::get('lingua/{lang}', 'LanguageController#select');
Your links
URL::action('LanguageController#select', 'it-IT')
URL::action('LanguageController#select', 'en-GB')
URL::action('LanguageController#select', 'fr-FR');
And in your controller you just have to do:
public function select($lang)
{
// Store the current language in the session
Session::put('lingua', $lang);
return Redirect::back(); // redirect to the same page, nothing changes, just the language
}
3) This way you don't need your language in all your URLs, you don't have to deal with it in all your routes. If your user changes the language in database, you just:
$user->save();
Session::put('lingua', $user->lingua);
return Redirect::route('home'); // or anything else
I'm trying to translate the prefix like 'mr.' and 'mrs.' those are set in: System >> Configuration >> Customer Configuration >> Prefix Dropdown Options
I need it in English, Dutch and German. Each language is a separate storeview.
I've added the translation to multiple .csv files like the themes translate.csv and the Mage_Core.csv
The default <?php echo $this->__($prefix) ?> works on the frontend like the checkout. But in the backend and emails it isn't translated.
Any way to translate those?
I found two ways to fix this.
remove the build in prefix and add a new one with custom prefixes.
overrule the Mage_Customer_Helper_Data class and it's getNamePrefixOptions method.
I used Nr2
NR 1: is more work, you will need to update tempaltes. But it is easier to manage for a customer if needs to ad a new translation.
NR2: You can add more prefix values in the config. Then in the class make a switch which to use in which store/language. Adding a new language will probably need to add more code the the class.
What I used to overrule the getNamePrefixOptions
public function getNamePrefixOptions($store = null)
{
$pre_val = $this->_prepareNamePrefixSuffixOptions(
Mage::helper('customer/address')->getConfig('prefix_options', $store)
);
// Show all prefixes in the admin
if (Mage::app()->getStore()->isAdmin()) {
return $pre_val;
}
// Transform array keys to integers
$pre_val = array_values( $pre_val );
$lang_code = Mage::app()->getLocale()->getDefaultLocale();
$new_prefixes_values = array();
// Add language codes here, and add their prefix key's, count starts at 0
switch ( $lang_code ) {
case "nl_NL":
// Set key the same as the value, that's how Magetnto gives it at first
$new_prefixes_values = array( $pre_val[0] => $pre_val[0], $pre_val[1] => $pre_val[1]);
break;
case "de_DE":
$new_prefixes_values = array( $pre_val[2] => $pre_val[2], $pre_val[3] => $pre_val[3]);
break;
default: // other languages
$new_prefixes_values = array( $pre_val[0] => $pre_val[0], $pre_val[1] => $pre_val[1]);
break;
}
return $new_prefixes_values;
}
What I filled in the Prefix Dropdown Options setting: Dhr.;Mevr.;Herr;Frau
It is a bit hard coded but works and allows you to change the values
I've configured my magento index.php so it detects the browser language and redirects the user to the corresponding store view. That works fine. But there is a problem with this with url specific for each store view. For example, a have a product with the url:
./product-url-in-english --> English view
./product-url-in-catalan --> Catalan view
If my browser is configured in English and I go to the Catalan url, then I got a 404 error, because that url is only for the Catalan view, but given that I'm detecting the browser language and redirecting to the English view, the Catalan URL won't work.
If I use the paramenters from_store and store, it will work, but I don't know how to reflect that on my index.php file. The code that detects the browser language is the following:
/* Language detection */
function getLanguageCode()
{
$default_language_code = 'es';
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
foreach (explode(",", strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $accept) {
if (preg_match("!([a-z-]+)(;q=([0-9.]+))?!", trim($accept), $found)) {
$langs[] = $found[1];
$quality[] = (isset($found[3]) ? (float) $found[3] : 1.0);
}
}
// Order the codes by quality
array_multisort($quality, SORT_NUMERIC, SORT_DESC, $langs);
// get list of stores and use the store code for the key
$stores = Mage::app()->getStores(false, true);
// iterate through languages found in the accept-language header
foreach ($langs as $lang) {
$lang = substr($lang,0,2);
if (isset($stores[$lang]) && $stores[$lang]->getIsActive())
return $lang;
}
}
return $default_language_code;
}
/* Store or website code */
if(isset($_SERVER['MAGE_RUN_CODE']))
$mageRunCode = $_SERVER['MAGE_RUN_CODE'];
else
$mageRunCode = getLanguageCode();
/* Run store or run website */
$mageRunType = isset($_SERVER['MAGE_RUN_TYPE']) ? $_SERVER['MAGE_RUN_TYPE'] : 'store';
Mage::run($mageRunCode, $mageRunType);
What do I need to change in my index.php file so I can handle url from all the store views and redirect to the specific page without getting a 404 error?
Thanks
I would like to create a custom CMS within Codeigniter, and I need a mechanism to route general pages to a default controller - for instance:
mydomain.com/about
mydomain.com/services/maintenance
These would be routed through my pagehandler controller. The default routing behaviour in Codeigniter is of course to route to a matching controller and method, so with the above examples it would require an About controller and a Services controller. This is obviously not a practical or even sensible approach.
I've seen the following solution to place in routes.php:
$route['^(?!admin|products).*'] = "pagehandler/$0";
But this poses it's own problems I believe. For example, it simply looks for "products" in the request uri and if found routes to the Products controller - but what if we have services/products as a CMS page? Does this not then get routed to the products controller?
Is there a perfect approach to this? I don't wish to have a routing where all CMS content is prefixed with the controller name, but I also need to be able to generically override the routing for other controllers.
If you use CodeIgniter 2.0 (which has been stable enough to use for months) then you can use:
$route['404_override'] = 'pages';
This will send anything that isn't a controller, method or valid route to your pages controller. Then you can use whatever PHP you like to either show the page or show a much nicer 404 page.
Read me guide explaining how you upgrade to CodeIgniter 2.0. Also, you might be interested in using an existing CMS such as PyroCMS which is now nearing the final v1.0 and has a massive following.
You are in luck. I am developing a CMS myself and it took me ages to find a viable solution to this. Let me explain myself to make sure that we are on the same page here, but I am fairly certain that we area.
Your URLS can be formatted the following ways:
http://www.mydomain.com/about - a top level page with no category
http://www.mydomain.com/services/maintenance - a page with a parent category
http://www.mydomain.com/services/maintenace/server-maintenance - a page with a category and sub category.
In my pages controller I am using the _remap function that basically captures all requests to your controllers and lets you do what you want with them.
Here is my code, commented for your convenience:
<?php
class Pages extends Controller {
// Captures all calls to this controller
public function _remap()
{
// Get out URL segments
$segments = $this->uri->uri_string();
$segments = explode("/", $segments);
// Remove blank segments from array
foreach($segments as $key => $value) {
if($value == "" || $value == "NULL") {
unset($segments[$key]);
}
}
// Store our newly filtered array segments
$segments = array_values($segments);
// Works out what segments we have
switch (count($segments))
{
// We have a category/subcategory/page-name
case 3:
list($cat, $subcat, $page_name) = $segments;
break;
// We have a category/page-name
case 2:
list($cat, $page_name) = $segments;
$subcat = NULL;
break;
// We just have a page name, no categories. So /page-name
default:
list($page_name) = $segments;
$cat = $subcat = NULL;
break;
}
if ($cat == '' && $subcat == '') {
$page = $this->mpages->fetch_page('', '', $page_name);
} else if ($cat != '' && $subcat == '') {
$page = $this->mpages->fetch_page($cat, '', $page_name);
} else if ($category != "" && $sub_category != "") {
$page = $this->mpages->fetch_page($cat, $subcat, $page_name);
}
// $page contains your page data, do with it what you wish.
}
?>
You of course would need to modify your page fetching model function accept 3 parameters and then pass in info depending on what page type you are viewing.
In your application/config/routes.php file simply put what specific URL's you would like to route and at the very bottom put this:
/* Admin routes, login routes etc here first */
$route['(:any)'] = "pages"; // Redirect all requests except for ones defined above to the pages controller.
Let me know if you need any more clarification or downloadable example code.