HiveBrain v1.2.0
Get Started
← Back to all entries
patternphpMinor

Detect locale with PHP

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withphpdetectlocale

Problem

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:

-
We look if user has active language in $_SESSION;

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

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

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

-
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!

Solution

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  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;

Code Snippets

// 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;
    }
}
$lang = xxx;
return $lang;
return xxx;

Context

StackExchange Code Review Q#5918, answer score: 2

Revisions (0)

No revisions yet.