web-dev-qa-db-ja.com

PHP HTTP_ACCEPT_LANGUAGEサーバー変数を使用する

HTTP_ACCEPT_LANGUAGE をチェックし、最初の2文字から適切な言語を使用してWebサイトをロードするPHPスクリプトを作成しました。

          $http_lang = substr($_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2);
      switch ($http_lang) {
        case 'en':
          $SESSION->conf['language'] = 'english';
          break;
        case 'es':
          $SESSION->conf['language'] = 'spanish';
          break;
        default:
          $SESSION->conf['language'] = $PREFS->conf['languages'][$SESSION->conf['language_id']];
      }

Firefoxで言語をスペイン語に変更すると、Webサイトはスペイン語で正常に読み込まれます。しかし、コロンビアの人々は英語でウェブサイトを見ているといういくつかの報告がありました。

詳細:「es-co」LCID = 9226スペイン語(コロンビア)

なぜこれが起こっているのかについてのアイデアはありますか?これがユーザーがサポートしている言語を確認する最良の方法だと思いました。

26
Beanie

より現代的な方法は、 http_negotiate_language() を使用することです。

 $map = array("en" => "english", "es" => "spanish");
 $conf_language= $map[ http_negotiate_language(array_keys($map)) ];

http拡張 がインストールされていない場合( およびintlも )、コメントに別の回避策があります( ser-note #86787(2008年11月、匿名による) ):

<?php 
/* 
  determine which language out of an available set the user prefers most 

  $available_languages        array with language-tag-strings (must be lowercase) that are available 
  $http_accept_language    a HTTP_ACCEPT_LANGUAGE string (read from $_SERVER['HTTP_ACCEPT_LANGUAGE'] if left out) 
*/ 
function prefered_language ($available_languages,$http_accept_language="auto") { 
    // if $http_accept_language was left out, read it from the HTTP-Header 
    if ($http_accept_language == "auto") $http_accept_language = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : ''; 

    // standard  for HTTP_ACCEPT_LANGUAGE is defined under 
    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 
    // pattern to find is therefore something like this: 
    //    1#( language-range [ ";" "q" "=" qvalue ] ) 
    // where: 
    //    language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) 
    //    qvalue         = ( "0" [ "." 0*3DIGIT ] ) 
    //            | ( "1" [ "." 0*3("0") ] ) 
    preg_match_all("/([[:alpha:]]{1,8})(-([[:alpha:]|-]{1,8}))?" . 
                   "(\s*;\s*q\s*=\s*(1\.0{0,3}|0\.\d{0,3}))?\s*(,|$)/i", 
                   $http_accept_language, $hits, PREG_SET_ORDER); 

    // default language (in case of no hits) is the first in the array 
    $bestlang = $available_languages[0]; 
    $bestqval = 0; 

    foreach ($hits as $arr) { 
        // read data from the array of this hit 
        $langprefix = strtolower ($arr[1]); 
        if (!empty($arr[3])) { 
            $langrange = strtolower ($arr[3]); 
            $language = $langprefix . "-" . $langrange; 
        } 
        else $language = $langprefix; 
        $qvalue = 1.0; 
        if (!empty($arr[5])) $qvalue = floatval($arr[5]); 

        // find q-maximal language  
        if (in_array($language,$available_languages) && ($qvalue > $bestqval)) { 
            $bestlang = $language; 
            $bestqval = $qvalue; 
        } 
        // if no direct hit, try the prefix only but decrease q-value by 10% (as http_negotiate_language does) 
        else if (in_array($langprefix,$available_languages) && (($qvalue*0.9) > $bestqval)) { 
            $bestlang = $langprefix; 
            $bestqval = $qvalue*0.9; 
        } 
    } 
    return $bestlang; 
} 
?>
16
mario

@GabrielAndersonの正規表現を使用し、RFC 2616に従って動作するこの関数を考案しました(言語に品質値が指定されていない場合、デフォルトは1です)。

複数の言語が同じ品質値を共有している場合、最も具体的な言語がより具体的な言語よりも優先されます。 (この動作は、この特定のケースに関する推奨事項を提供しないRFCの一部ではありません)

function Get_Client_Prefered_Language ($getSortedList = false, $acceptedLanguages = false)
{

    if (empty($acceptedLanguages))
        $acceptedLanguages = $_SERVER["HTTP_ACCEPT_LANGUAGE"];

        // regex inspired from @GabrielAnderson on http://stackoverflow.com/questions/6038236/http-accept-language
    preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})*)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $acceptedLanguages, $lang_parse);
    $langs = $lang_parse[1];
    $ranks = $lang_parse[4];


        // (create an associative array 'language' => 'preference')
    $lang2pref = array();
    for($i=0; $i<count($langs); $i++)
        $lang2pref[$langs[$i]] = (float) (!empty($ranks[$i]) ? $ranks[$i] : 1);

        // (comparison function for uksort)
    $cmpLangs = function ($a, $b) use ($lang2pref) {
        if ($lang2pref[$a] > $lang2pref[$b])
            return -1;
        elseif ($lang2pref[$a] < $lang2pref[$b])
            return 1;
        elseif (strlen($a) > strlen($b))
            return -1;
        elseif (strlen($a) < strlen($b))
            return 1;
        else
            return 0;
    };

        // sort the languages by prefered language and by the most specific region
    uksort($lang2pref, $cmpLangs);

    if ($getSortedList)
        return $lang2pref;

        // return the first value's key
    reset($lang2pref);
    return key($lang2pref);
}

