4
\$\begingroup\$

I am developing a multilingual site, so i needed some sort of a function to detect user locale, as well as not to scare away search engines, so I wrote this kind of a method to detect locale. The priority is as following:

  1. We look if user has active language in $_SESSION;

  2. If not, we look in the database to detect user preference;

  3. If nothing in the database, we look on the domain name and try to detect locale from domain name and superglobal $_SERVER;

  4. If we failed, we look at user's browser locale ($_SERVER again) and try to detect from it.

  5. If we are totally a failure, we fallback to English.

This method is called on every page of a website.

public static function detect_locale() {
    if(isset($_SESSION["lang"])){
        $lang = $_SESSION["lang"];
        return $lang;
    }
    if(isset($_SESSION["id"])){
        $user = new User($_SESSION["id"]);
        $lang = $user->get_locale();
        return $lang;
    }
    if($_SERVER["HTTP_HOST"] == "ru.mysupersite.com" || $_SERVER["HTTP_HOST"] == "www.mysupersite.ru"){
        $lang = "ru";
        return $lang;
    }
    if(isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])){
        $lang = substr($_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2);
        return $lang;
    }
    $lang = "en";
    return $lang;
}

I see it as a pretty straightforward solution, but something in the back of my mind says that there might be some flaws. Are there any or am I just paranoid?

Thank you!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Can you check if the locale is available/valid? If yes then I'd check $lang and only return if it's accepted and otherwise fall through to the subsequent tests. I'd also move the language-from-host detection code to it's own function to allow for easier testing and extension. \$\endgroup\$
    – user786653
    Commented Nov 9, 2011 at 16:53

1 Answer 1

2
\$\begingroup\$

Your basic hierarchy seems fairly solid. There is just one thing - HTTP_ACCEPT_LANGUAGE is not so simple. I wrote an answer on it here. What follows is the relevant code from that:

// Parse the Accept-Language according to:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
preg_match_all(
   '/([a-z]{1,8})' .       // M1 - First part of language e.g en
   '(-[a-z]{1,8})*\s*' .   // M2 -other parts of language e.g -us
   // Optional quality factor M3 ;q=, M4 - Quality Factor
   '(;\s*q\s*=\s*((1(\.0{0,3}))|(0(\.[0-9]{0,3}))))?/i',
   $_SERVER['HTTP_ACCEPT_LANGUAGE'],
   $langParse);

$langs = $langParse[1]; // M1 - First part of language
$quals = $langParse[4]; // M4 - Quality Factor

$numLanguages = count($langs);
$langArr = array();

for ($num = 0; $num < $numLanguages; $num++)
{
   $newLang = strtoupper($langs[$num]);
   $newQual = isset($quals[$num]) ?
      (empty($quals[$num]) ? 1.0 : floatval($quals[$num])) : 0.0;

   // Choose whether to upgrade or set the quality factor for the
   // primary language.
   $langArr[$newLang] = (isset($langArr[$newLang])) ?
      max($langArr[$newLang], $newQual) : $newQual;
}

// sort list based on value
// langArr will now be an array like: array('EN' => 1, 'ES' => 0.5)
arsort($langArr, SORT_NUMERIC);

// The languages the client accepts in order of preference.
$acceptedLanguages = array_keys($langArr);

// Set the most preferred language that we have a translation for.
foreach ($acceptedLanguages as $preferredLanguage)
{
    if (in_array($preferredLanguage, $websiteLanguages))
    {
       $_SESSION['lang'] = $preferredLanguage;
       return $preferredLanguage;
    }
}

You would need to define website languages or just set the most preferred language.

Also as a very minor point I would change:

$lang = xxx;
return $lang;

To:

return xxx;
\$\endgroup\$
2
  • \$\begingroup\$ Thank you! That's a sweet idea about more detailed parsing of ACCEPT_LANGUAGE. With the link you gave, always wondered, is there some sort of sacred knowledge behind using $_COOKIE instead of $_SESSION for language setting? \$\endgroup\$
    – paulus
    Commented Nov 11, 2011 at 0:10
  • \$\begingroup\$ @paulus $_COOKIE is stored by the browser whereas $_SESSION is stored on the server. The different lifetimes might make COOKIE a better choice for language in a lot of situations. This describes it well: buildinternet.com/2010/07/when-to-use-_session-vs-_cookie \$\endgroup\$
    – Paul
    Commented Nov 11, 2011 at 2:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.