この間の続きを面倒臭いながら実装中。
Accept-Languageヘッダフィールドの書式はRFC2616のSection14で定義されてるようです。
[RFC 2616] Hypertext Transfer Protocol—HTTP/1.1
Each language-range MAY be given an associated quality value which represents an estimate of the user’s preference for the languages specified by that range. The quality value defaults to ””q=1””. For example,
Accept-Language: da, en-gb;q=0.8, en;q=0.7
なるほど。これにそってgetLocales, getLocaleを実装してみました。
<?php
class RequestUtil {
function getLocale() {
return array_shift(RequestUtil::getLocales());
}
function getLocales() {
foreach (split(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"]) as $value) {
list($name, $pri) = split(";", trim($value));
$num = preg_replace("/^q=/", "", $pri);
$langs[($num ? $num : 1)] = $name;
}
arsort($langs);
foreach ($langs as $value) {
$locales[] = $value;
}
return $locales;
}
}
?>
Firefoxでは仕様通りこんなのが来るのでちゃんと取れます。
ja,en-us;q=0.7,en;q=0.3
IEではこんな感じ。
ja
quality valueを省略した場合は1ということになっているのでこれも問題なさそう。
でもOperaのこれは間違ってないのかな
ja, en
両方1だとどちらを選んでいいのかわからない!
現在の実装だと上記の場合、getLocale()はenが返って来てしまいます。かといって左側優先なんてルールを勝手に実装したくない。
・・・と書いていたらyoshukiさんから情報が。
[RFC 3282] Content Language Headers
The syntax and semantics of language-range is defined in [TAGS]. The Accept-Language header may list several language-ranges in a comma- separated list, and each may include a quality value Q. If no Q values are given, the language-ranges are given in priority order, with the leftmost language-range being the most preferred language; this is an extension to the HTTP/1.1 rules, but matches current practice.
If Q values are given, refer to HTTP/1.1 [RFC 2616] for the details on how to evaluate it.
Accept-LanguageヘッダはRFC3282で再定義されていてquality valueが無い場合は左優先となっているそうです!
さっそくさっきのヤツを左優先に修正。
<?php
class RequestUtil {
function getLocale() {
return array_shift(RequestUtil::getLocales());
}
function getLocales() {
foreach (<strong>array_reverse(</strong>split(",", $_SERVER["HTTP_ACCEPT_LANGUAGE"])<strong>)</strong> as $value) {
list($name, $pri) = split(";", trim($value));
$num = preg_replace("/^q=/", "", $pri);
$langs[($num ? $num : 1)] = $name;
}
arsort($langs);
foreach ($langs as $value) {
$locales[] = $value;
}
return $locales;
}
}
?>
これで安心です。