home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Translation2 / Admin / Container / gettext.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  18.8 KB  |  640 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * Contains the Translation2_Admin_Container_gettext class
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. The name of the author may not be used to endorse or promote products
  17.  *    derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
  20.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
  23.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  26.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  *
  30.  * @category  Internationalization
  31.  * @package   Translation2
  32.  * @author    Lorenzo Alberton <l.alberton@quipo.it>
  33.  * @author    Michael Wallner <mike@php.net>
  34.  * @copyright 2004-2007 Lorenzo Alberton, Michael Wallner
  35.  * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  36.  * @version   CVS: $Id: gettext.php,v 1.30 2007/11/10 00:02:50 quipo Exp $
  37.  * @link      http://pear.php.net/package/Translation2
  38.  */
  39.  
  40. /**
  41.  * require Translation2_Container_gettext class
  42.  */
  43. require_once 'Translation2/Container/gettext.php';
  44.  
  45. /**
  46.  * Storage driver for storing/fetching data to/from a gettext file
  47.  *
  48.  * This storage driver requires the gettext extension
  49.  *
  50.  * @category  Internationalization
  51.  * @package   Translation2
  52.  * @author    Lorenzo Alberton <l.alberton@quipo.it>
  53.  * @author    Michael Wallner <mike@php.net>
  54.  * @copyright 2004-2007 Lorenzo Alberton, Michael Wallner
  55.  * @license   http://www.debian.org/misc/bsd.license  BSD License (3 Clause)
  56.  * @version   CVS: $Id: gettext.php,v 1.30 2007/11/10 00:02:50 quipo Exp $
  57.  * @link      http://pear.php.net/package/Translation2
  58.  */
  59. class Translation2_Admin_Container_gettext extends Translation2_Container_gettext
  60. {
  61.     // {{{ class vars
  62.  
  63.     var $_bulk   = false;
  64.     var $_queue  = array();
  65.     var $_fields = array('name', 'meta', 'error_text', 'encoding');
  66.  
  67.     // }}}
  68.     // {{{ addLang()
  69.  
  70.     /**
  71.      * Creates a new entry in the langs_avail .ini file.
  72.      *
  73.      * @param array  $langData language data
  74.      * @param string $path     path to gettext data dir
  75.      *
  76.      * @return  mixed   Returns true on success or PEAR_Error on failure.
  77.      */
  78.     function addLang($langData, $path = null)
  79.     {
  80.         if (!isset($path) || !is_string($path)) {
  81.             $path = $this->_domains[$this->options['default_domain']];
  82.         }
  83.  
  84.         $path .= '/'. $langData['lang_id'] . '/LC_MESSAGES';
  85.  
  86.         if (!is_dir($path)) {
  87.             include_once 'System.php';
  88.             if (!System::mkdir(array('-p', $path))) {
  89.                 return $this->raiseError(sprintf(
  90.                         'Cannot create new language in path "%s"', $path
  91.                     ),
  92.                     TRANSLATION2_ERROR_CANNOT_CREATE_DIR
  93.                 );
  94.             }
  95.         }
  96.  
  97.         return true;
  98.     }
  99.  
  100.     // }}}
  101.     // {{{ addLangToList()
  102.  
  103.     /**
  104.      * Creates a new entry in the langsAvail .ini file.
  105.      * If the file doesn't exist yet, it is created.
  106.      *
  107.      * @param array $langData array('lang_id'    => 'en',
  108.      *                              'name'       => 'english',
  109.      *                              'meta'       => 'some meta info',
  110.      *                              'error_text' => 'not available'
  111.      *                              'encoding'   => 'iso-8859-1',
  112.      * );
  113.      *
  114.      * @return true|PEAR_Error on failure
  115.      */
  116.     function addLangToList($langData)
  117.     {
  118.         if (PEAR::isError($changed = $this->_updateLangData($langData))) {
  119.             return $changed;
  120.         }
  121.         return $changed ? $this->_writeLangsAvailFile() : true;
  122.     }
  123.  
  124.     // }}}
  125.     // {{{ add()
  126.  
  127.     /**
  128.      * Add a new entry in the strings domain.
  129.      *
  130.      * @param string $stringID string ID
  131.      * @param string $pageID   page/group ID
  132.      * @param array  $strings  Associative array with string translations.
  133.      *               Sample format:  array('en' => 'sample', 'it' => 'esempio')
  134.      *
  135.      * @return true|PEAR_Error on failure
  136.      */
  137.     function add($stringID, $pageID, $strings)
  138.     {
  139.         if (!isset($pageID)) {
  140.             $pageID = $this->options['default_domain'];
  141.         }
  142.  
  143.         $langs = array_intersect(array_keys($strings), $this->getLangs('ids'));
  144.  
  145.         if (!count($langs)) {
  146.             return true; // really?
  147.         }
  148.  
  149.         if ($this->_bulk) {
  150.             foreach ($strings as $lang => $string) {
  151.                 if (in_array($lang, $langs)) {
  152.                     $this->_queue['add'][$pageID][$lang][$stringID] = $string;
  153.                 }
  154.             }
  155.             return true;
  156.         } else {
  157.             $add = array();
  158.             foreach ($strings as $lang => $string) {
  159.                 if (in_array($lang, $langs)) {
  160.                     $add[$pageID][$lang][$stringID] = $string;
  161.                 }
  162.             }
  163.             return $this->_add($add);
  164.         }
  165.     }
  166.  
  167.     // }}}
  168.     // {{{ remove()
  169.  
  170.     /**
  171.      * Remove an entry from the domain.
  172.      *
  173.      * @param string $stringID string ID
  174.      * @param string $pageID   page/group ID
  175.      *
  176.      * @return true|PEAR_Error on failure
  177.      */
  178.     function remove($stringID, $pageID)
  179.     {
  180.         if (!isset($pageID)) {
  181.             $pageID = $this->options['default_domain'];
  182.         }
  183.  
  184.         if ($this->_bulk) {
  185.             $this->_queue['remove'][$pageID][$stringID] = true;
  186.             return true;
  187.         } else {
  188.             $tmp = array($pageID => array($stringID => true));
  189.             return $this->_remove($tmp);
  190.         }
  191.  
  192.     }
  193.  
  194.     // }}}
  195.     // {{{ removePage
  196.  
  197.     /**
  198.      * Remove all the strings in the given page/group (domain)
  199.      *
  200.      * @param string $pageID page/group ID
  201.      * @param string $path   path to gettext data dir
  202.      *
  203.      * @return mixed true on success, PEAR_Error on failure
  204.      */
  205.     function removePage($pageID = null, $path = null)
  206.     {
  207.         if (!isset($pageID)) {
  208.             $pageID = $this->options['default_domain'];
  209.         }
  210.  
  211.         if (!isset($path)) {
  212.             if (!empty($this->_domains[$pageID])) {
  213.                 $path = $this->_domains[$pageID];
  214.             } else {
  215.                 $path = $this->_domains[$this->options['default_domain']];
  216.             }
  217.         }
  218.  
  219.         if (PEAR::isError($e = $this->_removeDomain($pageID))) {
  220.             return $e;
  221.         }
  222.         
  223.         $this->fetchLangs();
  224.         foreach ($this->langs as $langID => $lang) {
  225.             $domain_file = $path .'/'. $langID .'/LC_MESSAGES/'. $pageID .'.';
  226.             if (!@unlink($domain_file.'mo') || !@unlink($domain_file.'po')) {
  227.                 return $this->raiseError('Cannot delete page ' . $pageID. ' (file '.$domain_file.'.*)',
  228.                     TRANSLATION2_ERROR
  229.                 );
  230.             }
  231.         }
  232.  
  233.         return true;
  234.     }
  235.  
  236.     // }}}
  237.     // {{{ update()
  238.  
  239.     /**
  240.      * Update
  241.      *
  242.      * Alias for Translation2_Admin_Container_gettext::add()
  243.      *
  244.      * @param string $stringID string ID
  245.      * @param string $pageID   page/group ID
  246.      * @param array  $strings  strings
  247.      *
  248.      * @return  mixed
  249.      * @access  public
  250.      * @see add()
  251.      */
  252.     function update($stringID, $pageID, $strings)
  253.     {
  254.         return $this->add($stringID, $pageID, $strings);
  255.     }
  256.  
  257.     // }}}
  258.     // {{{ removeLang()
  259.  
  260.     /**
  261.      * Remove Language
  262.      *
  263.      * @param string $langID language ID
  264.      * @param bool   $force  (unused)
  265.      *
  266.      * @return true|PEAR_Error
  267.      * @access public
  268.      */
  269.     function removeLang($langID, $force = false)
  270.     {
  271.         include_once 'System.php';
  272.         foreach ((array) $this->_domains as $domain => $path) {
  273.             if (is_dir($fp = $path .'/'. $langID)) {
  274.                 if (PEAR::isError($e = System::rm(array('-rf', $fp))) || !$e) {
  275.                     return $e ? $e : PEAR::raiseError(sprintf(
  276.                             'Could not remove language "%s" from domain "%s" '.
  277.                             'in path "%s" (probably insufficient permissions)',
  278.                             $langID, $domain, $path
  279.                         ),
  280.                         TRANSLATION2_ERROR
  281.                     );
  282.                 }
  283.             }
  284.         }
  285.         return true;
  286.     }
  287.  
  288.     // }}}
  289.     // {{{ updateLang()
  290.  
  291.     /**
  292.      * Update the lang info in the langs_avail file
  293.      *
  294.      * @param array $langData language data
  295.      *
  296.      * @return mixed Returns true on success or PEAR_Error on failure.
  297.      * @access public
  298.      */
  299.     function updateLang($langData)
  300.     {
  301.         if (PEAR::isError($changed = $this->_updateLangData($langData))) {
  302.             return $changed;
  303.         }
  304.         return $changed ? $this->_writeLangsAvailFile() : true;
  305.     }
  306.  
  307.     // }}}
  308.     // {{{ getPageNames()
  309.  
  310.     /**
  311.      * Get a list of all the domains
  312.      *
  313.      * @return array
  314.      * @access public
  315.      */
  316.     function getPageNames()
  317.     {
  318.         return array_keys($this->_domains);
  319.     }
  320.  
  321.     // }}}
  322.     // {{{ begin()
  323.  
  324.     /**
  325.      * Begin
  326.      *
  327.      * @return  void
  328.      * @access  public
  329.      */
  330.     function begin()
  331.     {
  332.         $this->_bulk = true;
  333.     }
  334.  
  335.     // }}}
  336.     // {{{ commit()
  337.  
  338.     /**
  339.      * Commit
  340.      *
  341.      * @return true|PEAR_Error on failure.
  342.      * @access public
  343.      */
  344.     function commit()
  345.     {
  346.         $this->_bulk = false;
  347.         if (isset($this->_queue['remove'])) {
  348.             if (PEAR::isError($e = $this->_remove($this->_queue['remove']))) {
  349.                 return $e;
  350.             }
  351.         }
  352.         if (isset($this->_queue['add'])) {
  353.             if (PEAR::isError($e = $this->_add($this->_queue['add']))) {
  354.                 return $e;
  355.             }
  356.         }
  357.         return true;
  358.     }
  359.  
  360.     // }}}
  361.     // {{{ _add()
  362.  
  363.     /**
  364.      * Add
  365.      *
  366.      * @param array &$bulk array('pageID' => array([languages]))
  367.      *
  368.      * @return true|PEAR_Error on failure.
  369.      * @access private
  370.      */
  371.     function _add(&$bulk)
  372.     {
  373.         include_once 'File/Gettext.php';
  374.         $gtFile = &File_Gettext::factory($this->options['file_type']);
  375.         $langs  = $this->getLangs('array');
  376.  
  377.         foreach ((array) $bulk as $pageID => $languages) {
  378.             //create the new domain on demand
  379.             if (!isset($this->_domains[$pageID])) {
  380.                 if (PEAR::isError($e = $this->_addDomain($pageID))) {
  381.                     return $e;
  382.                 }
  383.             }
  384.             $path = $this->_domains[$pageID];
  385.             if ($path[strlen($path)-1] != '/' && $path[strlen($path)-1] != '\\') {
  386.                 $path .= '/';
  387.             }
  388.             $file = '/LC_MESSAGES/'. $pageID .'.'. $this->options['file_type'];
  389.  
  390.             foreach ($languages as $lang => $strings) {
  391.  
  392.                 if (is_file($path . $lang . $file)) {
  393.                     if (PEAR::isError($e = $gtFile->load($path . $lang . $file))) {
  394.                         return $e;
  395.                     }
  396.                 }
  397.  
  398.                 if (!isset($gtFile->meta['Content-Type'])) {
  399.                     $gtFile->meta['Content-Type'] = 'text/plain; charset=';
  400.                     if (isset($langs[$lang]['encoding'])) {
  401.                         $gtFile->meta['Content-Type'] .= $langs[$lang]['encoding'];
  402.                     } else {
  403.                         $gtFile->meta['Content-Type'] .= $this->options['default_encoding'];
  404.                     }
  405.                 }
  406.  
  407.                 foreach ($strings as $stringID => $string) {
  408.                     $gtFile->strings[$stringID] = $string;
  409.                 }
  410.  
  411.                 if (PEAR::isError($e = $gtFile->save($path . $lang . $file))) {
  412.                     return $e;
  413.                 }
  414.  
  415.                 //refresh cache
  416.                 $this->cachedDomains[$lang][$pageID] = $gtFile->strings;
  417.             }
  418.         }
  419.  
  420.         $bulk = null;
  421.         return true;
  422.     }
  423.  
  424.     // }}}
  425.     // {{{ _remove()
  426.  
  427.     /**
  428.      * Remove
  429.      *
  430.      * @param array &$bulk array('pageID' => array([languages]))
  431.      *
  432.      * @return true|PEAR_Error on failure.
  433.      * @access private
  434.      */
  435.     function _remove(&$bulk)
  436.     {
  437.         include_once 'File/Gettext.php';
  438.         $gtFile = &File_Gettext::factory($this->options['file_type']);
  439.  
  440.         foreach ($this->getLangs('ids') as $lang) {
  441.             foreach ((array) $bulk as $pageID => $stringIDs) {
  442.                 $file = sprintf(
  443.                     '%s/%s/LC_MESSAGES/%s.%s',
  444.                     $this->_domains[$pageID],
  445.                     $lang,
  446.                     $pageID,
  447.                     $this->options['file_type']
  448.                 );
  449.  
  450.                 if (is_file($file)) {
  451.                     if (PEAR::isError($e = $gtFile->load($file))) {
  452.                         return $e;
  453.                     }
  454.  
  455.                     foreach (array_keys($stringIDs) as $stringID) {
  456.                         unset($gtFile->strings[$stringID]);
  457.                     }
  458.  
  459.                     if (PEAR::isError($e = $gtFile->save($file))) {
  460.                         return $e;
  461.                     }
  462.  
  463.                     //refresh cache
  464.                     $this->cachedDomains[$lang][$pageID] = $gtFile->strings;
  465.                 }
  466.             }
  467.         }
  468.  
  469.         $bulk = null;
  470.         return true;
  471.     }
  472.  
  473.     // }}}
  474.     // {{{ _addDomain()
  475.  
  476.     /**
  477.      * Add the path-to-the-new-domain to the domains-path-INI-file
  478.      *
  479.      * @param string $pageID domain name
  480.      *
  481.      * @return true|PEAR_Error on failure
  482.      * @access private
  483.      */
  484.     function _addDomain($pageID)
  485.     {
  486.         $domain_path = count($this->_domains) ? reset($this->_domains) : 'locale/';
  487.  
  488.         if (!is_resource($f = fopen($this->options['domains_path_file'], 'a'))) {
  489.             return $this->raiseError(sprintf(
  490.                     'Cannot write to domains path INI file "%s"',
  491.                     $this->options['domains_path_file']
  492.                 ),
  493.                 TRANSLATION2_ERROR_CANNOT_WRITE_FILE
  494.             );
  495.         }
  496.  
  497.         $CRLF = $this->options['carriage_return'];
  498.  
  499.         while (true) {
  500.             if (@flock($f, LOCK_EX)) {
  501.                 fwrite($f, $CRLF . $pageID . ' = ' . $domain_path . $CRLF);
  502.                 @flock($f, LOCK_UN);
  503.                 fclose($f);
  504.                 break;
  505.             }
  506.         }
  507.  
  508.         $this->_domains[$pageID] = $domain_path;
  509.  
  510.         return true;
  511.     }
  512.  
  513.     // }}}
  514.     // {{{ _removeDomain()
  515.  
  516.     /**
  517.      * Remove the path-to-the-domain from the domains-path-INI-file
  518.      *
  519.      * @param string $pageID domain name
  520.      *
  521.      * @return true|PEAR_Error on failure
  522.      * @access private
  523.      */
  524.     function _removeDomain($pageID)
  525.     {
  526.         $domain_path = count($this->_domains) ? reset($this->_domains) : 'locale/';
  527.  
  528.         if (!is_resource($f = fopen($this->options['domains_path_file'], 'r+'))) {
  529.             return $this->raiseError(sprintf(
  530.                     'Cannot write to domains path INI file "%s"',
  531.                     $this->options['domains_path_file']
  532.                 ),
  533.                 TRANSLATION2_ERROR_CANNOT_WRITE_FILE
  534.             );
  535.         }
  536.  
  537.         $CRLF = $this->options['carriage_return'];
  538.  
  539.         while (true) {
  540.             if (@flock($f, LOCK_EX)) {
  541.                 $pages = file($this->options['domains_path_file']);
  542.                 foreach ($pages as $page) {
  543.                     if (preg_match('/^'.$pageID.'\s*=/', $page)) {
  544.                         //skip
  545.                         continue;
  546.                     }
  547.                     fwrite($f, $page . $CRLF);
  548.                 }
  549.                 fflush($f);
  550.                 ftruncate($f, ftell($f));
  551.                 @flock($f, LOCK_UN);
  552.                 fclose($f);
  553.                 break;
  554.             }
  555.         }
  556.  
  557.         unset($this->_domains[$pageID]);
  558.  
  559.         return true;
  560.     }
  561.  
  562.     // }}}
  563.     // {{{ _writeLangsAvailFile()
  564.  
  565.     /**
  566.      * Write the langs_avail INI file
  567.      *
  568.      * @return true|PEAR_Error on failure.
  569.      * @access private
  570.      */
  571.     function _writeLangsAvailFile()
  572.     {
  573.         if (PEAR::isError($langs = $this->getLangs())) {
  574.             return $langs;
  575.         }
  576.  
  577.         if (!is_resource($f = fopen($this->options['langs_avail_file'], 'w'))) {
  578.             return $this->raiseError(sprintf(
  579.                     'Cannot write to available langs INI file "%s"',
  580.                     $this->options['langs_avail_file']
  581.                 ),
  582.                 TRANSLATION2_ERROR_CANNOT_WRITE_FILE
  583.             );
  584.         }
  585.         $CRLF = $this->options['carriage_return'];
  586.  
  587.         @flock($f, LOCK_EX);
  588.  
  589.         foreach ($langs as $id => $data) {
  590.             fwrite($f, '['. $id .']'. $CRLF);
  591.             foreach ($this->_fields as $k) {
  592.                 if (isset($data[$k])) {
  593.                     fwrite($f, $k . ' = ' . $data[$k] . $CRLF);
  594.                 }
  595.             }
  596.             fwrite($f, $CRLF);
  597.         }
  598.  
  599.         @flock($f, LOCK_UN);
  600.         fclose($f);
  601.         return true;
  602.     }
  603.  
  604.     // }}}
  605.     // {{{ _updateLangData()
  606.  
  607.     /**
  608.      * Update Lang Data
  609.      *
  610.      * @param array $langData language data
  611.      *
  612.      * @return true|PEAR_Error on failure.
  613.      * @access private
  614.      */
  615.     function _updateLangData($langData)
  616.     {
  617.         if (PEAR::isError($langs = $this->getLangs())) {
  618.             return $langs;
  619.         }
  620.  
  621.         $lang    = &$langs[$langData['lang_id']];
  622.         $changed = false;
  623.         foreach ($this->_fields as $k) {
  624.             if (    isset($langData[$k]) &&
  625.                     (!isset($lang[$k]) || $langData[$k] != $lang[$k])) {
  626.                 $lang[$k] = $langData[$k];
  627.                 $changed  = true;
  628.             }
  629.         }
  630.  
  631.         if ($changed) {
  632.             $lang['id']  = $langData['lang_id'];
  633.             $this->langs = $langs;
  634.         }
  635.         return $changed;
  636.     }
  637.  
  638.     // }}}
  639. }
  640. ?>