Getting Section home, language and locale
Permalink Browser Info Environment
How to get the language for the current section has been discussed in depth already, but mostly you also need to know the home page for the current section and sometimes also the locale (e.g. for strftime). I started adding this code to all of my themes:
Then somewhere in the template you have code like this
and
What do you think about this? Did I overlook any problems?
$lang = LANGUAGE; $locale = ACTIVE_LOCALE; $home = DIR_REL; if( Package::getByHandle('multilingual') ) { $ms = MultilingualSection::getCurrentSection(); if (is_object($ms)) { $home = Loader::helper('navigation')->getLinkToCollection($ms, true); $lang = $ms->getLanguage(); $locale = $lang . "_" . $ms->getIcon(); } }
Then somewhere in the template you have code like this
<html lang="<?=$lang?>">
and
<a href="<?=$home?>/">HOME</a>
What do you think about this? Did I overlook any problems?
Type: | Discussion |
---|---|
Status: | New |
Hi Antti,
I totally agree! This should all be included in the helper class.
Do you have any ideas how to approach the ACTIVE_LOCALE / t() problem? Maybe you can open a pull request at the repository.
Patrick
I totally agree! This should all be included in the helper class.
Do you have any ideas how to approach the ACTIVE_LOCALE / t() problem? Maybe you can open a pull request at the repository.
Patrick
Hi,
This is quite a tricky question for me because I'm not that familiar with the c5 core and also I cannot always know what the core team is thinking without meeting them in person.
However, I can suggest something here but I really have no idea whether this would affect to some other things in the core, so please be sure to check through whether this is a good solution.
Here's what I would do:
1. In dispatcher.php: Move the following
AFTER the package startup events are launched (I edited this, see below). This would allow developers to override the localization definitions, which I think would be a good thing for developers. This would also allow us to set the ACTIVE_LOCALE from the Multilingual package.
EDIT: In fact, it would be enough to move the localization.php require line AFTER these lines:
This would allow us to set those variables from the package before the localization.php is loaded.
2. In the Multilingual package, just grab on to that event, check for the current Multilingual section and set the ACTIVE_LOCALE, etc. accordingly.
I think that there is some reason why the localization configuration is run that early in the dispatcher, and I would think the reason for that is that some of the other configurations / classes require these settings to be already set. So it might be best to load the events class earlier in the dispatcher.php and create a new event that would be run before the localization.
Please consult the core team about this issue, I think they have much better view of what happens in dispatcher and in loading those configurations / classes.
Br,
Antti
EDIT2: Spent some time for checking through the files that are loaded between those require lines and I don't see any reason why the localization.php require could not be moved after the package startup events.
EDIT3: This is still not the most optimal solution because developers cannot change the order of how the package startup events are launched. So, if Multilingual package startup events sets the locale variables, they cannot be set after that from any other package which I still think is not good for developers. In my opinion the optimal solution would be to store the locale in a global variable that could easily be overridden by developers. Once the "define" function is used, that constant is really defined for that request, there's no way to override that in PHP (without PHP extensions).
So, this would require the following changes to
/concrete/config/localization.php
This is quite a tricky question for me because I'm not that familiar with the c5 core and also I cannot always know what the core team is thinking without meeting them in person.
However, I can suggest something here but I really have no idea whether this would affect to some other things in the core, so please be sure to check through whether this is a good solution.
Here's what I would do:
1. In dispatcher.php: Move the following
require(dirname(__FILE__) . '/config/localization.php');
AFTER the package startup events are launched (I edited this, see below). This would allow developers to override the localization definitions, which I think would be a good thing for developers. This would also allow us to set the ACTIVE_LOCALE from the Multilingual package.
EDIT: In fact, it would be enough to move the localization.php require line AFTER these lines:
## Package events require(dirname(__FILE__) . '/startup/packages.php');
This would allow us to set those variables from the package before the localization.php is loaded.
2. In the Multilingual package, just grab on to that event, check for the current Multilingual section and set the ACTIVE_LOCALE, etc. accordingly.
I think that there is some reason why the localization configuration is run that early in the dispatcher, and I would think the reason for that is that some of the other configurations / classes require these settings to be already set. So it might be best to load the events class earlier in the dispatcher.php and create a new event that would be run before the localization.
Please consult the core team about this issue, I think they have much better view of what happens in dispatcher and in loading those configurations / classes.
Br,
Antti
EDIT2: Spent some time for checking through the files that are loaded between those require lines and I don't see any reason why the localization.php require could not be moved after the package startup events.
EDIT3: This is still not the most optimal solution because developers cannot change the order of how the package startup events are launched. So, if Multilingual package startup events sets the locale variables, they cannot be set after that from any other package which I still think is not good for developers. In my opinion the optimal solution would be to store the locale in a global variable that could easily be overridden by developers. Once the "define" function is used, that constant is really defined for that request, there's no way to override that in PHP (without PHP extensions).
So, this would require the following changes to
/concrete/config/localization.php
I'd like to post a workaround for the t() problem. It works if you use the two letter language code in your URL. (likehttp://blabla.com/c5site/index.php/en/about)... If such a code is detected it will automatically set the locale according to that. That way all other functions that rely on LOCALE (including t()) will work properly.
Just put this at the end of your config/site.php:
The list of locales is just an example. You have to add the ones you need to make it work.
Please note that this code works with arbitrary sub directories and with or without pretty urls.
EDIT: Changed the regular expression to always return the first segment of the url no matter how long it is. Also it works now with or without a trailing "/"
Just put this at the end of your config/site.php:
$locales = array( "en" => "en_US", "es" => "es_ES", "fr" => "fr_FR", "it" => "it_IT", "de" => "de_DE", "zh" => "zh_CN", "ar" => "ar_AW"); $regexp = '/^'.preg_quote(DIR_REL,'/').'\/(index.php\/)?([^\/$]+)/'; preg_match($regexp,$_SERVER['REQUEST_URI'],$match); if (isset($locales[$match[2]])) { define('LOCALE', $locales[$match[2]]); } else { define('LOCALE', 'de_DE'); }
Viewing 15 lines of 16 lines. View entire code block.
The list of locales is just an example. You have to add the ones you need to make it work.
Please note that this code works with arbitrary sub directories and with or without pretty urls.
EDIT: Changed the regular expression to always return the first segment of the url no matter how long it is. Also it works now with or without a trailing "/"
This is actually quite good workaround because this cannot be done in packages themselves. However, this does not completely solve the t() function issue e.g. when browsing dashboard pages.
One thing that this does not solve is the tool-urls. For example when browsing the dashboard, there are parts quite often loaded from tool urls. In these urls you don't have the /en/ language defined. This might also happen in some rare cases on pages that have blocks using the tool urls (e.g. for AJAX purposes).
Now coming back to this issue when you posted a message and I got a reminder, I think I now know why the localization.php is loaded BEFORE the package on_start events. It's clearly because there might be packages that use the ACTIVE_LOCALE or LOCALE definitions.
However, it has not been documented anywhere that these definitions should be defined already when the on_start event is launched. There's a lot of other variables also that are not defined at the point when on_start is fired for packages. Therefore, I'd see no reason why it couldn't be done what I suggested in my previous message.
Also, I strongly feel that there should be a way for developers to set the variable. I think a proper way to do this would be to take the language definition completely out of the defined variables. For example this could be done:
This way the Localization class would store the locale in a static variable and it would be overridable by developers in a quite easy way.
Concrete5 uses the Zend_Translate object for doing the actual translations and in that class for example this is possible:
Actually it is also possible to call the addTranslation() function from C5 like this:
This requires you to have de_DE.mo file in /languages/site/ directory. I think this might also be another workaround, just store your translations in the /site/ dir and call that function with the correct locale. I'm not sure if this works (have not tested it) but at least I've used it for custom site-specific translations.
However, it's still a workaround and the core team should really check into this issue...
I also checked the 5.5 core and this issue has still not been resolved there.
Antti
One thing that this does not solve is the tool-urls. For example when browsing the dashboard, there are parts quite often loaded from tool urls. In these urls you don't have the /en/ language defined. This might also happen in some rare cases on pages that have blocks using the tool urls (e.g. for AJAX purposes).
Now coming back to this issue when you posted a message and I got a reminder, I think I now know why the localization.php is loaded BEFORE the package on_start events. It's clearly because there might be packages that use the ACTIVE_LOCALE or LOCALE definitions.
However, it has not been documented anywhere that these definitions should be defined already when the on_start event is launched. There's a lot of other variables also that are not defined at the point when on_start is fired for packages. Therefore, I'd see no reason why it couldn't be done what I suggested in my previous message.
Also, I strongly feel that there should be a way for developers to set the variable. I think a proper way to do this would be to take the language definition completely out of the defined variables. For example this could be done:
Localization::setLocale('en_US'); // At some other place: $locale = Localization::getLocale();
This way the Localization class would store the locale in a static variable and it would be overridable by developers in a quite easy way.
Concrete5 uses the Zend_Translate object for doing the actual translations and in that class for example this is possible:
// For more information:http://framework.zend.com/manual/en/zend.translate.using.html... $translate = new Zend_Translate(array( 'adapter' => 'gettext', 'content' => '...', 'locale' => 'de' )); $translate->addTranslation(array( 'content' => '...', 'locale' => 'fr' )); // This would translate to German echo $translate->_("My German Text"); // This would translate to French $translate->setLocale('fr'); echo $translate->_("My French Text");
Viewing 15 lines of 18 lines. View entire code block.
Actually it is also possible to call the addTranslation() function from C5 like this:
Localization::addSiteInterfaceLanguage('de_DE');
This requires you to have de_DE.mo file in /languages/site/ directory. I think this might also be another workaround, just store your translations in the /site/ dir and call that function with the correct locale. I'm not sure if this works (have not tested it) but at least I've used it for custom site-specific translations.
However, it's still a workaround and the core team should really check into this issue...
I also checked the 5.5 core and this issue has still not been resolved there.
Antti
Another thing what I'd like to point out here is that this could also be done by manually calling the Zend_Translate object's function what we first thought out when making the Language Manager. However, if concrete5 has already set the ACTIVE_LOCALE to en_US, it does not even create that object (check out Localization::__construct() method).
Antti
Antti
And one more thing, checking the /en/ from the address bar does not also work with some add-ons like eCommerce that has e.g. URLs with /checkout/ start.
Also, for example for the /profile/ pages it does not work.
Antti
Also, for example for the /profile/ pages it does not work.
Antti
Hi Antti,
I think you're right - It would be the best to store the locale as static variable instead of a constant. That way it would be a lot more flexible. Also for example the edit bar and the site content could have different languages that way.
Does anyone from the core team have an opinion about this?
However, aren't the problems you mention about dashboard,checkout and profile pages something that has to be adressed in a complete different way? Even if the internationalization addon could set the LOCALE early itself - it would still just trace back to the topmost parent that is defined as a language tree, right? So there is no buildin way yet to deal with one first-level page that contains mixed language children.
Patrick
I think you're right - It would be the best to store the locale as static variable instead of a constant. That way it would be a lot more flexible. Also for example the edit bar and the site content could have different languages that way.
Does anyone from the core team have an opinion about this?
However, aren't the problems you mention about dashboard,checkout and profile pages something that has to be adressed in a complete different way? Even if the internationalization addon could set the LOCALE early itself - it would still just trace back to the topmost parent that is defined as a language tree, right? So there is no buildin way yet to deal with one first-level page that contains mixed language children.
Patrick
>> aren't the problems you mention about dashboard,checkout and profile pages something that has to be adressed in a complete different way
A simple cookie and/or session variable might solve the problem for the system to remember user's preferred language. If that does not find the correct language, then it would fall back to the default one or expect some custom functionality (e.g. browser detection from Language Manager).
In the free internationalization add-on there is already a cookie variable that can be set in user-specific way from:
That code sets the DEFAULT_LANGUAGE cookie for the user depending what the user chose from the switch language block.
Antti
A simple cookie and/or session variable might solve the problem for the system to remember user's preferred language. If that does not find the correct language, then it would fall back to the default one or expect some custom functionality (e.g. browser detection from Language Manager).
In the free internationalization add-on there is already a cookie variable that can be set in user-specific way from:
/packages/multilingual/blocks/switch_language/tools/switch.php
That code sets the DEFAULT_LANGUAGE cookie for the user depending what the user chose from the switch language block.
Antti
And by the way, if you're in contact with the core team about this issue, I've already told them that I'd be more than happy to help out in the internationalization related problems.
One thing I talked about with them is about the language storage (currently the MyGengo is a temporary solution what I got from the conversation) and said to them that I'd be willing to help them out if they are developing some new kind of language storing solution because this is closely related to our Language Manager add-on. Currently we haven't integrated to MyGengo because 1) they don't offer a public API and 2) core team said that it's only a temporary solution.
So, just want to point out that I'm usable when it comes to the internationalization part. I'd really like to get things working properly also there.
Antti
One thing I talked about with them is about the language storage (currently the MyGengo is a temporary solution what I got from the conversation) and said to them that I'd be willing to help them out if they are developing some new kind of language storing solution because this is closely related to our Language Manager add-on. Currently we haven't integrated to MyGengo because 1) they don't offer a public API and 2) core team said that it's only a temporary solution.
So, just want to point out that I'm usable when it comes to the internationalization part. I'd really like to get things working properly also there.
Antti
Hmmm... I didn't know that there already is a session variable in the addon.
Since you have a brilliant insight into the subject, maybe you should just open a pull request with your proposed changes to the core.
Patrick
Since you have a brilliant insight into the subject, maybe you should just open a pull request with your proposed changes to the core.
Patrick
Maybe I'll change few words with Andrew before doing that to see his thoughts. However, I really think few lines should be re-written in the Localization class, it would solve like 95% of these problems.
Antti
Antti
Just to let you know, I sent email to Andrew who passed it to Ryan and he suggested me to make the change. It's now in there as a pull request:
https://github.com/concrete5/concrete5/pull/354...
Ryan promised to check it out in the next few days.
So, after this change it's up to the Internationalization add-on to handle the case correctly. Or any other add-on developers. At least there's now possibility to also handle the t() problem correctly.
I'll see also if I'll make a pull request to the Internationalization add-on as well if they approve my core pull request first (it would require that).
Antti
https://github.com/concrete5/concrete5/pull/354...
Ryan promised to check it out in the next few days.
So, after this change it's up to the Internationalization add-on to handle the case correctly. Or any other add-on developers. At least there's now possibility to also handle the t() problem correctly.
I'll see also if I'll make a pull request to the Internationalization add-on as well if they approve my core pull request first (it would require that).
Antti
Thanks Mainio!
Andrew's pretty busy working on our 5.5 release at the moment but I would imagine he'll be able to take a look at your submission sometime in the next couple of weeks.
Andrew's pretty busy working on our 5.5 release at the moment but I would imagine he'll be able to take a look at your submission sometime in the next couple of weeks.
Hi Patrick
Sounds like a great idea. But it doesn't work for me. Don't know why. Could it be when you send the form, that the URL is changing into a string without any language marks in it?
Thanks
Sounds like a great idea. But it doesn't work for me. Don't know why. Could it be when you send the form, that the URL is changing into a string without any language marks in it?
Thanks
Hi Wasabili,
I don't quite understand what the problem is. Can you explain a little further what exactly happens?
Best
Patrick
I don't quite understand what the problem is. Can you explain a little further what exactly happens?
Best
Patrick
Hi Patrick
Well when I use your script in the site.php it seams that the page only taks the "de_DE" no mater what language the page is on. But I saw that when I send the form, that the URL is changing to index.php?somestrings … and the /en/ language is gone.
You know what I mean?
cya
Well when I use your script in the site.php it seams that the page only taks the "de_DE" no mater what language the page is on. But I saw that when I send the form, that the URL is changing to index.php?somestrings … and the /en/ language is gone.
You know what I mean?
cya
Wasabili,
yes - you're right. It doesn't work if the code is not part of the url. So my suggestion is not really the final solution... merely something you might get along with until a better solution is available.
Best
Patrick
yes - you're right. It doesn't work if the code is not part of the url. So my suggestion is not really the final solution... merely something you might get along with until a better solution is available.
Best
Patrick
Kinda the same what I do with my themes. Would be great if there would be some helper method to automate it, though...
Also, as you already mentioned in the other discussion, with language manager I usually do this with the $GLOBALS['LOCALE'] definition because it already points to the "current" locale that is selected.
I think this is actually a minor issue in the multilingual package/c5 core because I feel that there should be a constant that would define under what language (or locale) the user currently is. I feel that ACTIVE_LOCALE should point to the "selected" locale instead of where it now points.
Other thing is also that there is no way for developers to override the locale settings which also made the t() function issue hard in Language Manager. We needed to write few lines over from the localization class to get the desired functionality.
And the reason why developers cannot override the locale constants is that they are defined before any event is launched that I could grab on in the package.
These are few things I feel could be fixed in the c5 core regarding the multilingual functionality and developers.
Br,
Antti