php
  • http
  • internationalization
  • 2011-05-17 111 views 23 likes 
    23

    我创建了一个PHP脚本,检查HTTP_ACCEPT_LANGUAGE并加载使用适当的语言从第1两个字符的网站:使用PHP HTTP_ACCEPT_LANGUAGE服务器变量

      $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的网站加载西班牙语罚款。然而,我有几个报道,哥伦比亚人用英文看到这个网站。

    详情: “ES-CO” LCID = 9226西班牙语(哥伦比亚)

    任何人有任何想法,为什么发生这种情况?我认为这是检查用户支持哪些语言的最佳方式。

    +2

    最好的方法是记录IP及其标题。并稍后检查日志 – zerkms 2011-05-17 23:20:22

    +4

    [如何从$ _SERVER \ ['HTTP_ACCEPT_LANGUAGE'\]使用PHP获取语言值?](http://stackoverflow.com/questions/2316476/how-to-get-the -language-value-from-serverhttp-accept-language-using-php) – 2011-05-17 23:23:18

    +0

    这可能是一个案例问题?改变它切换(strtolower($ http_lang))可能会有所帮助。但不知道。 – mjec 2011-05-20 18:28:33

    回答

    14

    一个更现代的方法是使用http_negotiate_language()

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

    如果你没有安装http extensionand not the intl one as well)做的,里面的意见另一解决办法(user-note #86787 (Nov 2008; by Anonymous)):

    <?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; 
    } 
    ?> 
    
    +0

    为了让代码示例正常工作,我必须替换'$ langrange = strtolower($ arr [3]); '用'$ langrange = $ arr [3]; '。请注意,我的lang字符串格式为es-CO,而不是es-co,如同问题中所示。 – 2015-02-12 23:31:15

    +0

    任何人都知道'http_negotiate_language'发生了什么事?在php.net上找不到它... – brasofilo 2017-11-09 16:38:26

    +0

    @brasofilo我认为它已完全停用http v3.xx pecl扩展:https://mdref.m6w6.name/http/Header/negotiate→全新的API,并没有包含在官方的PHP文档中。 – mario 2017-11-09 22:32:59

    5

    你知道吗全部是从访问您的网站的哥伦比亚访客?用户通常可以自由更改浏览器的语言设置 - 或者由负责计算机的人员修改它们。正如zerkms建议的,尝试记录IP地址及其标题。

    如果你有intl extension安装就可以使用Locale::lookupLocale::acceptFromHttp获得来自用户的浏览器设置语言的最合适的选择,你有什么可用翻译列表。

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

    最后,我去与此解决方案:

    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的链接。还要感谢所有回复。

    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]; 
    for($i=0; $i<count($langs); $i++){ 
        if ($rank[$i] == NULL) $rank[$i] = $rank[$i+1]; 
    } 
    

    这个输出数组语言e其他与价值观

    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 
    ) 
    
    6

    我使用了@GabrielAnderson的正则表达式,并设计了这个函数,它根据RFC 261 6(当没有给语言赋予质量值时,默认为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 
        ) 
    

    正如你可以看到,“恩'US'出现在第一个位置,尽管'en'是第一个在给定的字符串中。

    所以,你可以使用此功能,只需更换您的第一行代码:

    $http_lang = substr(Get_Client_Prefered_Language(),0,2); 
    
    +0

    我可能会误解,但是$ getRank函数中的while语句不应该是if语句吗? – 2013-12-03 16:03:55

    +0

    你是对的,我不记得为什么我用'while'而不是'if'。它可能是强调,递归会继续,而'$行列[$ j]'被定义... – 2072 2013-12-14 23:28:37

    +0

    真的很方便的功能。 谢谢彼得。 – Frank 2014-01-09 09:48:55

    0

    我把我的信任,在熟练的程序员谁的PHP工作,超前思考。 这是我为Google翻译器下拉的标签版本。

    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)]; 
    } 
    
    2

    我会用全区域代码是指语言,因为像zh-TWzh-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()); 
    
    相关问题