Я использую следующий PHP-скрипт в качестве индекса для моего сайта. Этот скрипт должен включать определенную страницу в зависимости от языка браузера (определяется автоматически). Этот скрипт не работает хорошо со всеми браузерами, поэтому он всегда включает index_en.php для любого обнаруженного языка (причина проблемы, скорее всего, в том, что какой-то заголовок Accept-Language не учитывается). Не могли бы вы предложить мне более надежное решение?
<?php
// открыть сессию
session_start();
// views: 1 = first visit; >1 = second visit
// Определить язык по агенту пользователя браузера
function lixlpixel_get_env_var($Var) {
if(empty($GLOBALS[$Var])) {
$GLOBALS[$Var]=(!empty($GLOBALS['_SERVER'][$Var]))?
$GLOBALS['_SERVER'][$Var] : (!empty($GLOBALS['HTTP_SERVER_VARS'][$Var])) ? $GLOBALS['HTTP_SERVER_VARS'][$Var]:'';
}
}
function lixlpixel_detect_lang() {
// определение HTTP_ACCEPT_LANGUAGE & HTTP_USER_AGENT.
lixlpixel_get_env_var('HTTP_ACCEPT_LANGUAGE');
lixlpixel_get_env_var('HTTP_USER_AGENT');
$_AL=strtolower($GLOBALS['HTTP_ACCEPT_LANGUAGE']);
$_UA=strtolower($GLOBALS['HTTP_USER_AGENT']);
// Попытка определить основной язык, если принято несколько языков.
foreach($GLOBALS['_LANG'] as $K) {
if(strpos($_AL, $K)===0)
return $K;
}
// Попытка обнаружить любой язык, если он еще не обнаружен.
foreach($GLOBALS['_LANG'] as $K) {
if(strpos($_AL, $K)!==false)
return $K;
}
foreach($GLOBALS['_LANG'] as $K) {
//if(preg_match("/[[( ]{$K}[;,_-)]/",$_UA)) // сопоставление различных букв (создать ошибку для seo spyder)
return $K;
}
// Вернуть язык по умолчанию, если язык еще не определен.
return $GLOBALS['_DLANG'];
}
// Определите язык по умолчанию.
$GLOBALS['_DLANG']='en';
// Определите все доступные языки.
// ПРЕДУПРЕЖДЕНИЕ: не комментировать все доступные языки
$GLOBALS['_LANG'] = array(
'af', // afrikaans.
'ar', // arabic.
'bg', // bulgarian.
'ca', // catalan.
'cs', // czech.
'da', // danish.
'de', // german.
'el', // greek.
'en', // english.
'es', // spanish.
'et', // estonian.
'fi', // finnish.
'fr', // french.
'gl', // galician.
'he', // hebrew.
'hi', // hindi.
'hr', // croatian.
'hu', // hungarian.
'id', // indonesian.
'it', // italian.
'ja', // japanese.
'ko', // korean.
'ka', // georgian.
'lt', // lithuanian.
'lv', // latvian.
'ms', // malay.
'nl', // dutch.
'no', // norwegian.
'pl', // polish.
'pt', // portuguese.
'ro', // romanian.
'ru', // russian.
'sk', // slovak.
'sl', // slovenian.
'sq', // albanian.
'sr', // serbian.
'sv', // swedish.
'th', // thai.
'tr', // turkish.
'uk', // ukrainian.
'zh' // chinese.
);
// Перенаправление на нужное место.
// Пример реализации aff var lang для имени файла
/*
echo 'Обнаружен язык: '.lixlpixel_detect_lang(); // Для демонстрации
echo "<br />";
*/
$lang_var = lixlpixel_detect_lang();//вставьте систему lang var в новую переменную для условного оператора
/*
echo "<br />";
echo $lang_var; // выведите var для отслеживания
echo "<br />";
*/
// Вставьте нужную страницу в соответствии с языком в браузере
switch ($lang_var){
case "fr":
//echo "PAGE DE";
include("index_fr.php");//включить проверку сеанса DE
break;
case "it":
//echo "PAGE IT";
include("index_it.php");
break;
case "en":
//echo "PAGE EN";
include("index_en.php");
break;
default:
//echo "PAGE EN - Setting Default";
include("index_en.php");//включите EN во всех остальных случаях обнаружения разных lang
break;
}
?>
Ответ 1
Например, такой способ:
<?php
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
$acceptLang = ['fr', 'it', 'en'];
$lang = in_array($lang, $acceptLang) ? $lang : 'en';
require_once "index_{$lang}.php";
?>
Ответ 2
Accept-Language – это список взвешенных значений (см. параметр q). Это означает, что если посмотреть на первый язык, это не будет значить, что он является наиболее предпочтительным; на самом деле, значение q, равное 0, означает, что он вообще не приемлем. Поэтому вместо того, чтобы просто смотреть на первый язык, разберите список принятых языков и доступных языков и найдите наилучшее соответствие:
// разбирает список языковых тегов, разделенных запятыми, и сортирует его по величине приемлемости
function parseLanguageList($languageList) {
if (is_null($languageList)) {
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return array();
}
$languageList = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
}
$languages = array();
$languageRanges = explode(',', trim($languageList));
foreach ($languageRanges as $languageRange) {
if (preg_match('/(\*|[a-zA-Z0-9]{1,8}(?:-[a-zA-Z0-9]{1,8})*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?/', trim($languageRange), $match)) {
if (!isset($match[2])) {
$match[2] = '1.0';
} else {
$match[2] = (string) floatval($match[2]);
}
if (!isset($languages[$match[2]])) {
$languages[$match[2]] = array();
}
$languages[$match[2]][] = strtolower($match[1]);
}
}
krsort($languages);
return $languages;
}
// сравнить два разобранных массива языковых тегов и найти совпадения
function findMatches($accepted, $available) {
$matches = array();
$any = false;
foreach ($accepted as $acceptedQuality => $acceptedValues) {
$acceptedQuality = floatval($acceptedQuality);
if ($acceptedQuality === 0.0) continue;
foreach ($available as $availableQuality => $availableValues) {
$availableQuality = floatval($availableQuality);
if ($availableQuality === 0.0) continue;
foreach ($acceptedValues as $acceptedValue) {
if ($acceptedValue === '*') {
$any = true;
}
foreach ($availableValues as $availableValue) {
$matchingGrade = matchLanguage($acceptedValue, $availableValue);
if ($matchingGrade > 0) {
$q = (string) ($acceptedQuality * $availableQuality * $matchingGrade);
if (!isset($matches[$q])) {
$matches[$q] = array();
}
if (!in_array($availableValue, $matches[$q])) {
$matches[$q][] = $availableValue;
}
}
}
}
}
}
if (count($matches) === 0 && $any) {
$matches = $available;
}
krsort($matches);
return $matches;
}
// сравнить два языковых тега и различить степень совпадения
function matchLanguage($a, $b) {
$a = explode('-', $a);
$b = explode('-', $b);
for ($i=0, $n=min(count($a), count($b)); $i<$n; $i++) {
if ($a[$i] !== $b[$i]) break;
}
return $i === 0 ? 0 : (float) $i / count($a);
}
$accepted = parseLanguageList($_SERVER['HTTP_ACCEPT_LANGUAGE']);
var_dump($accepted);
$available = parseLanguageList('en, fr, it');
var_dump($available);
$matches = findMatches($accepted, $available);
var_dump($matches);
Если findMatches возвращает пустой массив, то совпадений не найдено, и вы можете использовать язык по умолчанию.
Ответ 3
Существующие ответы слишком многословны, поэтому я создал эту уменьшенную версию с автоматическим подбором.
function prefered_language(array $available_languages, $http_accept_language) {
$available_languages = array_flip($available_languages);
$langs;
preg_match_all('~([\w-]+)(?:[^,\d]+([\d.]+))?~', strtolower($http_accept_language), $matches, PREG_SET_ORDER);
foreach($matches as $match) {
list($a, $b) = explode('-', $match[1]) + array('', '');
$value = isset($match[2]) ? (float) $match[2] : 1.0;
if(isset($available_languages[$match[1]])) {
$langs[$match[1]] = $value;
continue;
}
if(isset($available_languages[$a])) {
$langs[$a] = $value - 0.1;
}
}
arsort($langs);
return $langs;
}
И пример использования:
//$_SERVER["HTTP_ACCEPT_LANGUAGE"] = 'en-us,en;q=0.8,es-cl;q=0.5,zh-cn;q=0.3';
// языки, которые мы поддерживаем
$available_languages = array("en", "zh-cn", "es");
$langs = prefered_language($available_languages, $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
/* результат
Array (
[en] => 0.8
[es] => 0.4
[zh-cn] => 0.3
)*/
Ответ 4
Это очень простое решение, которое работает лучше всего. Браузеры возвращают языки в порядке предпочтения, поэтому это упрощает проблему. Хотя обозначение языка может состоять более чем из двух символов (например, "EN-US"), обычно достаточно первых двух. В следующем примере кода я ищу совпадение из списка известных языков, о которых знает моя программа.
$known_langs = array('en','fr','de','es');
$user_pref_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
foreach($user_pref_langs as $idx => $lang) {
$lang = substr($lang, 0, 2);
if (in_array($lang, $known_langs)) {
echo "Предпочитаемый язык - $lang ";
break;
}
}
Я надеюсь, что вы найдете это быстрое и простое решение, которое вы сможете легко использовать в своем коде. Я использую это решение в производстве уже довольно долгое время.
Ответ 5
Следующий сценарий представляет собой версию кода, который возвращается к языковым настройкам по умолчанию, если ни один язык не соответствует поддерживаемым, или если соответствие найдено, он заменяет языковые настройки по умолчанию на новые в соответствии с приоритетом языка. В данном сценарии браузер пользователя установлен в порядке приоритета на испанский, голландский, и английский языки, а приложение поддерживает только английский и голландский языки без региональных вариаций, и английский является языком по умолчанию. Порядок значений в строке "HTTP_ACCEPT_LANGUAGE" не важен, если по какой-то причине браузер не упорядочивает значения правильно.
$supported_languages = array("en","nl");
$supported_languages = array_flip($supported_languages);
var_dump($supported_languages); // array(2) { ["en"]=> int(0) ["nl"]=> int(1) }
$http_accept_language = $_SERVER["HTTP_ACCEPT_LANGUAGE"]; // es,nl;q=0.8,en-us;q=0.5,en;q=0.3
preg_match_all('~([\w-]+)(?:[^,\d]+([\d.]+))?~', strtolower($http_accept_language), $matches, PREG_SET_ORDER);
$available_languages = array();
foreach ($matches as $match) {
list($language_code,$language_region) = explode('-', $match[1]) + array('', '');
$priority = isset($match[2]) ? (float) $match[2] : 1.0;
$available_languages[][$language_code] = $priority;
}
var_dump($available_languages);
/*
array(4) {
[0]=> array(1) {
["es"]=>
float(1)
}
[1]=> array(1) {
["nl"]=>
float(0.8)
}
[2]=> array(1) {
["en"]=>
float(0.5)
}
[3]=> array(1) {
["en"]=>
float(0.3)
}
}
*/
$default_priority = (float) 0;
$default_language_code = 'en';
foreach ($available_languages as $key => $value) {
$language_code = key($value);
$priority = $value[$language_code];
if ($priority > $default_priority && array_key_exists($language_code,$supported_languages)) {
$default_priority = $priority;
$default_language_code = $language_code;
var_dump($default_priority); // float(0.8)
var_dump($default_language_code); // string(2) "nl"
}
}
var_dump($default_language_code); // string(2) "nl"
Web