语言重定向适用于桌面但不适用于移动浏览器
Language redirect works on desktop but not mobile browser
我在 PHP 中编写了一个小脚本,用于检查浏览器的语言设置并将它们重定向到站点的语言版本(WP 多站点),
function redirect() {
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
switch( $language ) {
case 'sv':
header( 'Location: http://www.example.com/sv/' );
break;
case 'no':
header( 'Location: http://www.example.com/no/' );
break;
case 'da':
header( 'Location: http://www.example.com/da/' );
break;
default:
header( 'Location: http://www.example.com/' );
break;
}
}
if ( strlen($url) < 4 ) {
session_start();
if ( empty($_SESSION[ 'language' ]) ) {
$_SESSION[ 'language' ] = true;
redirect();
}
}
使用 Mobile Safari 或 Mobile Chrome 进行测试时,重定向似乎不起作用。是否有任何我需要考虑的移动浏览器接受语言的特殊输出?
更新:经过更多调试后我发现了这个:
- Mobile Safari 在回显时显示正确的语言 HTTP_ACCEPT_LANGUAGE 但不重定向。
- 移动设备 Chrome(仅 iOS,适用于 Android)未显示正确的语言(默认为 "en")。
- iOS以不同的顺序解析http头数据,比较iOSChrome(en-US,en;q=0.8,sv;q=0.6)和OSX Chrome (sv,en-US;q=0.8,en;q=0.6).
试试这个,请让我们知道输出结果
function redirect() {
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
switch( $language ) {
case 'sv':
header( 'Location: http://www.example.com/sv/' );
break;
case 'no':
header( 'Location: http://www.example.com/no/' );
break;
case 'da':
header( 'Location: http://www.example.com/da/' );
break;
default:
die('Default location');
/* if you get this message on mobile devices, then this line
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
is faulty. Perhaps as @chris85 mentioned, HTTP_ACCEPT_LANGUAGE is
not populated so mobile behaves as a default by not redirecting to
other languages. If this is the case, fix that line
and remove the die();*/
header( 'Location: http://www.example.com/' );
break;
}
die(); // leave this one in. It forces the server to flush data to the browser
}
这在我的桌面浏览器和移动设备上运行良好。我也只在设备上遇到过会话问题,而且最常见的是,我依靠一个空的会话变量来满足我的条件要求,而实际上该变量仍然存在,或者根本没有 session_id( ) 实例化。
?reset 将清除会话。
如果语言已更改,它也会 运行 重定向。
<?php
session_start();
if (isset($_REQUEST['reset'])) {
unset($_SESSION);
$_SESSION['PREVIOUS_SESSION'] = '&cleared=1';
}
function redirect($loc) {
$_SESSION[ 'language' ] = true;
$_SESSION['last_language'] = $language;
header( 'Location: ?r='.$loc.$_SESSION['PREVIOUS_SESSION']);
}
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
if (( empty($_SESSION[ 'language' ]) ) || ($_SESSION['last_language'] != $language)) {
redirect($language);
}
echo '<pre>';
print_r($_SESSION);
echo '</pre>';
if (!empty($_SESSION['PREVIOUS_SESSION'])) {
unset($_SESSION['PREVIOUS_SESSION']);
}
?>
你真的不应该依赖于获得前两个字符。您确实需要依靠检查整个字符串并了解最佳语言选择应该是什么。这些字符串值具有特定的含义,例如在 "problem" 字符串的一种情况下,您实际上会做最合适的行为来显示 en
而不是 sv
。你显然可以编写逻辑来分解接受语言,调查组成部分,并采取适当的行动,但你也可以考虑使用类似的东西:
为您做这件事。快速 google 搜索中可能有许多其他脚本可以以更合适的方式真正使用此 header,而不仅仅是查看前两个字符。
此外,您可以在这里查看类似的问题:Using the PHP HTTP_ACCEPT_LANGUAGE server variable
你真的应该给我们举例说明 $_SERVER["HTTP_ACCEPT_LANGUAGE"]
在这三种情况下的价值是多少。
无论如何,请注意,根据RFC2616 of HTTP/1.1,选择语言比只取header的前两个字符要复杂得多。
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
would mean: "I prefer Danish, but will accept British English and
other types of English."
没有说那些 header 是排序的,也没有说用户的首选语言是列表中的第一个。而且浏览器也无法配置语言或者OS.
理想情况下,为了 select 最好的语言,你必须这样 header 解析:
- 用逗号分隔字符串
- 拆分在分号字符上找到的每个子字符串
- 不给数值时,使用默认值1.0
- 使用这个数值对结果进行排序
- 将此列表与您网站上可用的语言列表进行比较,找出最佳语言。
更新我之前的回答
HTTP_ACCEPT_LANGUAGE是通过headers设置的,会给每个人不同的值。
就我而言,我在南美洲使用英语设置的计算机,所以我的语言 headers 有英语和西班牙语
偏向英语的设置。
session_start();
function redirectToLang($langCode){
// use if's instead of switch so that you can
// check exact matches and presence of a substring
if ($langCode == 'sv'){
$langPath = 'sv';
}else if (strpos($langCode, 'en') !== false){ // this would match en, en-CA, en-US
$langPath = 'en';
}else if ($langCode == 'no'){
$langPath = 'no';
}else{
$langPath = 'en';
}
// you should have no output from the server before this line!
// that is no echoes, print_r, var_dumps, headers, etc
header( 'Location: http://www.example.com/' . $langPath .'/' );
die();
}
function parseLang(){
// echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; in my case
// Chrome Mac OS: en,es;q=0.8
// Chrome Android 5.1: en-US;en;q=0.8,es;q=0.6
// IE Windows Phone 8.1: en-US,en;q=0.5
// Safari iOS: en-US
// Chrome iOS: en-US,en;q=0.8
// get the lang and set a default
$lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : 'en';
// parse the lang code. This can be as simple or as complex as you want
// Simple
$langCode = substr($lang, 0, 2); // in my case 'en'
// Semi Complex (credits to http://www.thefutureoftheweb.com/blog/use-accept-language-header)
$languages = array();
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $lang, $parsed);
if (count($parsed[1])) {
$languages = array_combine($parsed[1], $parsed[4]);
foreach ($languages as $lang => $val) {
if ($val === '') $languages[$lang] = 1;
}
arsort($languages, SORT_NUMERIC);
}
// var_dump($languages); in my case
// array (size=2)
// 'en' => int 1
// 'es' => string '0.8'
$langCode = key($languages); // in my case 'en'
return $langCode;
}
if (!isset($_SESSION['lang'])){
$langCode = parseLang();
$_SESSION['lang'] = $langCode;
redirectToLang($langCode);
}else{
// we already know the language and it is in $_SESSION
// no need to parseLang nor redirect
}
就我而言,所有设备都正确重定向。我的猜测是调用 redirect()
的逻辑发生了某些事情
// this part
if ( strlen($url) < 4 ) {
session_start();
if ( empty($_SESSION[ 'language' ]) ) {
$_SESSION[ 'language' ] = true;
redirect();
}
}
和 session 变量
正在绕过重定向逻辑。尝试上面的代码并清除所有设备上的所有 cookie 和 sessions,以便您拥有的 $_SESSION['language']
var
在测试期间设置不会弄乱结果。让我们知道你这边发生了什么。
我在引用..
"A more contemporary method would be to use http_negotiate_language():"
你检查过这个吗?
我在 PHP 中编写了一个小脚本,用于检查浏览器的语言设置并将它们重定向到站点的语言版本(WP 多站点),
function redirect() {
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
switch( $language ) {
case 'sv':
header( 'Location: http://www.example.com/sv/' );
break;
case 'no':
header( 'Location: http://www.example.com/no/' );
break;
case 'da':
header( 'Location: http://www.example.com/da/' );
break;
default:
header( 'Location: http://www.example.com/' );
break;
}
}
if ( strlen($url) < 4 ) {
session_start();
if ( empty($_SESSION[ 'language' ]) ) {
$_SESSION[ 'language' ] = true;
redirect();
}
}
使用 Mobile Safari 或 Mobile Chrome 进行测试时,重定向似乎不起作用。是否有任何我需要考虑的移动浏览器接受语言的特殊输出?
更新:经过更多调试后我发现了这个:
- Mobile Safari 在回显时显示正确的语言 HTTP_ACCEPT_LANGUAGE 但不重定向。
- 移动设备 Chrome(仅 iOS,适用于 Android)未显示正确的语言(默认为 "en")。
- iOS以不同的顺序解析http头数据,比较iOSChrome(en-US,en;q=0.8,sv;q=0.6)和OSX Chrome (sv,en-US;q=0.8,en;q=0.6).
试试这个,请让我们知道输出结果
function redirect() {
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
switch( $language ) {
case 'sv':
header( 'Location: http://www.example.com/sv/' );
break;
case 'no':
header( 'Location: http://www.example.com/no/' );
break;
case 'da':
header( 'Location: http://www.example.com/da/' );
break;
default:
die('Default location');
/* if you get this message on mobile devices, then this line
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
is faulty. Perhaps as @chris85 mentioned, HTTP_ACCEPT_LANGUAGE is
not populated so mobile behaves as a default by not redirecting to
other languages. If this is the case, fix that line
and remove the die();*/
header( 'Location: http://www.example.com/' );
break;
}
die(); // leave this one in. It forces the server to flush data to the browser
}
这在我的桌面浏览器和移动设备上运行良好。我也只在设备上遇到过会话问题,而且最常见的是,我依靠一个空的会话变量来满足我的条件要求,而实际上该变量仍然存在,或者根本没有 session_id( ) 实例化。
?reset 将清除会话。
如果语言已更改,它也会 运行 重定向。
<?php
session_start();
if (isset($_REQUEST['reset'])) {
unset($_SESSION);
$_SESSION['PREVIOUS_SESSION'] = '&cleared=1';
}
function redirect($loc) {
$_SESSION[ 'language' ] = true;
$_SESSION['last_language'] = $language;
header( 'Location: ?r='.$loc.$_SESSION['PREVIOUS_SESSION']);
}
$language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
if (( empty($_SESSION[ 'language' ]) ) || ($_SESSION['last_language'] != $language)) {
redirect($language);
}
echo '<pre>';
print_r($_SESSION);
echo '</pre>';
if (!empty($_SESSION['PREVIOUS_SESSION'])) {
unset($_SESSION['PREVIOUS_SESSION']);
}
?>
你真的不应该依赖于获得前两个字符。您确实需要依靠检查整个字符串并了解最佳语言选择应该是什么。这些字符串值具有特定的含义,例如在 "problem" 字符串的一种情况下,您实际上会做最合适的行为来显示 en
而不是 sv
。你显然可以编写逻辑来分解接受语言,调查组成部分,并采取适当的行动,但你也可以考虑使用类似的东西:
为您做这件事。快速 google 搜索中可能有许多其他脚本可以以更合适的方式真正使用此 header,而不仅仅是查看前两个字符。
此外,您可以在这里查看类似的问题:Using the PHP HTTP_ACCEPT_LANGUAGE server variable
你真的应该给我们举例说明 $_SERVER["HTTP_ACCEPT_LANGUAGE"]
在这三种情况下的价值是多少。
无论如何,请注意,根据RFC2616 of HTTP/1.1,选择语言比只取header的前两个字符要复杂得多。
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
would mean: "I prefer Danish, but will accept British English and other types of English."
没有说那些 header 是排序的,也没有说用户的首选语言是列表中的第一个。而且浏览器也无法配置语言或者OS.
理想情况下,为了 select 最好的语言,你必须这样 header 解析:
- 用逗号分隔字符串
- 拆分在分号字符上找到的每个子字符串
- 不给数值时,使用默认值1.0
- 使用这个数值对结果进行排序
- 将此列表与您网站上可用的语言列表进行比较,找出最佳语言。
更新我之前的回答
HTTP_ACCEPT_LANGUAGE是通过headers设置的,会给每个人不同的值。 就我而言,我在南美洲使用英语设置的计算机,所以我的语言 headers 有英语和西班牙语 偏向英语的设置。
session_start();
function redirectToLang($langCode){
// use if's instead of switch so that you can
// check exact matches and presence of a substring
if ($langCode == 'sv'){
$langPath = 'sv';
}else if (strpos($langCode, 'en') !== false){ // this would match en, en-CA, en-US
$langPath = 'en';
}else if ($langCode == 'no'){
$langPath = 'no';
}else{
$langPath = 'en';
}
// you should have no output from the server before this line!
// that is no echoes, print_r, var_dumps, headers, etc
header( 'Location: http://www.example.com/' . $langPath .'/' );
die();
}
function parseLang(){
// echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; in my case
// Chrome Mac OS: en,es;q=0.8
// Chrome Android 5.1: en-US;en;q=0.8,es;q=0.6
// IE Windows Phone 8.1: en-US,en;q=0.5
// Safari iOS: en-US
// Chrome iOS: en-US,en;q=0.8
// get the lang and set a default
$lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : 'en';
// parse the lang code. This can be as simple or as complex as you want
// Simple
$langCode = substr($lang, 0, 2); // in my case 'en'
// Semi Complex (credits to http://www.thefutureoftheweb.com/blog/use-accept-language-header)
$languages = array();
preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $lang, $parsed);
if (count($parsed[1])) {
$languages = array_combine($parsed[1], $parsed[4]);
foreach ($languages as $lang => $val) {
if ($val === '') $languages[$lang] = 1;
}
arsort($languages, SORT_NUMERIC);
}
// var_dump($languages); in my case
// array (size=2)
// 'en' => int 1
// 'es' => string '0.8'
$langCode = key($languages); // in my case 'en'
return $langCode;
}
if (!isset($_SESSION['lang'])){
$langCode = parseLang();
$_SESSION['lang'] = $langCode;
redirectToLang($langCode);
}else{
// we already know the language and it is in $_SESSION
// no need to parseLang nor redirect
}
就我而言,所有设备都正确重定向。我的猜测是调用 redirect()
// this part
if ( strlen($url) < 4 ) {
session_start();
if ( empty($_SESSION[ 'language' ]) ) {
$_SESSION[ 'language' ] = true;
redirect();
}
}
和 session 变量
正在绕过重定向逻辑。尝试上面的代码并清除所有设备上的所有 cookie 和 sessions,以便您拥有的 $_SESSION['language']
var
在测试期间设置不会弄乱结果。让我们知道你这边发生了什么。
我在引用.. "A more contemporary method would be to use http_negotiate_language():"
你检查过这个吗?