Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, biapar, Willr, Ingo, swaiba, simon_w

Overload choose_site_locale?


Reply


5 Posts   635 Views

Avatar
Josua

Community Member, 86 Posts

3 March 2012 at 11:50pm

Edited: 03/03/2012 11:52pm

Hi all!

How I can overload the Translatable::choose_site_locale function?
I would like to automatically be selected the language according to the browser and it remember the language selection of the person for the following occasiones using cookies.
It would also be interesting to consider the language selection to the member.

I've seen that this has been tried:
http://www.silverstripe.org/customising-the-cms/show/11218
but I will not touch the SilverStripe sourcecode.

By the way, do you take into account these features in SilverStripe 3.0?

From what I've seen in SilverStripe 3 code (Translatable module) has not change any of this, and it would be very interesting to give options for all this.

For the tests I've done, the language choice should be performed in _config.php, not in the init function of the controller base page, as the documentacion says, because otherwise the $Translations placeholder not working properly.

Thanks,

Regards,
Jose.

Avatar
Chris_Bryer

Community Member, 35 Posts

7 March 2012 at 9:14pm

you can essentially extend / decorate Translatable, then use your implementation in place of the translatable class. then you can overwrite that one function.
take a look at this help page for full instruction: http://doc.silverstripe.org/sapphire/en/reference/dataobjectdecorator.

hope it helps,
-Chris

Avatar
Josua

Community Member, 86 Posts

8 March 2012 at 1:05am

Hello Chris!

Choose_site_locale is used by other SilverStripe methods, so I want to replace for my method.
However, the tutorial that you show me reads:
--------------------
It's worth noting that you can't override existing methods with DataObjectDecorator, you can only add new ones. So in situations where you want to change the behavior of an existing method (other those with hooks mentioned above), this won't quite work.
--------------------

