我创建了一个PHP脚本,用于检查HTTP_ACCEPT_LANGUAGE
并使用前两个字符中的相应语言加载网站:
$http_lang = substr($_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2);
switch ($http_lang) {
case 'en':
$SESSION->conf['language'] = 'english';
break;
case 'es':
$SESSION->conf['language'] = 'spanish';
break;
default:
$SESSION->conf['language'] = $PREFS->conf['languages'][$SESSION->conf['language_id']];
}
如果我在Firefox中将语言更改为西班牙语,则网站会以西班牙语加载。不过,我有几份报告称哥伦比亚人民用英文看网站。
详细说明: “es-co”LCID = 9226西班牙语(哥伦比亚)
任何人都有任何关于为什么会这样做的想法?我认为这是检查用户支持的语言的最佳方式。
答案 0 :(得分:16)
更现代的方法是使用http_negotiate_language()
:
$map = array("en" => "english", "es" => "spanish");
$conf_language= $map[ http_negotiate_language(array_keys($map)) ];
如果您没有安装http extension(and not the intl one as well),则评论中还有另一种解决方法(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;
}
?>
答案 1 :(得分:7)
我使用了来自@GabrielAnderson的正则表达式并设计了这个根据RFC 2616行为的函数(当没有给出语言的质量值时,它默认为1)。
当多种语言共享相同的质量值时,最具体的语言优先于不太具体的语言。 (此行为不是RFC的一部分,不提供针对此特定情况的建议)
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);
}
示例:
print_r(Get_Client_Prefered_Language(true, 'en,en-US,en-AU;q=0.8,fr;q=0.6,en-GB;q=0.4'));
输出:
Array
(
[en-US] => 1
[en] => 1
[en-AU] => 0.8
[fr] => 0.6
[en-GB] => 0.4
)
正如您所注意到的,尽管“en”在给定字符串中排在第一位,但“en-US”仍处于第一位。
所以你可以使用这个函数,只需用你的第一行代码替换:
$http_lang = substr(Get_Client_Prefered_Language(),0,2);
答案 2 :(得分:6)
您知道吗?所有来自哥伦比亚的网站访客是否会发生这种情况?用户通常可以自由地更改其浏览器的语言设置 - 或者由负责计算机的任何人更改它们。正如zerkms建议的那样,尝试记录IP地址及其标题。
如果您安装了intl extension,则可以使用Locale::lookup
和Locale::acceptFromHttp
从用户浏览器设置中获取最适合的语言选择以及您提供的翻译列表
Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']); # e.g. "en_US"
答案 3 :(得分:3)
最后我选择了这个解决方案:
if (isset($_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', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
if (count($lang_parse[1])){
$langs = array_combine($lang_parse[1], $lang_parse[4]);
foreach ($langs as $lang => $val){
if ($val === '') $langs[$lang] = 1;
}
arsort($langs, SORT_NUMERIC);
}
foreach ($langs as $lang => $val){
if (strpos($lang,'en')===0){
$language = 'english';
break;
} else if (strpos($lang,'es')===0){
$language = 'spanish';
}
}
}
我要感谢AJ的链接。也感谢所有回复。
答案 4 :(得分:2)
我将使用完整的区域设置代码来引用语言,因为zh-TW
和zh-CN
是2种不同的语言。
function httpAcceptLanguage($httpAcceptLanguage = null)
{
if ($httpAcceptLanguage == null) {
$httpAcceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
$languages = explode(',', $httpAcceptLanguage);
$result = array();
foreach ($languages as $language) {
$lang = explode(';q=', $language);
// $lang == [language, weight], default weight = 1
$result[$lang[0]] = isset($lang[1]) ? floatval($lang[1]) : 1;
}
arsort($result);
return $result;
}
// zh-TW,en-US;q=0.7,en;q=0.3
echo $_SERVER['HTTP_ACCEPT_LANGUAGE'];
/*
Array
(
[zh-TW] => 1
[en-US] => 0.7
[en] => 0.3
)
*/
print_r(httpAcceptLanguage());
答案 5 :(得分:1)
如果你想在数组中存储语言,我这样做:
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', 'pt-br,pt;q=0.8,en-us;q=0.5,en,en-uk;q=0.3', $lang_parse);
$langs = $lang_parse[1];
$rank = $lang_parse[4];
for($i=0; $i<count($langs); $i++){
if ($rank[$i] == NULL) $rank[$i] = $rank[$i+1];
}
这会将数组输出到其他值为
的语言preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', 'pt-br,pt;q=0.8,en-us;q=0.5,en,en-uk;q=0.3', $lang_parse);
$langs = $lang_parse[1];
$rank = $lang_parse[4];
$lang = array();
for($i=0; $i<count($langs); $i++){
$lang[$langs[$i]] = ($rank[$i] == NULL) ? $rank[$i+1] : $rank[$i];
}
这个输出像这样的数组:
Array
(
[pt-br] => 0.8
[pt] => 0.8
[en-us] => 0.5
[en] => 0.3
[en-uk] => 0.3
)
答案 6 :(得分:0)
我信赖那些为PHP工作并且提前思考的熟练程序员。 这是我的Google翻译器下拉标签版本。
function gethttplanguage(){
$langs = array(
'en',// default
'it',
'dn',
'fr',
'es'
);
$questions = array(
"en" => "If you wish to see this site in another language click here",
"it" => "Se vuole vedere questo sito in italiano clicca qui",
"dn" => "Hvis du ønsker at se denne hjemmeside i danske klik her",
"fr" => "Si vous voulez visualiser ce site en français, cliquez ici",
"es" => "Si quieres ver este sitio en español haga clic aquí"
);
$result = array();
http_negotiate_language($langs, &$result);
return $questions[key($result)];
}