Php как узнать язык браузера
Я использую следующий PHP-скрипт в качестве индекса для моего сайта. Этот скрипт должен включать определенную страницу в зависимости от языка браузера (определяется автоматически). Этот скрипт не работает хорошо со всеми браузерами, поэтому он всегда включает index_en.php для любого обнаруженного языка (причина проблемы, скорее всего, в том, что какой-то заголовок Accept-Language не учитывается). Не могли бы вы предложить мне более надежное решение?
// открыть сессию
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("/[[( ][;,_-)]/",$_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 "
";*/
$lang_var = lixlpixel_detect_lang();//вставьте систему lang var в новую переменную для условного оператора
/*
echo "
";echo $lang_var; // выведите var для отслеживания
echo "
";*/
// Вставьте нужную страницу в соответствии с языком в браузере
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
Например, такой способ:
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
$acceptLang = ['fr', 'it', 'en'];
$lang = in_array($lang, $acceptLang) ? $lang : 'en';
require_once "index_.php";
?>
Ответ 2
Ответ 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"
Мы будем очень благодарны
если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.
I use the following PHP script as index for my website.
This script should include a specific page depending on the browser's language (automatically detected).
This script does not work well with all browsers, so it always includes index_en.php for any detected language (the cause of the problem is most probably an issue with some Accept-Language header not being considered).
Could you please suggest me a more robust solution?
The accepted answer to this should be changed to one of those that take multiple languages into account.
include and require's are happen at the compile time of php so basically you include all the index*.php and show only one - waste of ressources
Besides from the real question and regarding the code above, I'd not recommend using different index pages for every language. An user would be happy to see same page layout and content in each language. You only have to load appropriate texts/pics inside one index.php page. The content can be organized e.g. in one XML file like [item]->[lang] sections -
16 Answers 16
why dont you keep it simple and clean
This code doesn't look at the whole list. What if pl is first priority and fr is second in my language list? I'd get English instead of French.
There are no other lengths than two letters! Go in your favorite browser and change the language priority and you will see it.
Accept-Language is a list of weighted values (see q parameter). That means just looking at the first language does not mean it’s also the most preferred; in fact, a q value of 0 means not acceptable at all.
So instead of just looking at the first language, parse the list of accepted languages and available languages and find the best match:
If findMatches returns an empty array, no match was found and you can fall back on the default language.
Hi, script was working fine and now stop. could be possible that if SESSION on the server are turn off this script wont work?
@Phantom007 Depends of the preference : 0 = I don't want this language, 1 = I always want this language.
The existing answers are a little too verbose so I created this smaller, auto-matching version.
And the sample usage:
Very nice method! Maybe you should check if $langs already contains an entry for the language. happened to me that perferred language was en-US, 2nd de and 3rd en, your method always gave me de, cause the first value of en was overwritten by the 3rd entry
not working as expected, my preferred language in the browser is ("en","ar","en-us") what is happening is that is shows ar is the preferred language :\
All three of these links appear to be dead, and they don't seem to have any easily Googleable install instructions (also this function is deprecated according to their page for it)
The problem with the selected answer above is that the user may have their first choice set as a language that's not in the case structure, but one of their other language choices are set. You should loop until you find a match.
This is a super simple solution that works better. Browsers return the languages in order of preference, so that simplifies the problem. While the language designator can be more than two characters (e.g. - "EN-US"), typically the first two are sufficient. In the following code example I'm looking for a match from a list of known languages my program is aware of.
I hope you find this a quick and simple solution that you can easily use in your code. I've been using this in production for quite a while.
Сейчас работаю над сайтом, который претендует на глобальность, естественно и с мультыязычностью у него должно быть все в порядке.
О том как отображать информацию на разных языках тут речи идти не будет. Разговор пойдет о том как определить язык пользователя, и выбрать из доступных на сайте языковых версий наиболее подходящую.
Кому лень читать — посмотрите скринкаст он правда не очень получился, поэтому тут не выкладываю.
- PHP
- Фреймворк CodeIgniter (класс писался для этого фреймворка, но его можно использовать где угодно, внеся небольшие изменения)
Эта строка содержит языки пользователя, которые он предпочитает, и их приоритеты выражаются через q, ели q для языка не задано, то предполагается, что оно будет равно 1. Если постараться отобразить ее в более менее читаемом виде то она выглядит так:
Отсюда видно что я предпочитаю русский язык, а на втором месте у меня английский.
Языки написаны в двух форматах главный код языка это «ru» и «en» в моем случае, который относится к языкоывм стандартам ISO 639
И главный код языка — расширенный код языка в моем случае это «ru-ru» и «en-us» тут расширенный код языка указывает на регион использования языка у меня это United States.
Временами возникает недопонимание с тем как пометить языки, когда списки кодов ISO содержат как двухбуквенные так и трехбуквенные коды (иногда несколько трехбуквенных кодов). Сейчас все действительные коды перечислены в одном IANA реестре, который для языка принимает только одно значение из списков ISO. Если доступен двухбуквенный код ISO, то он будет один в реестре. Иначе реестр будет содержать один трехбуквенный код. Это упростит вещи.
С теорией разобрались переходим к практике:
Напишем конструктор контроллера класса:
Отсортированный по убыванию приоритета языка(значение q)
Далее создаем метод находящую наиболее подходящий язык.
Первым пареметром в нее передается язык используемый по умолчанию, вторым массив ключами которого будут языки которые есть на сайте, а значениями ссылки на него с других языков выглядит массив примерно так:
В функции урезаются языки формата главный код языка — расширенный код языка до формата главный код языка т.к. необходимость в Английской и Американской версии языка врядли возникнет, а при желании всегда можно дописать.
Результатом ее выполнения будет наиболее подходящий язык пользователя, в формате ISO 639 в качестве дефолтного языка я передал английский, и для всех языков что не находятся в массиве $langs будет возвращен en.
Предистория
Захотелось заказчику, чтобы при заходе на сайт отображался его любимый логотип с пробегающей по нему искоркой света… Уговорить отказаться от этой идеи человека я так и не смог, но в итоге мы решили, что радость эта будет отображаться только раз, и только при заходе на главную страницу. Если человек попал на сайт с поисковика, он сразу переходит на страницу. Если он руками вписывает адрес в браузер, он перенаправляется на страницу с анимацией. После успешного отображения в куки пишется маркер, и видео больше не грузится. Но… Если на сайт зайдет не человек, а поисковик, то писать себе куки он не будет. Поэтому он всегда будет натыкаться на страницу с анимацией, и в выдаче поисковиков мы себя так и не увидим. Да и зачем поисковику логотип компании видеть :)
Как можно узнать что-либо о браузере клиента
Что же делать
if(ini_get('browscap'))
//неленивые админы попались
/* старт шутки */
//вероятность выполнение участка кода стремится к нулю поэтому пишем сюда
echo "Начальство - ты меня задрало!";
/* конец шутки - всем смеяться :)*/
>
else
//используем нашу библиотеку
require_once('browscap.php');
$bc = new Browscap('path/to/the/cache/dir');
$browserInfo=$bc->getBrowser();
в результате чего получим примерно следующее
stdClass Object
(
[browser_name] => Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_2; en-us) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.1 Safari/525.18
[browser_name_regex] => ^mozilla/5\.0 \(macintosh; .; .*mac os x.*\) applewebkit/.* \(.*\) version/3\.1.* safari/.*$
[browser_name_pattern] => Mozilla/5.0 (Macintosh; ?; *Mac OS X*) AppleWebKit/* (*) Version/3.1* Safari/*
[Parent] => Safari 3.1
[Platform] => MacOSX
[Browser] => Safari
[Version] => 3.1
[MajorVer] => 3
[MinorVer] => 1
[Frames] => 1
[IFrames] => 1
[Tables] => 1
[Cookies] => 1
[BackgroundSounds] => 1
[JavaApplets] => 1
[JavaScript] => 1
[CSS] => 2
[CssVersion] => 2
[supportsCSS] => 1
[Alpha] =>
[Beta] =>
[Win16] =>
[Win32] =>
[Win64] =>
[AuthenticodeUpdate] =>
[CDF] =>
[VBScript] =>
[ActiveXControls] =>
[Stripper] =>
[isBanned] =>
[WAP] =>
[isMobileDevice] =>
[isSyndicationReader] =>
[Crawler] =>
[AOL] =>
[aolVersion] => 0
[netCLR] =>
[ClrVersion] => 0
)
UPD. Полученные данные свидетельствуют лишь о поддержке браузером некоторой технологии, а не о ее доступности, так как файл browscap.ini это по сути база данных всех веб-клиентов, в которой по значению User-Agent браузера предоставляется информация о поддерживаемых этим браузером технологиях. Тоесть для современных браузеров при отключенных куках и яве соответствующие параметры все равно будут возвращать еденицу.
Я использую следующий сценарий PHP в качестве индекса для своего веб-сайта.
Этот сценарий должен включать определенную страницу в зависимости от языка браузера (определяется автоматически).
Этот сценарий не работает со всеми браузерами, поэтому он всегда включает index_en.php в себя любой обнаруженный язык (причина проблемы, скорее всего, заключается в том, что какой-то заголовок Accept-Language не рассматривается).
Не могли бы вы предложить мне более надежное решение?
include и require происходят во время компиляции php, поэтому в основном вы включаете весь индекс * .php и показываете только один - трата ресурсов
почему бы тебе не сделать это простым и чистым
Этот код не рассматривает весь список. Что, если pl это первый приоритет и fr второй в моем списке языков? Я бы взял английский вместо французского.
Нет другой длины, кроме двух букв! Зайдите в свой любимый браузер и измените приоритет языка, и вы его увидите.
Accept-Language - это список взвешенных значений (см. Параметр q ). Это означает, что простой взгляд на первый язык не означает, что он также является наиболее предпочтительным; Фактически, значение q, равное 0, означает, что оно вообще неприемлемо.
Поэтому вместо того, чтобы просто смотреть на первый язык, проанализируйте список допустимых языков и доступных языков и найдите наилучшее соответствие:
Если findMatches возвращается пустой массив, совпадение не найдено, и вы можете вернуться к языку по умолчанию.
Привет, скрипт работал нормально, остановитесь. Возможно ли, что если SESSION на сервере выключен, этот скрипт не будет работать?
Существующие ответы слишком подробны, поэтому я создал эту меньшую версию с автоматическим соответствием.
И пример использования:
Очень красивый метод! Возможно, вам стоит проверить, содержит ли уже $ langs запись для языка. случилось со мной, что предпочтительный язык был en-US, 2nd de и 3rd en, ваш метод всегда давал мне de, потому что первое значение en было перезаписано третьей записью
не работает должным образом, мой предпочтительный язык в браузере - это ("en","ar","en-us") то, что происходит, это показывает ar , что предпочтительный язык: \
Все три ссылки кажутся мертвыми, и у них, похоже, нет никаких простых инструкций по установке в Google (также эта функция устарела в соответствии с их страницей для нее)
Проблема с выбранным ответом выше заключается в том, что для пользователя может быть задан первый выбор языка, который не входит в структуру case, но установлен один из других вариантов языка. Вы должны зацикливаться, пока не найдете совпадение.
Это очень простое решение, которое работает лучше. Браузеры возвращают языки в порядке предпочтения, что упрощает задачу. Хотя обозначение языка может состоять более чем из двух символов (например, «EN-US»), обычно достаточно первых двух. В следующем примере кода я ищу совпадение из списка известных языков, о которых знает моя программа.
Я надеюсь, что вы найдете это быстрым и простым решением, которое вы легко сможете использовать в своем коде. Я уже довольно давно использую это в продакшене.
Читайте также: