Web

Как определить язык браузера в PHP

Я использую следующий 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

Как проверить адрес электронной почты на корректность в PHP

Web

Потеря PHP сеанса после перенаправления

Какой выбрать CDN для сайта. Оптимизируем скорость загрузки
Web

Какой выбрать CDN для сайта. Оптимизируем скорость загрузки

Web

Почему событие Onclick работает, даже если форма пуста? И после нажатия на кнопку submit появляется оповещение, которое показывает, что поле ввода является обязательным

×