例:

print_r(Get_Client_Prefered_Language(true, 'en,en-US,en-AU;q=0.8,fr;q=0.6,en-GB;q=0.4'));

出力:

Array
    (
        [en-US] => 1
        [en] => 1
        [en-AU] => 0.8
        [fr] => 0.6
        [en-GB] => 0.4
    )

お気づきのとおり、「en-US」は指定された文字列の先頭に「en」があったにもかかわらず、最初の位置に表示されます。

したがって、この関数を使用して、コードの最初の行を次のように置き換えることができます。

$http_lang = substr(Get_Client_Prefered_Language(),0,2);
7
2072

これがコロンビアからあなたのサイトへの訪問者allに起こっているかどうか知っていますか?ユーザーは通常、ブラウザの言語設定を自由に変更できます。または、コンピューターの管理者が誰でも自由に変更できます。 zerkmsが推奨するように、IPアドレスとそのヘッダーを記録してみてください。

intl extension がインストールされている場合は、 Locale::lookup および Locale::acceptFromHttp ユーザーのブラウザ設定から最適な言語を選択し、使用可能な翻訳のリストを取得します。

Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']); # e.g. "en_US"
6
Nev Stokes

最後に、私はこの解決策に取り組みました:

if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
  preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $lang_parse);
  if (count($lang_parse[1])){
    $langs = array_combine($lang_parse[1], $lang_parse[4]);
    foreach ($langs as $lang => $val){
      if ($val === '') $langs[$lang] = 1;
    }
    arsort($langs, SORT_NUMERIC);
  }
  foreach ($langs as $lang => $val){
    if (strpos($lang,'en')===0){
      $language = 'english';
      break;
    } else if (strpos($lang,'es')===0){
      $language = 'spanish';
    }
  }
}

リンクについてはAJに感謝します。また、すべての回答に感謝します。

3
Beanie

言語の参照には完全なロケールコードを使用します。なぜならzh-TWおよびzh-CNは2つの異なる言語です。

function httpAcceptLanguage($httpAcceptLanguage = null)
{
    if ($httpAcceptLanguage == null) {
        $httpAcceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
    }

    $languages = explode(',', $httpAcceptLanguage);
    $result = array();
    foreach ($languages as $language) {
        $lang = explode(';q=', $language);
        // $lang == [language, weight], default weight = 1
        $result[$lang[0]] = isset($lang[1]) ? floatval($lang[1]) : 1;
    }

    arsort($result);
    return $result;
}

// zh-TW,en-US;q=0.7,en;q=0.3
echo $_SERVER['HTTP_ACCEPT_LANGUAGE'];
/*
    Array
    (
        [zh-TW] => 1
        [en-US] => 0.7
        [en] => 0.3
    )
 */
print_r(httpAcceptLanguage());
2
Steely Wing

言語を配列に保存したい場合、私はこれを行います:

preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',  'pt-br,pt;q=0.8,en-us;q=0.5,en,en-uk;q=0.3', $lang_parse);
$langs = $lang_parse[1];
$rank = $lang_parse[4];
for($i=0; $i<count($langs); $i++){
    if ($rank[$i] == NULL) $rank[$i] = $rank[$i+1];
}

これは、値を持つ他の言語への配列を出力します

preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', 'pt-br,pt;q=0.8,en-us;q=0.5,en,en-uk;q=0.3', $lang_parse);
$langs = $lang_parse[1];
$rank = $lang_parse[4];
$lang = array();
for($i=0; $i<count($langs); $i++){
    $lang[$langs[$i]] = ($rank[$i] == NULL) ? $rank[$i+1] : $rank[$i];
}

これは、次のような配列を出力します。

Array
(
    [pt-br] => 0.8
    [pt] => 0.8
    [en-us] => 0.5
    [en] => 0.3
    [en-uk] => 0.3
)
1

私はPHPで働いており、先を考えている。

function gethttplanguage(){
    $langs = array(     
            'en',// default
            'it',
            'dn',
            'fr',
            'es'         
    );
    $questions = array(
    "en" => "If you wish to see this site in another language click here",
    "it" => "Se vuole vedere questo sito in italiano clicca qui",
    "dn" => "Hvis du ønsker at se denne hjemmeside i danske klik her",
    "fr" => "Si vous voulez visualiser ce site en français, cliquez ici",
    "es" => "Si quieres ver este sitio en español haga clic aquí"
    );
    $result = array();  
    http_negotiate_language($langs, &$result);  
    return $questions[key($result)];
}
0
user462990