Created
December 26, 2012 07:21
-
-
Save suin/4378670 to your computer and use it in GitHub Desktop.
AcceptLanguage negotiation algorithm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Return accept languages | |
* @return array | |
* | |
* HTTP content negotiation (section 12) uses short "floating point" numbers to indicate the | |
* relative importance ("weight") of various negotiable parameters. A weight is normalized to | |
* a real number in the range 0 through 1, where 0 is the minimum and 1 the maximum value. | |
* If a parameter has a quality value of 0, then content with this parameter is `not acceptable' | |
* for the client. HTTP/1.1 applications MUST NOT generate more than three digits after the | |
* decimal point. User configuration of these values SHOULD also be limited in this fashion. | |
* | |
* qvalue = ( "0" [ "." 0*3DIGIT ] ) | |
* | ( "1" [ "." 0*3("0") ] ) | |
* | |
* "Quality values" is a misnomer, since these values merely represent relative degradation in desired quality. | |
* | |
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9 | |
*/ | |
public function getAcceptLanguages() | |
{ | |
if ( isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) === false ) | |
{ | |
return []; | |
} | |
if ( preg_match_all('/(?P<langcode>[A-Za-z-]+)(?:;q=(?P<quality>[0-9\.]+))?/', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches) == 0 ) | |
{ | |
return []; | |
} | |
$qualities = $matches['quality']; | |
$languages = $matches['langcode']; | |
$languages = array_map('strtolower', $languages); | |
foreach ( $qualities as $k => $quality ) | |
{ | |
if ( $quality === '' or $quality > 1 ) | |
{ | |
$qualities[$k] = 1; | |
} | |
else | |
{ | |
$qualities[$k] = ceil($quality * 1000) / 1000; | |
} | |
} | |
$acceptLanguages = array_combine($languages, $qualities); | |
$acceptLanguages = array_filter($acceptLanguages); // remove quality=0 | |
return $acceptLanguages; | |
} | |
/** | |
* Negotiate language | |
* @param string[] $serverLanguages Language codes must be lower case | |
* @param float[] $clientLanguages A Hush which keys are language codes and values are qualities | |
* @return string | |
*/ | |
public function negotiateLanguage(array $serverLanguages, array $clientLanguages) | |
{ | |
// Set up client language list. | |
$orderPriority = 1; | |
foreach ( $clientLanguages as $language => $clientPriority ) | |
{ | |
$clientLanguages[$language] = ( ( 1 - $clientPriority ) * 10000 ) + $orderPriority; | |
$orderPriority += 1; | |
if ( strpos($language, '-') > 0 ) | |
{ | |
$primaryLanguage = substr($language, 0, strpos($language, '-')); | |
if ( isset($clientLanguages[$primaryLanguage]) === false ) | |
{ | |
// The priority will be increased by 1000 for partial matches. | |
$clientLanguages[$primaryLanguage] = $clientLanguages[$language] + 1000; | |
} | |
} | |
} | |
// Here, the nearer to zero the priority is, the higher the quality is. | |
asort($clientLanguages); | |
// Set up server language list. | |
$serverLanguages = array_combine($serverLanguages, $serverLanguages); | |
foreach ( $serverLanguages as $serverLanguage ) | |
{ | |
if ( strpos($serverLanguage, '-') > 0 ) | |
{ | |
$primaryLanguage = substr($serverLanguage, 0, strpos($serverLanguage, '-')); | |
if ( isset($serverLanguages[$primaryLanguage]) === false ) | |
{ | |
$serverLanguages[$primaryLanguage] = $serverLanguage; | |
} | |
} | |
} | |
// Negotiate. | |
foreach ( $clientLanguages as $language => $priority ) | |
{ | |
if ( isset($serverLanguages[$language]) === true ) | |
{ | |
return $serverLanguages[$language]; | |
} | |
} | |
return reset($serverLanguages); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment