5
\$\begingroup\$

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
asked Jun 22, 2014 at 15:01
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.