복붙노트

PHP에서 브라우저 언어 감지

PHP

PHP에서 브라우저 언어 감지

내 웹 사이트의 색인으로 다음 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;
}
?>

해결법

  1. ==============================

    1.왜 당신은 그것을 간단하고 깨끗하게 유지하지 않는가?

    왜 당신은 그것을 간단하고 깨끗하게 유지하지 않는가?

    <?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;
    }
    ?>
    
  2. ==============================

    2.수락 - 언어는 가중 값 목록입니다 (q 매개 변수 참조). 즉, 첫 번째 언어를 보는 것만으로도 가장 선호되는 것은 아닙니다. 실제로 q 값 0은 전혀 수용 할 수 없음을 의미합니다.

    수락 - 언어는 가중 값 목록입니다 (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가 빈 배열을 반환하면 일치하는 항목이 없으므로 기본 언어로 되돌릴 수 있습니다.

  3. ==============================

    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';
    
    // 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
    )*/
    

    전체 요점 소스는 여기에

  4. ==============================

    4.이를 처리하는 공식적인 방법은 PECL HTTP 라이브러리를 사용하는 것입니다. 일부 응답과 달리 여기서는 언어 우선 순위 (q 값), 부분 언어 일치를 올바르게 처리하고 가장 가까운 일치를 반환하거나 일치하는 항목이없는 경우 배열의 첫 번째 언어로 되돌아갑니다.

    이를 처리하는 공식적인 방법은 PECL HTTP 라이브러리를 사용하는 것입니다. 일부 응답과 달리 여기서는 언어 우선 순위 (q 값), 부분 언어 일치를 올바르게 처리하고 가장 가까운 일치를 반환하거나 일치하는 항목이없는 경우 배열의 첫 번째 언어로 되돌아갑니다.

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

    사용하는 방법: http://php.net/manual/fa/function.http-negotiate-language.php

    $supportedLanguages = [
        'en-US', // first one is the default/fallback
        'fr',
        'fr-FR',
        'de',
        'de-DE',
        'de-AT',
        'de-CH',
    ];
    
    // Returns the negotiated language 
    // or the default language (i.e. first array entry) if none match.
    $language = http_negotiate_language($supportedLanguages, $result);
    
  5. ==============================

    5.위의 선택된 대답의 문제점은 사용자가 케이스 구조에없는 언어로 설정된 첫 번째 선택을 할 수 있지만 다른 언어 선택 중 하나가 설정된다는 것입니다. 일치 항목을 찾을 때까지 반복해야합니다.

    위의 선택된 대답의 문제점은 사용자가 케이스 구조에없는 언어로 설정된 첫 번째 선택을 할 수 있지만 다른 언어 선택 중 하나가 설정된다는 것입니다. 일치 항목을 찾을 때까지 반복해야합니다.

    이것은 더 잘 작동하는 매우 간단한 솔루션입니다. 브라우저는 우선 순위에 따라 언어를 반환하므로 문제가 간단 해집니다. 언어 지정자는 2 자 이상 (예 : "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;
        }
    }
    

    이 코드를 코드에서 쉽게 사용할 수있는 빠르고 간단한 솔루션을 찾으시기 바랍니다. 나는 이것을 생산에서 꽤 오랫동안 사용 해왔다.

  6. ==============================

    6.이거 한번 해봐:

    이거 한번 해봐:

    #########################################################
    # 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);
    }
    
  7. ==============================

    7.다음 스크립트는 지원되는 언어와 일치하는 언어가없는 경우 Xeoncross의 코드 (Xeoncross에 감사드립니다)가 기본 언어 설정으로 변경되거나 기본 언어 설정이 새로운 언어 설정으로 바뀌는 경우 일치하는 코드가 수정되었습니다 언어 우선 순위에 따라

    다음 스크립트는 지원되는 언어와 일치하는 언어가없는 경우 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" 
    
  8. ==============================

    8.나는 이것이 가장 깨끗한 방법이라고 생각한다!

    나는 이것이 가장 깨끗한 방법이라고 생각한다!

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

    9.위의 모든 내용을 'en'으로 대체합니다.

    위의 모든 내용을 '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];
    }
    

    한 줄:

    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'
    
  10. ==============================

    10.나는 이것을 가지고 쿠키를 설정한다. 보시다시피, 사용자가 언어를 게시했는지 먼저 확인합니다. 왜냐하면 브라우저 언어가 항상 사용자에 대해 알려주지는 않기 때문입니다.

    나는 이것을 가지고 쿠키를 설정한다. 보시다시피, 사용자가 언어를 게시했는지 먼저 확인합니다. 왜냐하면 브라우저 언어가 항상 사용자에 대해 알려주지는 않기 때문입니다.

    <?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/');
            } 
    ?>
    
  11. from https://stackoverflow.com/questions/3770513/detect-browser-language-in-php by cc-by-sa and MIT license