\$\begingroup\$
\$\endgroup\$
I am using this script to detect the most prefered language by the user.
function Get_Client_Prefered_Language ($getSortedList = false, $acceptedLanguages = false)
{
if (empty($acceptedLanguages))
$acceptedLanguages = $_SERVER["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'));
Output:
Array
(
[en-US] => 1
[en] => 1
[en-AU] => 0.8
[fr] => 0.6
[en-GB] => 0.4
)
Is this reliable? How about performance, this script will get called many times per seconds.
200_success
145k22 gold badges190 silver badges478 bronze badges
1 Answer 1
\$\begingroup\$
\$\endgroup\$
The following is imho easier to read and should give you best performance.
<?php
/**
* Get a sorted list of client accepted languages.
*
* @staticvar array $examined
* Used to cache the sorted list for <var>$accept_languages</var> strings.
* @param boolean $list [optional]
* Whether to get a sorted list or the language with the highest preference, defaults to <code>FALSE</code> and
* the language with the highest preference will be returned.
* @param string $accept_languages [optional]
* The client submitted accept languages string in the format defined in RFC 2616.
* @param string $default [optional]
* The default ISO 639-1 alpha-2 language code to use if no other language could be determined, defaults to
* <code>"en"</code>.
* @return array|string
* Associative array where the key is the language code or locale and the value the preference if <var>$list</var>
* is set to <code>TRUE</code>, otherwise the ISO 639-1 alpha-2 code or locale of the language with the highest
* preference.
*/
function get_client_preferred_language($list = false, $accept_languages = null, $default = "en") {
static $examined = array();
// Either use the supplied string or use the string from server input, this construct ensures highest performance
// because a positive check is performed.
$accept_languages || ($accept_languages = filter_input(INPUT_SERVER, "HTTP_ACCEPT_LANGUAGE", FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH));
// Only examine this string if we haven't done so in the past.
if (empty($examined[$accept_languages])) {
// Prepare default fallback in our cache for this string.
$examined[$accept_languages] = array($default => 1.0);
// Only continue if we have a string to examine.
if ($accept_languages) {
// Prepare array for collecting the preferred languages.
$languages = array();
// Extract all languages from the accept languages string, the format is defined in RFC 2616.
preg_match_all("/([a-z]+(?:-[a-z]+)?)\s*(?:;\s*q\s*=\s*(1|0?\.[0-9]+))?/i", $accept_languages, $matches);
// Only go through all extracted languages if we have any.
if (!empty($matches[1])) {
foreach ($matches[1] as $delta => $code) {
// Empty means highest preference.
$languages[$code] = empty($matches[2][$delta]) ? 1.0 : (float) $matches[2][$delta];
}
// Sort the accepted languages by preference, if sorting fails use default.
if (arsort($languages, SORT_NUMERIC) === true) {
$examined[$accept_languages] = $languages;
}
}
}
}
return $list ? $examined[$accept_languages] : array_values($examined[$accept_languages])[0];
}
// ----------------------------------------------------------------------------------------------------------------- Test
function get_client_preferred_language_test() {
assert(array(
"en-US" => 1.0,
"en" => 1.0,
"en-AU" => 0.8,
"fr" => 0.6,
"en-GB" => 0.4,
) === get_client_preferred_language(true, "en,en-US,en-AU;q=0.8,fr;q=0.6,en-GB;q=0.4"));
}
get_client_preferred_language_test();
answered Jul 4, 2014 at 14:49
lang-php