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-сайтов и подборка полезных ссылок
Web

Инструменты для разработки Web-сайтов и подборка полезных ссылок

Web

Когда использовать константу PHP «PHP_EOL»

Web

Как настроить права доступа к файлам в Laravel?

Web

Определение размера удаленного файла без загрузки файла