So it seems I can not do what I need.
This is a problem in SilverStripe, because it prevents a good multilanguage management. :(

Is there another way to do what I want?

Thanks Chris,
Regards,

Jose

Avatar
Chris_Bryer

Community Member, 35 Posts

9 March 2012 at 6:46pm

sorry about that..
when i built the translatable-domains module, i ended up decorating sitetree, and you can write a contentcontrollerInit() function to handle page init. i played around with this a little tonight, and have a rough start for you here.

just fyi, i havent added cookies to this, and right now it always forces to the browsers locale so language switchers wont work right now.. could probably override with cookie states or url params. also not sure how crawlers like google will like this (do they have a HTTP_ACCEPT_LANGUAGE header, and what happens if its missing? right now i think it would just return the requested record from the url segment so i think it'll be fine..)

i'd love to see where you go with this. i've seen one or two other posts like this in the past, and thought it was a slick way of handling multilingual sites on one domain, and being courteous to guests. I spoke with one of the core dev's months ago about the translatable domains module and the new translatable module and i think at some point in the future we want to merge them together to offer more comprehensive domain / locale handling options. perhaps we can add this feature in.. mind posting your progress? i'm happy to tinker when i can :)

-Chris

   
   public function contentcontrollerInit(){
   
      if($this->owner->hasExtension('Translatable')){
         $browserloc = str_replace('-','_', self::detectlanguage());
         $curLoc = Translatable::get_current_locale();
         
         $normalizedBrowserLocale = self::non_rfc1766($browserloc);
         
         if(!preg_match('/'.$normalizedBrowserLocale.'/i', $curLoc)){
            
            //check to see if we have the requested translation
            if($this->owner->hasTranslation($curLoc)){
               i18n::set_locale($normalizedBrowserLocale);
               $correctPage = $this->owner->getTranslation($normalizedBrowserLocale);
               Director::redirect($correctPage->Link());
            }else{
               // what to do if the site doesnt have a translation for the selected page??..
            }
            
         }
      }
   }

function detectlanguage() {
// change en-us,en;q=0.5 to en-us

      $langcode = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
      $langcode = explode(",", $langcode['0']);
      return $langcode['0'];
}

   function non_rfc1766($locale_submitted){
      
      // convert en-us to en_US
      // some locales may not be capitalized.. i.e. zh_yue
      // compares against locales in allowed_locales in Translatable class..
      
      $locales = Translatable::get_allowed_locales();
      if(count($locales) == 0) $locales = &i18n::$all_locales;
      
      foreach($locales as $locale){
         if (strtolower($locale_submitted) == strtolower($locale)){
            return $locale;
         }
      }
   }

Avatar
Josua

Community Member, 86 Posts

11 March 2012 at 9:13am

Edited: 11/03/2012 9:14am

Hi Chris!!

For the moment I have created a function that is called from _config.php to select the locale.

static function set_global_locale($locale) {
i18n::set_default_locale($locale);
i18n::set_locale($locale);
Cookie::set('senda_lang', $locale, 365);
}

static function get_choose_locale($langsAvailable = array()) {
$locale = self::default_locale();
if((isset($_GET['locale']) && !$langsAvailable) || (isset($_GET['locale']) && in_array($_GET['locale'], $langsAvailable))) {
// get from GET parameter
$locale = $_GET['locale'];
} else {
// Si es la homepage del locale por defecto o es una página de tipo multilenguaje
if (Director::baseURL() == $_REQUEST["url"] || self::is_page_multilanguage()) {
// if (!(isset($_SERVER["HTTP_REFERER"]) && (Director::is_site_url($_SERVER["HTTP_REFERER"])))) {
$locale = Cookie::get('senda_lang');
if (!isset($locale)) {
$uid = Cookie::get('senda_mem');
if (isset($uid) && ($uid != 0)) {
$member = Member::get_by_id("Member", $uid);
if ($member) {
$locale = $member->locale;
}
}
if (!isset($locale) || !(in_array($locale, $langsAvailable))) {
$locale = self::default_locale();
// First try to detect browser preferred language
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$locales = array();
$list = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
foreach($list as $part) {
$priority = '';
@list($_locale, $priority) = explode(';', $part);
if ($priority) {
$priority = substr($priority, 2);
} else {
$priority = 1.0;
}
if (preg_match('/^([a-zA-Z]+)$/', $_locale, $match)) {
if (isset(i18n::$likely_subtags[$match[1]])) {
$_locale = i18n::$likely_subtags[$match[1]];
} else {
$_locale = self::default_locale();
}
} else if (preg_match('/^([a-zA-Z]+)-([a-zA-Z]+)$/', $_locale, $match)) {
$_locale = $match[1] . '_' . strtoupper($match[2]);
} else {
$_locale = self::default_locale();
}
if (in_array($_locale, $locales) == false) {
$locales[$priority] = $_locale;
}
}
// Sort browser locales by priority
krsort($locales);
// Try to find best matching browser locale
foreach($locales as $_locale) {
if ($langsAvailable) {
if (isset($langsAvailable) && in_array($_locale, $langsAvailable)) {
$locale = $_locale;
break;
}
} else if (self::$allowed_locales) {
if (in_array($_locale, self::$allowed_locales)) {
$locale = $_locale;
break;
}
} else {
if (isset(i18n::$all_locales[$_locale])) {
$locale = $_locale;
break;
}
}
}
}
}
}
// }
}
}
self::set_current_locale($locale);
return self::$current_locale;
}


In _config.php

Translatable::set_allowed_locales(array(
'en_US', // US English
'es_ES' // Español
));

TranslatableExtension::set_pages_multilanguage(array(
'/Security/login',
'/Security/lostpassword',
'/Security/passwordsent'
));

$cu_locale = TranslatableExtension::get_choose_locale(array(
'en_US',
'es_ES'
));

TranslatableExtension::set_global_locale($cu_locale);

I call it from _config.php because I have seen problems if the locale is specified elsewhere.
There are problems with automated forms :
'/Security/login',
'/Security/lostpassword',
'/Security/passwordsent'

It's very interesting your translatable-domains module.

I am going to do tests with your code to see if a better implementation could be done.
If you do other inquiries tell me.

Thanks for everything and good weekend. :)

Regards,
Jose