phphttp-redirecthttp-accept-language

Language redirect works on desktop but not mobile browser


I've put together a small script in PHP that checks for the browser's language settings and redirect them to a language version of the site (WP multisite),

function redirect() {
  $language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
  switch( $language ) {
    case 'sv':
      header( 'Location: http://www.example.com/sv/' );
      break;
    case 'no':
      header( 'Location: http://www.example.com/no/' );
      break;
    case 'da':
      header( 'Location: http://www.example.com/da/' );
      break;
    default:
      header( 'Location: http://www.example.com/' );
      break;
  }
}
if ( strlen($url) < 4 ) {
  session_start();
  if ( empty($_SESSION[ 'language' ]) ) {
    $_SESSION[ 'language' ] = true;
    redirect();
  }
}

When testing with Mobile Safari or Mobile Chrome the redirect doesn't appear to work. Is there any special output for the accept language for mobile browsers that I need to consider?

Update: After some more debugging I found out this:


Solution

  • UPDATE to my previous answer

    The HTTP_ACCEPT_LANGUAGE is set via headers and will give different values for everyone. In my case I am in south america on an computer setup in english so my lang headers have english and spanish settings with a bias towards english.

    session_start();
    
    function redirectToLang($langCode){
        // use if's instead of switch so that you can
        // check exact matches and presence of a substring
        if ($langCode == 'sv'){
            $langPath = 'sv';
        }else if (strpos($langCode, 'en') !== false){ // this would match en, en-CA, en-US
            $langPath = 'en';
        }else if ($langCode == 'no'){
            $langPath = 'no';
        }else{
            $langPath = 'en';
        }
    
        // you should have no output from the server before this line!
        // that is no echoes, print_r, var_dumps, headers, etc
        header( 'Location: http://www.example.com/' . $langPath .'/' );
        die();
    }
    
    function parseLang(){
        // echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; in my case
        // Chrome Mac OS:        en,es;q=0.8
        // Chrome Android 5.1:   en-US;en;q=0.8,es;q=0.6
        // IE Windows Phone 8.1: en-US,en;q=0.5
        // Safari iOS:           en-US
        // Chrome iOS:           en-US,en;q=0.8
    
        // get the lang and set a default
        $lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : 'en';
    
        // parse the lang code. This can be as simple or as complex as you want
    
        // Simple
        $langCode = substr($lang, 0, 2); // in my case 'en'
    
        // Semi Complex (credits to http://www.thefutureoftheweb.com/blog/use-accept-language-header)
        $languages = array();
        preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $lang, $parsed);
    
        if (count($parsed[1])) {
            $languages = array_combine($parsed[1], $parsed[4]);
            foreach ($languages as $lang => $val) {
                if ($val === '') $languages[$lang] = 1;
            }
            arsort($languages, SORT_NUMERIC);
        }
        // var_dump($languages); in my case
        // array (size=2)
        //  'en' => int 1
        //  'es' => string '0.8'
    
    
        $langCode = key($languages); // in my case 'en'
    
        return $langCode;
    }
    
    
    if (!isset($_SESSION['lang'])){
        $langCode = parseLang();
        $_SESSION['lang'] = $langCode;
        redirectToLang($langCode);
    }else{
        // we already know the language and it is in $_SESSION
        // no need to parseLang nor redirect
    }
    

    In my case, all devices redirect correctly. My guess is that there is something happening on the logic that calls redirect()

    // this part
    if ( strlen($url) < 4 ) {
      session_start();
      if ( empty($_SESSION[ 'language' ]) ) {
        $_SESSION[ 'language' ] = true;
        redirect();
      }
    }
    

    and the session var is bypassing the redirect logic. Try the code above and clear all cookies and sessions from all devices so that the $_SESSION['language'] var you have set during testing wont mess up the results. Let us know what happens on your end.