Определение языка браузера в PHP

Я использую следующий PHP-скрипт как индекс для своего сайта.

Этот скрипт должен содержать определенную страницу в зависимости от языка браузера (автоматически определяется).

Этот скрипт не работает со всеми браузерами, поэтому он всегда включает index_en.php для любого обнаруженного языка (причина проблемы, скорее всего, index_en.php с отсутствием рассмотрения заголовка Accept-Language).

Не могли бы вы предложить мне более надежное решение?

 <?php // Open session var session_start(); // views: 1 = first visit; >1 = second visit // Detect language from user agent browser 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() { // Detect 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']); // Try to detect Primary language if several languages are accepted. foreach($GLOBALS['_LANG'] as $K) { if(strpos($_AL, $K)===0) return $K; } // Try to detect any language if not yet detected. foreach($GLOBALS['_LANG'] as $K) { if(strpos($_AL, $K)!==false) return $K; } foreach($GLOBALS['_LANG'] as $K) { //if(preg_match("/[[( ]{$K}[;,_-)]/",$_UA)) // matching other letters (create an error for seo spyder) return $K; } // Return default language if language is not yet detected. return $GLOBALS['_DLANG']; } // Define default language. $GLOBALS['_DLANG']='en'; // Define all available languages. // WARNING: uncomment all available languages $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. ); // Redirect to the correct location. // Example Implementation aff var lang to name file /* echo 'The Language detected is: '.lixlpixel_detect_lang(); // For Demonstration echo "<br />"; */ $lang_var = lixlpixel_detect_lang(); //insert lang var system in a new var for conditional statement /* echo "<br />"; echo $lang_var; // print var for trace echo "<br />"; */ // Insert the right page iacoording with the language in the browser switch ($lang_var){ case "fr": //echo "PAGE DE"; include("index_fr.php");//include check session 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");//include EN in all other cases of different lang detection break; } ?> в <?php // Open session var session_start(); // views: 1 = first visit; >1 = second visit // Detect language from user agent browser 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() { // Detect 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']); // Try to detect Primary language if several languages are accepted. foreach($GLOBALS['_LANG'] as $K) { if(strpos($_AL, $K)===0) return $K; } // Try to detect any language if not yet detected. foreach($GLOBALS['_LANG'] as $K) { if(strpos($_AL, $K)!==false) return $K; } foreach($GLOBALS['_LANG'] as $K) { //if(preg_match("/[[( ]{$K}[;,_-)]/",$_UA)) // matching other letters (create an error for seo spyder) return $K; } // Return default language if language is not yet detected. return $GLOBALS['_DLANG']; } // Define default language. $GLOBALS['_DLANG']='en'; // Define all available languages. // WARNING: uncomment all available languages $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. ); // Redirect to the correct location. // Example Implementation aff var lang to name file /* echo 'The Language detected is: '.lixlpixel_detect_lang(); // For Demonstration echo "<br />"; */ $lang_var = lixlpixel_detect_lang(); //insert lang var system in a new var for conditional statement /* echo "<br />"; echo $lang_var; // print var for trace echo "<br />"; */ // Insert the right page iacoording with the language in the browser switch ($lang_var){ case "fr": //echo "PAGE DE"; include("index_fr.php");//include check session 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");//include EN in all other cases of different lang detection break; } ?> в <?php // Open session var session_start(); // views: 1 = first visit; >1 = second visit // Detect language from user agent browser 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() { // Detect 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']); // Try to detect Primary language if several languages are accepted. foreach($GLOBALS['_LANG'] as $K) { if(strpos($_AL, $K)===0) return $K; } // Try to detect any language if not yet detected. foreach($GLOBALS['_LANG'] as $K) { if(strpos($_AL, $K)!==false) return $K; } foreach($GLOBALS['_LANG'] as $K) { //if(preg_match("/[[( ]{$K}[;,_-)]/",$_UA)) // matching other letters (create an error for seo spyder) return $K; } // Return default language if language is not yet detected. return $GLOBALS['_DLANG']; } // Define default language. $GLOBALS['_DLANG']='en'; // Define all available languages. // WARNING: uncomment all available languages $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. ); // Redirect to the correct location. // Example Implementation aff var lang to name file /* echo 'The Language detected is: '.lixlpixel_detect_lang(); // For Demonstration echo "<br />"; */ $lang_var = lixlpixel_detect_lang(); //insert lang var system in a new var for conditional statement /* echo "<br />"; echo $lang_var; // print var for trace echo "<br />"; */ // Insert the right page iacoording with the language in the browser switch ($lang_var){ case "fr": //echo "PAGE DE"; include("index_fr.php");//include check session 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");//include EN in all other cases of different lang detection break; } ?> 

