* @copyright 2004 by http://wombat.exit0.net * @package wombatSite * @subpackage install */ /** * make tool like unix-make * * helper class to install and maintain site * * @version 1.0.0 * @package wombatSite * @subpackage install */ class wbTranslateTools { /** * overwriteable factory parameter * @access protected * @var array $_parameter */ var $_parameter = array( 'configDir', 'varDir', 'configFile' ); /** * a temporary directory... * @access protected * @var string $_tmpDir */ var $_tmpDir; /** * verbosity level * @access private * @var int $_verbose */ var $_verbose = 0; /** * debug mode * @access private * @var int $_debug */ var $_debug = 0; /** * run over system files * @access private * @var int $_system */ var $_system = 0; /** * install languages * @access protected * @var string $_tmpDir */ var $_languages = array(); /** * text domains (gnu getext) * @access protected * @var array $_domains */ var $_domains = array( 'system' => 'wombat', 'site' => 'site' ); /** * known commands * @access private * @var array $_commands */ var $_commands = array( 'xpages' => 'extract translateable strings from page definitions', 'xtemplate' => 'extract translateable strings from templates', 'xadminmenu' => 'extract translateable strings from admin menu', 'xgettext' => 'run xgettext to generate pot file', 'msgmerge' => 'merge pot with exsiting po files', 'translate' => 'create mo files of exiting languages' ); /** * file handler * @access private * @var int $_phpDump */ var $_phpDump; /** * bring birth! * * @access public * @return boolean $result true on success */ function __construct() { $this->_tmpDir = wbFactory::getParam( 'systemDir' ) . '/var/tmp'; } /** * php4 constructor wrapper * * @access public * @see __construct() */ function wbTranslateTools() { $this->__construct(); } /** * event hanlder * * @access private * @param string $e named event * @param mixed $info event inforation * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _onEvent( $e, $info ) { return true; } /** * run command: xadminmenu * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function runXpages() { $files = array(); $baseDir = wbFactory::getParam( 'baseDir' ) . '/' . wbFactory::getParam( 'configDir' ); $dir = 'pages'; $res = $this->_findFile( $baseDir, $dir, '/(.*)(\.xml)$/i', $files ); if( patErrorManager::isError( $res ) ) { return $res; } $this->_onEvent( 'pagesfiles', $files ); $this->_phpDumpStart( 'pages', 'site' ); $conf =& wbFactory::singleton( 'patConfiguration' ); $j = 0; foreach( $files as $file ) { $conf->loadConfig( $file ); $c = $conf->getConfigValue( 'page' ); $this->_phpDumpAdd( $file, ++$j, $c['title'] ); $this->_phpDumpAdd( $file, ++$j, $c['brief'] ); $conf->clearConfigValue(); } $this->_phpDumpEnd(); return true; } /** * run command: xadminmenu * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function runXadminmenu() { if( !$this->_system ) { return true; } $cacheDir = wbFactory::getParam( 'baseDir' ) . '/' . wbFactory::getParam( 'varDir' ); $menuFile = 'admin/menu/menu.ser'; $infoFile = 'admin/menu/info.ser'; $result = $this->_phpDumpStart( 'menu', 'system' ); if( patErrorManager::isError( $result ) ) { return $result; } $j = 0; $info = unserialize( file_get_contents( $cacheDir . '/' .$infoFile ) ); foreach( $info as $in ) { $this->_phpDumpAdd( $infoFile, ++$j, $in['title'] ); $this->_phpDumpAdd( $infoFile, ++$j, $in['brief'] ); } $menu = unserialize( file_get_contents( $cacheDir . '/' .$menuFile ) ); foreach( $menu as $m ) { for( $i = 0; $i < count( $m ); ++$i ) { $this->_phpDumpAdd( $menuFile, ++$j, $m[$i]['title'] ); $this->_phpDumpAdd( $menuFile, ++$j, $m[$i]['brief'] ); } } $this->_onEvent( 'adminmenu', $j ); $this->_phpDumpEnd(); return true; } /** * run command: xtemplate * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function runXtemplate() { if( $this->_system ) { $this->_scanTemplates( 'system' ); } $this->_scanTemplates( 'site' ); return true; } /** * run command: xgettext * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function runXgettext() { if( $this->_system ) { $this->_scanPhpFiles( 'system' ); } $this->_scanPhpFiles( 'site' ); return true; } /** * run command: msgmerge * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function runMsgmerge() { if( $this->_system ) { $this->_mergePo( 'system' ); } $this->_mergePo( 'site' ); return true; } /** * run command: msgfmt * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function runTranslate() { if( $this->_system ) { $this->_translate( 'system' ); } $this->_translate( 'site' ); return true; } /** * run command: msgmerge * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _mergePo( $type ) { switch( $type ) { case 'system': $dom = $this->_domains['system']; $folder = 'lang/' . $dom ; $baseDir = wbFactory::getParam( 'systemDir' ); break; case 'site': $dom = $this->_domains['site']; $folder = 'lang/' . $dom ; $baseDir = wbFactory::getParam( 'baseDir' ); if( !is_dir( $baseDir . '/' . $folder ) ) { mkdir( $baseDir . '/' . $folder, 0755 ); } break; default: return false; break; } $this->_onEvent( 'source', $type ); $files = array(); $res = $this->_findFile( $baseDir, $folder, '/(.*)(\.po)$/i', $files ); if( patErrorManager::isError( $res ) ) { return $res; } $this->_onEvent( 'msgmergestart', $files ); foreach( $files as $file ) { $this->_onEvent( 'msgmergepo', $file ); $path = $baseDir . '/' . $file; rename( $path, $path . '.old' ); $silent = ''; if( !$this->_verbose ) { $silent = ' --quiet'; } $cmd = 'msgmerge '. $silent.' --force-po -o '. $path .' ' . $path . '.old ' . $baseDir. '/lang/' . $this->_domains[$type] . '.pot'; $res = 0; $out = array(); exec( $cmd, $out, $res ); if( $res ) { print_r( $out ); return patErrorManager::raiseError( 'wbTranslateTools:5', 'msgmerge failed', $cmd ); } unlink( $path . '.old' ); } return true; } /** * run command: msgfmt * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _translate( $type ) { switch( $type ) { case 'system': $dom = $this->_domains['system']; $folder = 'lang/' . $dom ; $baseDir = wbFactory::getParam( 'systemDir' ); $varDir = 'var'; break; case 'site': $dom = $this->_domains['site']; $folder = 'lang/' . $dom ; $baseDir = wbFactory::getParam( 'baseDir' ); if( !is_dir( $baseDir . '/' . $folder ) ) { mkdir( $baseDir . '/' . $folder, 0755 ); } $varDir = wbFactory::getParam( 'varDir' ); break; default: return false; break; } $this->_onEvent( 'source', $type ); $files = array(); $res = $this->_findFile( $baseDir, $folder, '/(.*)(\.po)$/i', $files ); if( patErrorManager::isError( $res ) ) { return $res; } $this->_onEvent( 'translatestart', $files ); foreach( $files as $file ) { $lang = basename( $file, '.po' ); $this->_onEvent( 'translatepo', $file ); $verbose = ''; if( $this->_verbose ) { $verbose = ' -v'; } $des = $baseDir . '/' .$varDir. '/lang/'. $lang . '/LC_MESSAGES/'. $this->_domains[$type] .'.mo'; $this->_mkDir( dirname( $des ) ); $cmd = 'msgfmt '. $verbose.' -o '. $des . ' ' . $baseDir . '/' . $file; $res = 0; $out = array(); exec( $cmd, $out, $res ); if( $res ) { print_r( $out ); return patErrorManager::raiseError( 'wbTranslateTools:5', 'msgfmt failed', $cmd ); } } return true; } /** * run command: xgettext * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _scanPhpFiles( $type ) { switch( $type ) { case 'system': $des = $this->_domains['system']; $folder = array( 'include', 'var/cache/lang/system' ); $baseDir = wbFactory::getParam( 'systemDir' ); break; case 'site': $des = $this->_domains['site']; $folder = array( 'extension', wbFactory::getParam( 'varDir' ) . '/cache/lang/site' ); $baseDir = wbFactory::getParam( 'baseDir' ); break; default: return false; break; } $this->_onEvent( 'source', $type ); // create pot file $files = array(); foreach( $folder as $dir ) { $res = $this->_findFile( $baseDir, $dir, '/(.*)(\.php)$/i', $files ); if( patErrorManager::isError( $res ) ) { return $res; } } $this->_onEvent( 'phpfiles', $files ); $lFile = tempnam( $this->_tmpDir, 'translate' ); $lfh = fopen( $lFile, 'w' ); if( !$lfh ) { return patErrorManager::raiseError( 'wbTranslateTools:2', 'Could not open temporary file', 'File "' . $$lFile . '"' ); } fwrite( $lfh, implode( "\n", $files ) ); fclose( $lfh ); $cmd = 'xgettext -f '.$lFile.' -o '. $baseDir .'/lang/' . $this->_domains[$type] . '.pot'; $res = 0; $out = array(); exec( $cmd, $out, $res ); if( $res ) { print_r( $out ); return patErrorManager::raiseError( 'wbTranslateTools:3', 'xgettext failed', $cmd ); } unlink( $lFile ); return true; } /** * scan template folders * * @access public * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _scanTemplates( $type ) { $des = 'templates'; switch( $type ) { case 'system': $folder = array( 'admin/templates' ); $baseDir = wbFactory::getParam( 'systemDir' ); break; case 'site': $folder = array( 'templates' ); $baseDir = wbFactory::getParam( 'baseDir' ); break; default: return false; break; } $this->_onEvent( 'source', $type ); $preg = '#(]*)>)(.*)()#imsU'; $pregForm = '##imsU'; $pregFormAtts = '#(\w+)="(gettext):\'(.*)\'"#imsU'; $result = $this->_phpDumpStart( $des, $type ); if( patErrorManager::isError( $result ) ) { return $result; } $files = array(); foreach( $folder as $dir ) { $res = $this->_findFile( $baseDir, $dir, '/(.*)(\.[f]?tmpl)$/i', $files ); if( patErrorManager::isError( $res ) ) { return $res; } } $this->_onEvent( 'templatefiles', $files ); foreach( $files as $file ) { $this->_onEvent( 'templatestart', $file ); $html = file_get_contents( $baseDir . '/' . $file ); $j = 0; // extract patTemplate:gettext if( preg_match_all( $preg, $html, $match, PREG_SET_ORDER ) ) { for( $i = 0; $i < count( $match ); ++$i) { $this->_phpDumpAdd( $file, $j, $match[$i][4] ); ++$j; } } // extract patForms - attribute="gettext:''" if( preg_match_all( $pregForm, $html, $match, PREG_SET_ORDER ) ) { foreach( $match as $m ) { $atts = $m[2]; if( preg_match_all( $pregFormAtts, $atts, $attMatch, PREG_SET_ORDER ) ) { foreach( $attMatch as $am ) { $this->_phpDumpAdd( $file, $j, stripslashes( $am[3] ) ); ++$j; } } } } $this->_onEvent( 'templateend', $j ); } $this->_phpDumpEnd(); return true; } /** * find php files * * @access public * @param string $base global directory * @param string $dir folder to sgcna * @param string $preg pereg to match file * * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _findFile( $base, $dir, $preg, &$files ) { $dh = dir( $base . '/' . $dir ); if( !$dh ) { return patErrorManager::raiseError( 'wbTranslateTools:1', 'Could not open folder', 'Dir: "' . $base . '/' . $dir . '"' ); } while( false !== ( $file = $dh->read() ) ) { if( $file[0] == '.' ) { continue; } // recursion if( is_dir( $base . '/' . $dir . '/' . $file ) ) { $res = $this->_findFile( $base, $dir . '/' . $file, $preg, $files ); if( patErrorManager::isError( $res ) ) { return $res; } continue; } // check regualr expression if( !preg_match( $preg, $file ) ) { continue; } array_push( $files, $dir . '/' . $file ); } $dh->close(); return true; } /** * create php file * * @access public * @param string $file destination * @param string $type either "system" or "site" * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _phpDumpStart( $file , $type ) { if( $type == 'system' ) { $des = wbFactory::getParam( 'systemDir' ) . '/var/cache/lang/system/' . $file . '.php'; } else { $des = wbFactory::getParam( 'baseDir' ) . '/'. wbFactory::getParam( 'varDir' ) .'/cache/lang/site/' . $file . '.php'; } $this->_phpDump = fopen( $des, 'w' ); if( !$this->_phpDump ) { return patErrorManager::raiseError( 'wbTranslateTools:1', 'Could not open destination file for writing', 'File: "' . $des. '"' ); } $code = array(); array_push( $code, '_phpDump, implode( "\n", $code ) . "\n" ); return true; } /** * create php file * * @access public * @param string $file destination * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _phpDumpAdd( $src, $id, $value ) { // $src = str_replace( '/', '_', $src ); $name = sprintf( '%s:%04d', $src, $id ); fwrite( $this->_phpDump, '$var[\'' . $name . '\'] = gettext( \'' . addslashes( $value ) . '\');' . "\n" ); return true; } /** * create php file * * @access public * @param string $file destination * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _phpDumpEnd() { $code = array(); array_push( $code, '// end' ); array_push( $code, '?>' ); fwrite( $this->_phpDump, implode( "\n", $code ) . "\n" ); fclose( $this->_phpDump ); $this->_phpDump = null; return true; } /** * make folder recursive * * @access public * @param string $dir folder path * @return boolean true on success, false if any target has failed (or patError object on error!) */ function _mkDir( $dir ) { if( is_dir( $dir ) ) { return true; } $path = explode( '/', $dir ); array_pop( $path ); if( empty( $path ) ) { return false; } $path = implode( '/', $path ); $this->_mkDir( $path ); mkdir( $dir, 0755 ); return true; } } ?>