Using the PHP HTTP_ACCEPT_LANGUAGE server variable Using the PHP HTTP_ACCEPT_LANGUAGE server variable php php

Using the PHP HTTP_ACCEPT_LANGUAGE server variable


A more contemporary method would be to use http_negotiate_language():

 $map = array("en" => "english", "es" => "spanish"); $conf_language= $map[ http_negotiate_language(array_keys($map)) ];

If you don't have the http extension installed (and not the intl one as well), there is yet another workaround in the comments (user-note #86787 (Nov 2008; by Anonymous)):

<?php /*   determine which language out of an available set the user prefers most   $available_languages        array with language-tag-strings (must be lowercase) that are available   $http_accept_language    a HTTP_ACCEPT_LANGUAGE string (read from $_SERVER['HTTP_ACCEPT_LANGUAGE'] if left out) */ function prefered_language ($available_languages,$http_accept_language="auto") {     // if $http_accept_language was left out, read it from the HTTP-Header     if ($http_accept_language == "auto") $http_accept_language = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';     // standard  for HTTP_ACCEPT_LANGUAGE is defined under     // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4     // pattern to find is therefore something like this:     //    1#( language-range [ ";" "q" "=" qvalue ] )     // where:     //    language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )     //    qvalue         = ( "0" [ "." 0*3DIGIT ] )     //            | ( "1" [ "." 0*3("0") ] )     preg_match_all("/([[:alpha:]]{1,8})(-([[:alpha:]|-]{1,8}))?" .                    "(\s*;\s*q\s*=\s*(1\.0{0,3}|0\.\d{0,3}))?\s*(,|$)/i",                    $http_accept_language, $hits, PREG_SET_ORDER);     // default language (in case of no hits) is the first in the array     $bestlang = $available_languages[0];     $bestqval = 0;     foreach ($hits as $arr) {         // read data from the array of this hit         $langprefix = strtolower ($arr[1]);         if (!empty($arr[3])) {             $langrange = strtolower ($arr[3]);             $language = $langprefix . "-" . $langrange;         }         else $language = $langprefix;         $qvalue = 1.0;         if (!empty($arr[5])) $qvalue = floatval($arr[5]);         // find q-maximal language          if (in_array($language,$available_languages) && ($qvalue > $bestqval)) {             $bestlang = $language;             $bestqval = $qvalue;         }         // if no direct hit, try the prefix only but decrease q-value by 10% (as http_negotiate_language does)         else if (in_array($langprefix,$available_languages) && (($qvalue*0.9) > $bestqval)) {             $bestlang = $langprefix;             $bestqval = $qvalue*0.9;         }     }     return $bestlang; } ?>


Do you know if this is happening for all visitors to your site from Colombia? Users are usually free to alter the language settings of their browsers — or to have them altered for them by whoever is in charge of the computer. As zerkms recommends, try logging IP addresses and their headers.

If you have the intl extension installed you can use Locale::lookup and Locale::acceptFromHttp to get a best-fit choice of language from the users browser settings and a list of what translations you have available.

Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']); # e.g. "en_US"


I used the regex from @GabrielAnderson and devised this function which behaves according to RFC 2616 (when no quality value is given to a language, it defaults to 1).

When several languages share the same quality value, the most specific are given priority over the less specific ones. (this behaviour is not part of the RFC which provides no recommendation for this specific case)

function Get_Client_Prefered_Language ($getSortedList = false, $acceptedLanguages = false){    if (empty($acceptedLanguages))        $acceptedLanguages = $_SERVER["HTTP_ACCEPT_LANGUAGE"];        // regex inspired from @GabrielAnderson on http://stackoverflow.com/questions/6038236/http-accept-language    preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})*)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $acceptedLanguages, $lang_parse);    $langs = $lang_parse[1];    $ranks = $lang_parse[4];        // (create an associative array 'language' => 'preference')    $lang2pref = array();    for($i=0; $i<count($langs); $i++)        $lang2pref[$langs[$i]] = (float) (!empty($ranks[$i]) ? $ranks[$i] : 1);        // (comparison function for uksort)    $cmpLangs = function ($a, $b) use ($lang2pref) {        if ($lang2pref[$a] > $lang2pref[$b])            return -1;        elseif ($lang2pref[$a] < $lang2pref[$b])            return 1;        elseif (strlen($a) > strlen($b))            return -1;        elseif (strlen($a) < strlen($b))            return 1;        else            return 0;    };        // sort the languages by prefered language and by the most specific region    uksort($lang2pref, $cmpLangs);    if ($getSortedList)        return $lang2pref;        // return the first value's key    reset($lang2pref);    return key($lang2pref);}

Example:

print_r(Get_Client_Prefered_Language(true, 'en,en-US,en-AU;q=0.8,fr;q=0.6,en-GB;q=0.4'));

Outputs:

Array    (        [en-US] => 1        [en] => 1        [en-AU] => 0.8        [fr] => 0.6        [en-GB] => 0.4    )

As you can notice, 'en-US' appears in first position despite the fact that 'en' was first in the given string.

So you could use this function and just replace your first line of code by:

$http_lang = substr(Get_Client_Prefered_Language(),0,2);