почему бы вам не сделать это простым и чистым

 <?php $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); switch ($lang){ case "fr": //echo "PAGE FR"; include("index_fr.php");//include check session FR 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");//include EN in all other cases of different lang detection break; } ?> в <?php $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); switch ($lang){ case "fr": //echo "PAGE FR"; include("index_fr.php");//include check session FR 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");//include EN in all other cases of different lang detection break; } ?> в <?php $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); switch ($lang){ case "fr": //echo "PAGE FR"; include("index_fr.php");//include check session FR 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");//include EN in all other cases of different lang detection break; } ?> 

Accept-Language – это список взвешенных значений (см. Параметр q ). Это означает, что просто смотреть на первый язык не означает, что он также является самым предпочтительным; фактически, значение q 0 означает, что оно вообще неприемлемо.

Поэтому вместо того, чтобы просто смотреть на первый язык, проанализируйте список принятых языков и доступных языков и найдите наилучшее соответствие:

 // parse list of comma separated language tags and sort it by the quality value 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; } // compare two parsed arrays of language tags and find the matches 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; } // compare two language tags and distinguish the degree of matching 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 возвращает пустой массив, совпадение не найдено, и вы можете вернуться к языку по умолчанию.

Существующие ответы немного слишком подробные, поэтому я создал эту меньшую, автосогласованную версию.

 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'; // Languages we support $available_languages = array("en", "zh-cn", "es"); $langs = prefered_language($available_languages, $_SERVER["HTTP_ACCEPT_LANGUAGE"]); /* Result Array ( [en] => 0.8 [es] => 0.4 [zh-cn] => 0.3 )*/ 

Полный источник источника

Для тех, кто наткнулся на этот старый вопрос, как я, есть также решение, доступное при использовании расширения php_http . Он позаботится о нескольких языках и значениях q и оставит ваш код намного чище, чем другие решения здесь (на момент написания).

PECL HTTP: http://pecl.php.net/package/pecl_http

Как использовать: http://www.php.net/manual/en/function.http-negotiate-language.php

Проблема с выбранным ответом выше заключается в том, что пользователь может выбрать свой первый выбор в качестве языка, который не относится к структуре случая, но один из их вариантов выбора другого языка. Вы должны зацикливаться до тех пор, пока не найдете совпадение.

Это супер простое решение, которое работает лучше. Браузеры возвращают языки в порядке предпочтения, что упрощает проблему. Хотя обозначение языка может содержать более двух символов (например, «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 "Preferred language is $lang"; break; } } 

Надеюсь, вы найдете это быстрое и простое решение, которое вы можете легко использовать в своем коде. Я использую это в производстве довольно долгое время.

Попробуй это:

 ######################################################### # Copyright © 2008 Darrin Yeager # # https://www.dyeager.org/ # # Licensed under BSD license. # # https://www.dyeager.org/downloads/license-bsd.txt # ######################################################### function getDefaultLanguage() { if (isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) return parseDefaultLanguage($_SERVER["HTTP_ACCEPT_LANGUAGE"]); else return parseDefaultLanguage(NULL); } function parseDefaultLanguage($http_accept, $deflang = "en") { if(isset($http_accept) && strlen($http_accept) > 1) { # Split possible languages into array $x = explode(",",$http_accept); foreach ($x as $val) { #check for q-value and create associative array. No q-value means 1 by rule if(preg_match("/(.*);q=([0-1]{0,1}.\d{0,4})/i",$val,$matches)) $lang[$matches[1]] = (float)$matches[2]; else $lang[$val] = 1.0; } #return default language (highest q-value) $qval = 0.0; foreach ($lang as $key => $value) { if ($value > $qval) { $qval = (float)$value; $deflang = $key; } } } return strtolower($deflang); } 

Я думаю, что это самый чистый путь!

  <?php $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); $supportedLanguages=['en','fr','gr']; if(!in_array($lang,$supportedLanguages)){ $lang='en'; } require("index_".$lang.".php"); 

Следующий скрипт – это модифицированная версия кода Xeoncross (спасибо за этот Xeoncross), который возвращается к языку по умолчанию, если языки не соответствуют поддерживаемым, или если найдено совпадение, он заменяет настройку языка по умолчанию новой в соответствии с приоритетом языка.

В этом случае браузер пользователя устанавливается в порядке приоритета на испанский, голландский, американский английский и английский, и приложение поддерживает английский и голландский только без региональных вариаций, а английский язык по умолчанию. Порядок значений в строке «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" 

все вышеперечисленное с отступлением от «en»:

 $lang = substr(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE'])[0],0,2)?:'en'; 

или с репутацией по умолчанию и известным языковым массивом:

 function lang($l=['en'],$u){return $l[array_keys($l,substr(explode(',',$u?:$_SERVER['HTTP_ACCEPT_LANGUAGE'])[0],0,2))[0]]?:$l[0];} 

Примеры:

 // first known lang is always default $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-us'; lang(['de']); // 'de' lang(['de','en']); // 'en' // manual set accept-language lang(['de'],'en-us'); // 'de' lang(['de'],'de-de, en-us'); // 'de' lang(['en','fr'],'de-de, en-us'); // 'en' lang(['en','fr'],'fr-fr, en-us'); // 'fr' lang(['de','en'],'fr-fr, en-us'); // 'de' 

У меня есть этот, который устанавливает cookie. И, как вы можете видеть, он сначала проверяет, опубликован ли пользователь пользователем. Потому что язык браузера не всегда говорит о пользователе.

 <?php $lang = getenv("HTTP_ACCEPT_LANGUAGE"); $set_lang = explode(',', $lang); if (isset($_POST['lang'])) { $taal = $_POST['lang']; setcookie("lang", $taal); header('Location: /p/'); } else { setcookie("lang", $set_lang[0]); echo $set_lang[0]; echo '<br>'; echo $set_lang[1]; header('Location: /p/'); } ?>