2009-12-22 43 views
1

我做了幾個相關的線程,但這是我正在尋求答案的一個直接問題。我的框架將使用Zend_Translate如果PHP版本是5,否則我必須模仿功能爲4.如何在PHP4中解析gettext .mo文件而不依賴setlocale/locales?

似乎幾乎每個gettext的實現都依賴於setlocale或locales,我知道系統之間存在很多不一致這就是爲什麼我不想依賴它。

我試了幾次纔得到textdomainbindtextdomaingettext函數可以正常工作,但我總是需要調用setlocale

順便說一句,所有的.mo文件將是UTF-8。

回答

1

好吧,我基本上最終寫了一個基於Zend的Gettext適配器的mo文件解析器,據我所知gettext幾乎依賴於語言環境,所以手動解析.mo文件可以節省運行奇怪的麻煩地區問題與setlocale的情況。我還計劃解析以xml文件形式提供的Zend Locale數據。

+0

+1,這就是我最後做了。我要在這裏發佈代碼。 – 2012-04-04 08:47:01

2

下面是一些可重用的代碼來解析在PHP MO文件的基礎上,Zend_Translate_Adapter_Gettext

<?php 

class MoParser { 

    private $_bigEndian = false; 
    private $_file  = false; 
    private $_data  = array(); 

    private function _readMOData($bytes) 
    { 
     if ($this->_bigEndian === false) { 
      return unpack('V' . $bytes, fread($this->_file, 4 * $bytes)); 
     } else { 
      return unpack('N' . $bytes, fread($this->_file, 4 * $bytes)); 
     } 
    } 

    public function loadTranslationData($filename, $locale) 
    { 
     $this->_data  = array(); 
     $this->_bigEndian = false; 
     $this->_file  = @fopen($filename, 'rb'); 
     if (!$this->_file) throw new Exception('Error opening translation file \'' . $filename . '\'.'); 
     if (@filesize($filename) < 10) throw new Exception('\'' . $filename . '\' is not a gettext file'); 

     // get Endian 
     $input = $this->_readMOData(1); 
     if (strtolower(substr(dechex($input[1]), -8)) == "950412de") { 
      $this->_bigEndian = false; 
     } else if (strtolower(substr(dechex($input[1]), -8)) == "de120495") { 
      $this->_bigEndian = true; 
     } else { 
      throw new Exception('\'' . $filename . '\' is not a gettext file'); 
     } 
     // read revision - not supported for now 
     $input = $this->_readMOData(1); 

     // number of bytes 
     $input = $this->_readMOData(1); 
     $total = $input[1]; 

     // number of original strings 
     $input = $this->_readMOData(1); 
     $OOffset = $input[1]; 

     // number of translation strings 
     $input = $this->_readMOData(1); 
     $TOffset = $input[1]; 

     // fill the original table 
     fseek($this->_file, $OOffset); 
     $origtemp = $this->_readMOData(2 * $total); 
     fseek($this->_file, $TOffset); 
     $transtemp = $this->_readMOData(2 * $total); 

     for($count = 0; $count < $total; ++$count) { 
      if ($origtemp[$count * 2 + 1] != 0) { 
       fseek($this->_file, $origtemp[$count * 2 + 2]); 
       $original = @fread($this->_file, $origtemp[$count * 2 + 1]); 
       $original = explode("\0", $original); 
      } else { 
       $original[0] = ''; 
      } 

      if ($transtemp[$count * 2 + 1] != 0) { 
       fseek($this->_file, $transtemp[$count * 2 + 2]); 
       $translate = fread($this->_file, $transtemp[$count * 2 + 1]); 
       $translate = explode("\0", $translate); 
       if ((count($original) > 1) && (count($translate) > 1)) { 
        $this->_data[$locale][$original[0]] = $translate; 
        array_shift($original); 
        foreach ($original as $orig) { 
         $this->_data[$locale][$orig] = ''; 
        } 
       } else { 
        $this->_data[$locale][$original[0]] = $translate[0]; 
       } 
      } 
     } 

     $this->_data[$locale][''] = trim($this->_data[$locale]['']); 

     unset($this->_data[$locale]['']); 
     return $this->_data; 
    } 

}