registerTask( 'cancel', 'doTask' ); $this->registerTask( 'cancelxml', 'doTask' ); $this->registerTask( 'checkin', 'doTask' ); $this->registerTask( 'checkout', 'doTask' ); $this->registerTask( 'publish', 'doTask' ); $this->registerTask( 'remove', 'doTask' ); $this->registerTask( 'removexml', 'doTask' ); $this->registerTask( 'unpublish', 'doTask' ); $this->registerTask( 'add', 'edit' ); $this->registerTask( 'apply', 'edit' ); $this->registerTask( 'save', 'edit' ); $this->registerTask( 'addxml', 'editXML' ); $this->registerTask( 'applyxml', 'editXML' ); $this->registerTask( 'editxml', 'editXML' ); $this->registerTask( 'savexml', 'editXML' ); $this->registerTask( 'default', 'setDefault' ); } /** * Build the filters for a view * @param array an associative array of allowed fields and values * @param string the namespace for this view * @return array The Configuration in an array */ function _buildfilters( $allowed=array(), $namespace='' ) { // initialise global $mainframe; $filters = array(); if ($namespace) { $namespace = trim($namespace,'.') . '.'; } else { $namespace = 'com_translationsmanager.'; } // get the limitstart for this namespace $filters['limitstart'] = $mainframe->getUserStateFromRequest( $namespace . 'limitstart', 'limitstart', 0 ); // then validate all the filters for this namespace foreach ($allowed as $k=>$v) { // values are all changed to lower case $values = explode('|',$v); foreach ( $values as $k2=>$v2 ) { $values[$k2] = strtolower($v2); } // A: get the old/current value $old = $mainframe->getUserState( 'request.' . $namespace . $k ); // B: get the new value from the user input $new = $mainframe->getUserStateFromRequest( $namespace . $k, $k, $values[0] ); // C: check that the new (lowercase) value is valid if ($k=='limit') { $new = (is_numeric($new)) ? abs($new) : $values[0]; } else if ( $v && array_search(strtolower($new),$values) === false ) { $new = $values[0]; } // D: reset the page to #1 if the value has changed if ( $old != $new ) { $options['limitstart'] = 0; } // set the value $filters[$k] = $new; } // return return $filters; } /** * Build the configuration options. * @return array The Configuration in an array */ function _buildoptions () { // initialise configuration variables global $mainframe; $task = strtolower($this->_task); $options['config'] = JComponentHelper::getParams( 'com_translationsmanager' ); $options['autoCorrect'] = $options['config']->get( 'autoCorrect', 'a^=รข' ); $options['backticks'] = $options['config']->get( 'backticks', 0 ); $options['cid'] = JRequest::getVar( 'cid', array(''), '', 'array' ); $options['client_lang'] = $mainframe->getUserStateFromRequest('com_translationsmanager.client_lang','client_lang',''); $options['globalChanges'] = $options['config']->get('globalChanges', 0 ); $options['limitstart'] = $mainframe->getUserStateFromRequest('com_translationsmanager.limitstart','limitstart',''); $options['newprocess'] = JRequest::getVar('newprocess',0,'','integer' ); $options['refLang'] = $options['config']->get( 'refLanguage', 'en-GB' ); $options['refLangMissing'] = false; $options['searchStyle'] = $options['config']->get( 'searchStyle', 'background-color:yellow;' ); $options['task'] = strtolower($task); // initialise a list of available languages $options['languages'] = array(); $options['clients'] = array(); $options['clients']['S'] = JText::_('Site'); foreach (JLanguage::getKnownLanguages(JPATH_SITE) as $k=>$v) { $options['languages']['S_'.$k] = $options['clients']['S'] . ' - '.$v['name']; } $options['clients']['A'] = JText::_('Administrator'); foreach (JLanguage::getKnownLanguages(JPATH_ADMINISTRATOR) as $k=>$v) { $options['languages']['A_'.$k] = $options['clients']['A'] . ' - '.$v['name']; } if (JFolder::exists(JPATH_INSTALLATION)) { $options['clients']['I'] = JText::_('Installation'); foreach (JLanguage::getKnownLanguages(JPATH_INSTALLATION) as $k=>$v) { $options['languages']['I_'.$k] = $options['clients']['I'] . ' - '.$v['name']; } } // validate client_lang (split, reassemble with cases, check against allowed values, on failure default to first allowed value) $cl_split = preg_split("/[^a-z]/i",$options['client_lang']); $options['client_lang'] = strtoupper($cl_split[0]) . '_' . strtolower($cl_split[1]) . '-' . strtoupper($cl_split[2]); if (!isset($options['languages'][$options['client_lang']])) { $options['client_lang'] = key($options['languages']); } // set client variables $options['client'] = $options['client_lang']{0}; if ($options['client']=='A') { $options['basePath'] = JPATH_ADMINISTRATOR; $options['clientKey'] = 'administrator'; } else if ($options['client']=='I') { $options['basePath'] = JPATH_INSTALLATION; $options['clientKey'] = 'installation'; } else { $options['basePath'] = JPATH_SITE; $options['clientKey'] = 'site'; } $options['clientName'] = JText::_( $options['clientKey'] ); // validate that the reference language exists on this client if (!isset($options['languages'][$options['client'].'_'.$options['refLang']])) { // initialise to en-GB $use = 'en-GB'; // look for the first key index containing the reference language string foreach($options['languages'] as $k=>$v) { if ($k{0}==$options['client']) { $use = substr($k,-4); break; } } // set back to $options key $options['refLang'] = $use; } // set language variables $options['lang'] = substr($options['client_lang'],2); $options['langLen'] = strlen($options['lang']); $options['langName'] = $options['languages'][$options['client_lang']]; $options['langPath'] = JLanguage::getLanguagePath( $options['basePath'], $options['lang'] ); $options['refLangLen'] = strlen($options['refLang']); $options['refLangPath'] = JLanguage::getLanguagePath( $options['basePath'], $options['refLang'] ); // set reference language variables $options['isReference'] = intval( $options['lang']==$options['refLang'] ); // validate the cid array if ( !is_array( $options['cid'] )) { if (!empty($options['cid'])) $options['cid'] = array($options['cid']); else $options['cid'] = array(''); } // process the cid array to validate filenames foreach($options['cid'] as $k=>$v ){ if ($v) { // strip unpublished prefix if (substr($v,0,3)=='xx.') $v = substr($v,3); // strip files that don't match the selected language if (substr($v,0,$options['langLen'])!=$options['lang']) unset($options['cid'][$k]); // otherwise set back to $options else $options['cid'][$k] = $v; } } // set the filename $options['filename'] = $options['cid'][0]; // build the autocorrect array $autoCorrect = array(); if ($options['autoCorrect']) { foreach(explode(';',$options['autoCorrect']) as $v){ list($k2,$v2)=explode('=',$v); $k2 = trim($k2); $v2 = trim($v2); if(($k2)&&($v2)) { $autoCorrect[$k2] = $v2; } } } $options['autoCorrect'] = $autoCorrect; // return the options array return $options; } /** * Processing File(s) * @param array $options The configuration array for the component * @param string $task a specific task (overrides $options) * @param mixed $file a specific filename or array of filenames to process (overrides $options) * @param string $redirect_task the task to use when redirecting (blank means no redirection) * @param boolean $report whether or not to report processing success/failure */ function _multitask( $task=null, $file=null, $redirect_task='files', $report=true ) { // variables $options =& $this->getOptions(); $task = strtolower( is_null($task) ? $this->_task : $task ); // validate the task if ($task=='cancel') { $task = 'checkin'; $redirect_task = 'files'; $report = false; } else if ($task=='cancelxml') { $task = 'checkin'; $redirect_task = 'languages'; $report = false; } // validate the filename // 1: use a specific file or files // 2: use the client_lang // 3: check that we have at least one file if ($file) { $options['cid'] = (is_array($file)) ? $file : array($file); } else if ($task=='removexml') { $options['cid'][0] = $options['lang'].'.xml'; } else if ( (empty($options['cid'][0])) && ($task!='checkin') ) { echo "\n"; exit(); } // initialise file classes jimport('joomla.filesystem.file'); // initialise checkout file content if ($task=='checkout') { $user = & JFactory::getUser(); $chk_file_content = time() . '#' . $user->get('id','0') . '#' . $user->get('name','[ Unknown User ]'); } // initialise variables global $mainframe; $file_list = array(); $nofile_list = array(); $inifile_list = array(); $last = ''; // process each passed file name (always the 'real' filename) foreach ($options['cid'] as $file) { // validate the filename language prefix if ( preg_match('/^[a-z]{2,3}-[A-Z]{2}[.].*/',$file) ) { // get the language and language path $lang = substr($file,0,$options['langLen']); $langPath = JLanguage::getLanguagePath( $options['basePath'], $lang ); // ensure that XML files are only affected by XML tasks if ( (substr($file,-4)=='.xml') && (substr($task,-3)!='xml') ) { // continue without error warning continue; } // ensure that there are no existing published INI files when we are deleting an XML file if ( ($task=='removexml') && (count( JFolder::files($langPath,'^'.$lang.'.*ini$') ) ) ) { // error and continue $inifile_list[$file] = $file; continue; }; // get file path-names $chk_file = 'chk.'.$file; $pub_file = $file; $unpub_file = 'xx.'.$file; // check for an unpublished file if (JFile::exists($langPath.DS.$unpub_file)) { $file = $unpub_file; } // check the file exists else if (!JFile::exists($langPath.DS.$file)) { // error and continue $nofile_list[$file] = $file; continue; } // cancel/checkin a file // checkout a file // delete a file // delete an XML file // publish a file // unpublish a file // otherwise break because the task isn't recognised if ( ($task=='checkin') && (JFile::exists($langPath.DS.$chk_file)) ) { $do = JFile::delete( $langPath.DS.$chk_file ); } else if ($task=='checkout') { $do = Jfile::write( $langPath.DS.$chk_file, $chk_file_content ); } else if ($task=='remove') { $do = JFile::delete( $langPath.DS.$file ); } else if ($task=='removexml') { if ( $do = JFile::delete( $langPath.DS.$file ) ) { $do = JFolder::delete( $langPath ); } } else if ($task=='publish') { $do = JFile::move( $file, $pub_file, $langPath ); } else if ($task=='unpublish') { $do = JFile::move( $file, $unpub_file, $langPath ); } else { break; } // build an array of things to hide form the filename $filename_hide = array(); // add the function to the file list on success if ($do) { $file_list[$file] = str_replace( 'xx.'.$lang, $lang,substr($file,0,-4) ); } } } if ($report) { // report processing success if (count($file_list)) { $mainframe->enqueueMessage(sprintf(JText::_($task.' success'), count($file_list), implode(', ',$file_list) ) ); } // report existing ini files if (count($inifile_list)) { $mainframe->enqueueMessage(sprintf(JText::_($task.' inifile'), count($inifile_list), implode(', ',$inifile_list) ) ); } } // redirect if ($redirect_task) { if ($task=='removexml') { $mainframe->redirect( 'index.php?option=com_translationsmanager' ); } else { $mainframe->redirect( 'index.php?option=com_translationsmanager&client_lang='.$options['client_lang'].'&task='.$redirect_task ); } } } /** * Do various tasks * @uses _multitask */ function doTask() { return $this->_multitask(); } /** * Create Edit or Save a Translation File */ function edit() { // import file functions jimport('joomla.filesystem.file'); // variables global $mainframe; $options =& $this->getOptions(); // build the search highlight array $options['filter_search'] = $mainframe->getUserStateFromRequest( 'com_translationsmanager.files.filter_search', 'filter_search', '' ); // we are creating a new file // always in the reference language if ($options['task']=='add') { $options['newprocess'] = 1; if (! $options['isReference'] ) { $mainframe->enqueueMessage( JText::_('Always create in reference language') ); } } // we are in the process of creating a new file // the filename is set by the 'newfilename' field if ( $options['newprocess'] ) { $options['newfilename'] = strtolower(JRequest::getVar('newfilename','','','string')); // validate the filename if ($options['newfilename']) { // strip off ini if (substr($options['newfilename'],-4)=='.ini') { $options['newfilename'] = substr($options['newfilename'],0,-4); } // strip off language if (preg_match('/^[a-z]{2}-[a-z]{2}[.].*/',$options['newfilename'])) { $options['newfilename'] = substr($options['newfilename'],6); } // set variables $options['filename'] = $options['lang'].'.'.$options['newfilename'].'.ini'; } // no filename else { // report error $mainframe->enqueueMessage( JText::_('filename desc') ); // change task if ($options['task']!='add') { $options['task'] = 'edit'; $options['field_error_list']['filename'] = JText::_('filename'); } } } // 2: otherwise verify that we have a filename // 3: otherwise validate the checkout status of the selected file else if (empty($options['filename'])) { $mainframe->enqueueMessage( JText::_('You must select a file to edit') ); $mainframe->redirect( 'index.php?option=com_translationsmanager&task=files' ); } else if ( $content = @file_get_contents($options['langPath'].DS.'chk.'.$options['filename'])) { list ($timestamp,$userid,$username) = explode( '#', $content.'##' ); $user = & JFactory::getUser(); // validate the checkout if ( ( (time()-$timestamp) < 3600 ) && ( $userid <> 0 ) && ( $userid <> $user->get('id','0') ) ) { // report and redirect $checkin = '[' . JText::_( 'Checkin' ) . ']'; $mainframe->enqueueMessage(sprintf(JText::_('checked out by'), $options['filename'], $username, $checkin ) ); $mainframe->redirect( 'index.php?option=com_translationsmanager&task=files' ); } } // set the reference language filename from the selected filename $options['refFilename'] = str_replace($options['lang'],$options['refLang'],$options['filename']); // find the published reference language file // default to an unpublished reference file if ( JFile::exists($options['refLangPath'].DS.$options['refFilename']) ) { $options['ref_path_file'] = $options['refLangPath'].DS.$options['refFilename']; } else { $options['ref_path_file'] = $options['refLangPath'].DS.'xx.'.$options['refFilename']; } // find the published selected language file // default to an unpublished new file if ( JFile::exists($options['langPath'].DS.$options['filename']) ) { $options['path_file'] = $options['langPath'].DS.$options['filename']; } else { $options['path_file'] = $options['langPath'].DS.'xx.'.$options['filename']; } // STRINGS: initialise $editData from the reference language file contents // $editData is an analogue of the reference file // header lines are skipped // comments and blank lines are strings with an integer index // key=value pairs are arrays with the key as an index $editData = array(); $header = 0; $refStrings = array(); if ( $refContent = @file($options['ref_path_file']) ) { foreach ($refContent as $k=>$v) { $v = trim($v); // grab the comments (but skip up to 6 lines before we have any strings in the file) // grab the strings if ( (empty($v))||($v{0}=='#')||($v{0}==';') ) { if($header++>6) $editData[$k] = $v; } else if(strpos($v,'=')) { $header = 7; list($key,$value) = explode('=',$v,2); $key = strtoupper($key); $refStrings[$key] = $value; $editData[$key] = array('ref'=>$value,'edit'=>$value); if ($options['isReference']) { $editData[$key]['lang_file'] = $value; } } } } // STRINGS: load the selected file contents and process into $editData // only when the selected language is not the same as the reference language if ($options['isReference']) { $fileContent = $refContent; $fileStrings = array(); $fileMeta = TranslationsHelper::getINIMeta( $fileContent, $fileStrings ); $editStrings = $fileStrings; } else if ( $fileContent = @file($options['path_file']) ) { $fileStrings = array(); $fileMeta = TranslationsHelper::getINIMeta( $fileContent, $fileStrings ); $editStrings = $fileStrings; foreach ( $fileStrings as $k=>$v ) { $editData[$k]['edit'] = $v; $editData[$k]['lang_file'] = $v; } } else { $fileContent = array(); $fileStrings = array(); $fileMeta = array( 'headertype'=>1, 'owner'=>'ff', 'complete'=>0 ); $editStrings = array(); } // STRINGS: load the user form contents and process into $editData $editFormOnly = array(); if ($FormKeys = JRequest::getVar( 'ffKeys', array(), '', 'ARRAY', JREQUEST_ALLOWRAW )) { $FormValues = JRequest::getVar( 'ffValues', array(), '', 'ARRAY', JREQUEST_ALLOWRAW ); // process each key=value pair from the form into $editData foreach ($FormKeys as $k=>$v) { if ( ($v) && (isset($FormValues[$k])) ) { $key = strtoupper(trim(stripslashes($v))); $value = trim(stripslashes(str_replace('\n',"\n",$FormValues[$k]))); $editStrings[$key] = $value; $editData[$key]['edit'] = $value; $editData[$key]['user_form'] = $value; } } // every element of $editData must have a form entry foreach($editData as $k=>$v){ if ( is_array($v) && !isset($v['user_form']) ) { unset($editStrings[$k]); unset($editData[$k]); } } } // META: get the XML and status meta then initialise $options['XMLmeta'] = TranslationsHelper::getXMLMeta($options['langPath'].DS.$options['lang'].'.xml'); $statusMeta = TranslationsHelper::getINIstatus( $refStrings, $editStrings ); $editMeta = array_merge( $options['XMLmeta'], $fileMeta, $statusMeta ); $editMeta['filename'] = $options['filename']; // META: apply any user form values foreach($editMeta as $k=>$v) { $editMeta[$k] = JRequest::getVar($k,$v,'','string'); } // META: require meta values foreach(array('version','author') as $v) { if(empty($editMeta[$v])) { $options['field_error_list'][$v] = JText::_($v); } } // ERRORS: report any errors and change the task if ((!empty($options['field_error_list']))&&($options['task']!='add')) { $mainframe->enqueueMessage( sprintf( JText::_('Values Required'), implode(', ',$options['field_error_list']) ) ); $options['task'] = 'edit'; } // create a new file or save an existing file if (($options['task']=='apply')||($options['task']=='save')) { // ensure the file does not already exist when we are creating a new file if ( ($options['newprocess'])&&(JFile::exists($options['path_file'])) ) { // report error and set task flag $mainframe->enqueueMessage( sprintf(JText::_('Language INI Exists'),$options['newfilename']) ); $options['task'] = 'edit'; } // otherwise save the file else { // check the complete status // we set the complete value to the number of strings that are 'unchanged' // so that if the reference INI file should change the 'complete' flag is unset/broken $editMeta['complete'] = JRequest::getVar( 'complete', '', 'post', 'string' ); $editMeta['complete'] = ( $editMeta['complete'] == 'COMPLETE' ) ? $editMeta['unchanged'] : 0; // build the header if ($editMeta['headertype']==1) { $saveContent = '# $Id: ' . $options['filename'] . ' ' . $editMeta['version'] . ' ' . date('Y-m-d H:i:s') . ' ' . $editMeta['owner'] . ' ~' . $editMeta['complete'] . ' $'; } else { $saveContent = '# version ' . $editMeta['version'] . ' ' . date('Y-m-d H:i:s') . ' ~' . $editMeta['complete']; } $saveContent .= "\n" . '# author ' . $editMeta['author']; $saveContent .= "\n" . '# copyright ' . $editMeta['copyright']; $saveContent .= "\n" . '# license ' . $editMeta['license']; $saveContent .= "\n\n" . '# Note : All ini files need to be saved as UTF-8'; $saveContent .= "\n\n"; // process the $editData array to get the remaining content $changedStrings = array(); $header = 0; foreach ($editData as $k=>$v) { // 1: add a blank line or comment // 2: add a key=value line (no need to addslashes on quote marks) if (!is_array($v)) { $saveContent .= $v . "\n"; } else { // change newlines in the value $value = preg_replace( '/(\r\n)|(\n\r)|(\n)/', '\n', $v['edit'] ); // change single-quotes or backticks in the value if ($options['backticks']>0) { $value = strtr( $value, "'", '`' ); } else if ($options['backticks']<0) { $value = strtr( $value, '`', "'" ); } // set back to $editData $editData[$k]['edit'] = $value; // add to file content $saveContent .= $k . '=' . $value . "\n"; // if the string is in the selected language file if (isset($v['lang_file'])) { // and it has changed (via the user form) if ($v['lang_file'] != $v['edit']) { // log the change in a translation array $changedStrings[ "\n".$k.'='.$v['lang_file'] ] = "\n".$k.'='.$v['edit']; } } } } // if there is no reference Language File, automatically initialise/create one which is the same as the selected language file if ($options['refLangMissing']) { if ( JFile::write( $options['refLangPath'].DS.$options['refLangFile'], trim($saveContent) ) ) { $mainframe->enqueueMessage(sprintf(JText::_('Language INI Created'), $options['refLangFile'] ) ); } } // 1: write the selected language file and clear newprocess flag // 2: report failure if ( JFile::write( $options['path_file'], trim($saveContent) ) ) { $mainframe->enqueueMessage(sprintf(JText::_('Language INI '.(($options['newprocess'])?'Created':'Saved') ),$options['clientName'],$options['filename'] ) ); $options['newprocess'] = 0; } else { $mainframe->enqueueMessage( sprintf(JText::_('Could not write to file'),$options['path_file']) ); } // process changed strings globally across all the the ini files from the selected language directory if ( (count($changedStrings)) && ($options['globalChanges']) ) { $write = 0; $writeFiles = array(); if ($files = JFolder::files($options['langPath'])) { foreach ($files as $file) { // skip non-INI files // skip this file // skip this file (unpublished) // skip checked out files if ( (strtolower(substr($file,-4)!='.ini')) || ($file==$options['filename']) || ($file=='xx.'.$options['filename']) || (array_search($options['langPath'].DS.'chk.'.$file,$files)) ) { continue; } // otherwise grab the file content if ($content = file_get_contents($options['langPath'].DS.$file)) { // parse the changed strings $new_content = strtr( $content, $changedStrings ); // check for changes then write to the file if ($new_content != $content) { if ( JFile::write( $options['langPath'].DS.$file, trim($new_content) ) ) { $writeFiles[$write++] = $file; } } } } } // report if ($write) { $mainframe->enqueueMessage( sprintf(JText::_('Global String Change'), $write, implode('; ',$writeFiles) ) ); } } } } // 1: checkin when we are saving (this will redirect also) // 2: call the html when we are editing or applying (and checkout existing files) if ($options['task'] == 'save') { $this->_multitask( 'checkin', $options['filename'], 'files', false ); } else { $view = $this->getView( $this->_name, 'html'); $view->setLayout( 'edit' ); $view->assignRef( 'data', $editData ); $view->assignRef( 'meta', $editMeta ); $view->assignRef( 'options', $options ); $view->display(); if (!$options['newprocess']) { $this->_multitask( 'checkout', $options['filename'], false, false ); } } } /** * Create Edit or Save an XML Language File * @uses HTML_translationsmanager::editINI To build and output the HTML when editing or applying changes */ function editXML() { // import file functions jimport('joomla.filesystem.file'); // variables global $mainframe; $options =& $this->getOptions(); $options['field_error_list'] = array(); // new tasks set newprocess if ($options['task']=='addxml') { $options['newprocess'] = 1; $mainframe->enqueueMessage( JText::_('Tag Desc') ); } // when we are in the process of creating a new file // the client is passed by the 'addclient' field // the language tag is passed by the 'tag' field if ($options['newprocess']) { // get the client and set the client name and path $client = JRequest::getVar('newclient','','','string'); if (($client=='A')||($client=='I')||($client=='S')){ $options['client'] = $client; if ($options['client']=='A') { $options['basePath'] = JPATH_ADMINISTRATOR; $options['clientKey'] = 'administrator'; } else if ($options['client']=='I') { $options['basePath'] = JPATH_INSTALLATION; $options['clientKey'] = 'installation'; } else { $options['basePath'] = JPATH_SITE; $options['clientKey'] = 'site'; } $options['clientName'] = JText::_( $options['clientKey'] ); } // validate the language tag (split, check case, reassemble, on failure report error and change task) // report error and change task if we need to $tag_split = preg_split( "/[^a-z]/i", JRequest::getVar('tag','','','string') ); $tag = strtolower($tag_split[0]) . '-' . strtoupper($tag_split[1]); print_r($tag); if (!preg_match('/^[a-z]{2,3}-[A-Z]{2}$/',$tag)) { $options['field_error_list']['tag'] = JText::_('Tag Desc'); if ($options['task']!='addxml') { $options['task'] = 'editxml'; } } // set variables $options['client_lang'] = $options['client'].'_'.$tag; $options['lang'] = $tag; $options['langPath'] = $options['basePath'].DS.'language'.DS.$options['lang']; $options['filename'] = $tag.'.xml'; } // otherwise we use the selected language XML file else { $options['filename'] = $options['lang'].'.xml'; } // initialise the $editData array (with all the necessary entries) // any extra entries in the XML file will be retained but are not editable $editData = array( 'tag' => '', 'name' => '', 'description' => '', 'version' => '1.5.0', 'creationDate' => date('Y-m-d'), 'author' => '', 'authorUrl' => '', 'authorEmail' => '', 'copyright' => '', 'license' => 'http://www.gnu.org/copyleft/gpl.html GNU/GPL', 'metadata' => array( 'name' => '', 'tag' => '', 'rtl' => 0, 'locale' => '', 'winCodePage' => 'iso-8859-1', 'backwardLang' => '', 'pdfFontName' => 'vera' ), 'params' => '', ); // load the XML file (if there is one, there won't be when creating a new language) // if a filename exists when we are creating a new file we will copy values from it $xml = & JFactory::getXMLParser('Simple'); if (JFile::exists($options['langPath'].DS.$options['filename'])) { if ($xml->loadFile($options['langPath'].DS.$options['filename'])) { // go through each child of the xml root (using the XML file as master) // all the nodes in the XML file are parsed in lowercase // do it this way to ensure that we retain all the existing data in the XML file foreach( $xml->document->children() as $node ) { // main nodes if ($node->name()!='metadata') { $editData[$node->name()] = $node->data(); } // metadata nodes else { foreach ($node->children() as $subnode) { $editData['metadata'][$subnode->name()] = $subnode->data(); } } } // copy any lowercase keys to mixed case keys // remove the lowercase key afterwards foreach ($editData as $k=>$v) { if ($k!='metadata') { $k_lc = strtolower($k); if ( $k_lc != $k ) { $editData[$k] = $editData[$k_lc]; unset($editData[$k_lc]); } } else { foreach ($editData['metadata'] as $k=>$v) { $k_lc = strtolower($k); if ( $k_lc != $k ) { $editData['metadata'][$k] = $editData['metadata'][$k_lc]; unset($editData['metadata'][$k_lc]); } } } } // ensure that metadata and main body values match foreach ($editData['metadata'] as $k=>$v) { if (isset($editData[$k])) { $editData[$k] = $v; } } } } // require a valid XML file (unless creating a new language) else if (!$options['newprocess']) { $mainframe->enqueueMessage( sprintf(JText::_('Invalid XML File'),$options['langPath'].DS.$options['filename']) ); $mainframe->redirect( 'index.php?option=com_translationsmanager' ); } // apply the user form data (only when not empty) foreach($editData as $k=>$v){ // check the main nodes if (is_string($v)) $editData[$k] = JRequest::getVar($k,$v,'','string'); // check the metadata nodes else if (is_array($v)) { foreach($v as $k2=>$v2) $editData[$k][$k2] = JRequest::getVar($k2,$v2,'','string'); } } // validate the language name values $editData['metadata']['pdfFontName'] = strtolower($editData['metadata']['pdfFontName']); $editData['metadata']['rtl'] = intval($editData['metadata']['rtl']); // validate required (non-blank) $required = array ('tag','name','version','creationDate','author','locale','winCodePage','backwardLang','pdfFontName'); foreach ($required as $v) { if ( (isset($editData[$v])) && (empty($editData[$v])) ) { $options['field_error_list'][$v] = JText::_($v); } else if ( (isset($editData['metadata'][$v])) && (empty($editData['metadata'][$v])) ) { $options['field_error_list'][$v] = JText::_($v); } } // report any errors and change the task if (($options['field_error_list'])&&($options['task']!='addxml')) { $mainframe->enqueueMessage( sprintf( JText::_('Values Required'), implode(', ',$options['field_error_list']) ) ); $options['task'] = 'editxml'; } // create a new file or save an existing file if (($options['task']=='savexml')||($options['task']=='applyxml')) { // ensure the file does not already exist when we are creating a new language if ( ($options['newprocess'])&&(JFile::exists($options['langPath'].DS.$options['filename'])) ) { // report error and set task flag $mainframe->enqueueMessage( sprintf(JText::_('Language XML Exists'), $options['lang'] )); $options['task'] = 'editxml'; } // otherwise build and save the file else { // build the file content $saveData = ''."\n"; $saveData .= ''."\n"; foreach($editData as $k=>$v){ if (is_string($v)) { $saveData .= "\t".'<'.$k.'>'.htmlspecialchars($v).''."\n"; } else if (is_array($v)) { $saveData .= "\t".'<'.$k.'>'."\n"; foreach($v as $k2=>$v2){ $saveData .= "\t\t".'<'.$k2.'>'.htmlspecialchars($v2).''."\n"; } $saveData .= "\t".''."\n"; } } $saveData .= ''."\n"; // create the directory when we are creating a language // do this manually because JFile::write does not work on windows ( if ($options['newprocess']) { jimport('joomla.filesystem.folder'); if (!JFolder::create($options['langPath'])) { // report failure and set task flag $mainframe->enqueueMessage( sprintf(JText::_('Folder Created'),$options['langPath'] ) ); $options['task'] = 'applyxml'; } } // write the XML file (this will create a new file or overwrite an existing file) // 1: report new/existing file and clear new process flag // 2: report failure and set task flag if we can't write if ( JFile::write( $options['langPath'].DS.$options['filename'], $saveData ) ) { $msg = ($options['newprocess']) ? 'Language XML Created' : 'Language XML Saved' ; $mainframe->enqueueMessage( sprintf(JText::_($msg),$options['clientName'],$options['lang']) ); $options['newprocess'] = 0; } else { $mainframe->enqueueMessage( sprintf(JText::_('Could not write to file'),$options['langPath'].DS.$options['filename']) ); $options['task'] = 'applyxml'; } } } // redirect or show HTML after saving if ($options['task'] == 'savexml') { $mainframe->redirect( 'index.php?option=com_translationsmanager' ); } else { $view = $this->getView( $this->_name, 'html'); $view->setLayout( 'editxml' ); $view->assignRef( 'data', $editData ); $view->assignRef( 'options', $options ); $view->display(); } } /** * Get the configuration options. * @return array The Configuration in an array */ function &getOptions () { if (!isset($this->_options)) { $this->_options = $this->_buildoptions(); } return $this->_options; } /** * Make a language the default language for a client */ function setDefault( ) { // variables global $mainframe; $params = JComponentHelper::getParams('com_languages'); $options =& $this->getOptions(); if ($options['client']=='A') { $client = 'administrator'; } else if ($options['client']=='S') { $client = 'site'; } else if ($options['client']=='I') { $client = 'installation'; } else { return false; } $lang = $options['lang']; // check for request forgeries. $token = JUtility::getToken(); if (!JRequest::getInt($token, 0, 'post')) { JError::raiseError(403, 'Request Forbidden'); } // set variables $params->set($client, $lang); $table =& JTable::getInstance('component'); $table->loadByOption( 'com_languages' ); $table->params = $params->toString(); // save the changes if (!$table->check()) { JError::raiseWarning( 500, $table->getError() ); $write = false; } else if (!$table->store()) { JError::raiseWarning( 500, $table->getError() ); $write = false; } else { $write = true; } // Redirect on success/failure if ($write) { $mainframe->redirect('index.php?option=com_translationsmanager', sprintf( JText::_('Default Language Saved'), JText::_($client), $options['lang'] ) ); } else { $mainframe->redirect('index.php?option=com_translationsmanager', JText::_('ERRORCONFIGWRITEABLE') ); } } /** * Show Credits/Homepage for the component */ function credits() { // call the html view $view = $this->getView( $this->_name, 'html'); $view->setLayout( 'credits' ); $view->display(); } /** * Show a List of INI Translation Files for a given Client-Language */ function files() { // filesystem functions jimport('joomla.filesystem.folder'); jimport('joomla.filesystem.file'); // variables global $mainframe; $options =& $this->getOptions(); $user = &JFactory::getUser(); $userid = $user->get('id',0); // build client_lang select box foreach ($options['languages'] as $k=>$v) { $sel_lang[] = JHTML::_( 'select.option', $k, $v ); } $lists['client_lang'] = JHTML::_( 'select.genericlist', $sel_lang, 'client_lang', 'class="inputbox" size="1" onchange="document.adminForm.limitstart.value=0;document.adminForm.submit( );"', 'value', 'text', $options['client_lang'] ); // validate all the filters (specific to this view) $allowed = array( 'client_lang' => '', 'filter_search' => '', 'filter_state' => '*|U|P', 'filter_status' => '*|NS|IP|C', 'filter_order' => 'name|status|strings|version|datetime|author', 'filter_order_Dir' => 'asc|desc', 'limit' => $mainframe->getCfg('list_limit') ); $filters = $this->_buildfilters( $allowed, 'com_translationsmanager.files.' ); // copy to $options $options = array_merge( $options, $filters ); // copy to $lists $lists['order'] = $options['filter_order']; $lists['order_Dir'] = $options['filter_order_Dir']; // validate and build the filter_search box $options['dosearch'] = ''; if ($options['filter_search']) { // 1: turn it into a case-insensitive regexp // 2: check and use a submitted regexp // 3: invalid regexp if ($options['filter_search']{0}!='/') { $options['dosearch'] = '/.*'.trim($options['filter_search'],'/').'.*/i'; } else if ( @preg_match($options['filter_search'],'') !== false ) { $options['dosearch'] = $options['filter_search']; } else { $mainframe->enqueueMessage( JText::_('Search') . ': ' . sprintf( JText::_('Invalid RegExp'), htmlentities($options['filter_search']) ), 'error' ); $options['filter_search'] = ''; } } $lists['search'] = ''; // build the filter_state select box $extra = 'class="inputbox" size="1" onchange="document.adminForm.submit();"'; $sel_state[] = JHTML::_( 'select.option', '*', JText::_( 'Any State' ) ); $sel_state[] = JHTML::_( 'select.option', 'P', JText::_( 'Published' ) ); $sel_state[] = JHTML::_( 'select.option', 'U', JText::_( 'Not Published' ) ); $lists['state'] = JHTML::_( 'select.genericlist', $sel_state, 'filter_state', $extra, 'value', 'text', $options['filter_state'] ); // build the filter_status select box $sel_status[] = JHTML::_( 'select.option', '*', JText::_( 'Any Status' ) ); $sel_status[] = JHTML::_( 'select.option', 'NS', JText::_( 'Not Started' ) ); $sel_status[] = JHTML::_( 'select.option', 'IP', JText::_( 'In Progress' ) ); $sel_status[] = JHTML::_( 'select.option', 'C', JText::_( 'Complete' ) ); if ($options['isReference']) { $options['filter_status'] = '*'; } if ($options['lang'] == $options['refLang']) { $extra .= ' disabled'; } $lists['status'] = JHTML::_( 'select.genericlist', $sel_status, 'filter_status', $extra, 'value', 'text', $options['filter_status'] ); // create objects for loading data $refLangLoader = new JLanguage( $options['refLang'] ); $LangLoader = ( $options['lang'] == $options['refLang'] ) ? $refLangLoader : new JLanguage( $options['lang'] ); // load all the the ini filenames (published or unpublished) from the reference directory // load the same from the selected language directory $refLangFiles = JFolder::files( $options['refLangPath'] , '^(xx|'.$options['refLang'].')[.].*ini$' ); if ($options['isReference']) { $LangFiles = array_flip( $refLangFiles ); } else { $LangFiles = JFolder::files( $options['langPath'] , '^(xx|'.$options['lang'].')[.].*ini$' ); $LangFiles = array_flip( $LangFiles ); } // build a composite filename list, keyed using the filename without language tag $allFiles = array(); foreach ( $refLangFiles as $v ) { $k = preg_replace('/^(xx[.])*'.$options['refLang'].'[.]/','',$v); $allFiles[$k]['refLang'] = $v; } foreach ( $LangFiles as $v=>$k ) { $k = preg_replace('/^(xx[.])*'.$options['lang'].'[.]/','',$v); $allFiles[$k]['lang'] = $v; } // get default metadata for the selected language $xmlData = TranslationsHelper::getXMLMeta( $options['langPath'].DS.$options['lang'].'.xml' ); // process the reference language INI files and compare them against the files for the selected language $rows = array (); $rowid = 1; foreach ($allFiles as $k=>$v) { // get the content, bare filename, Meta and Strings from the reference language INI file // in some cases there may not be a reference language INI file if (isset($v['refLang'])) { $refContent = file( $options['refLangPath'].DS.$v['refLang'] ); $refFileName = ( substr($v['refLang'],0,3)=='xx.' ) ? substr($v['refLang'],3) : $v['refLang']; $fileName = $options['lang'] . substr($refFileName,$options['refLangLen']); $refStrings = array(); $refMeta = TranslationsHelper::getINIMeta( $refContent, $refStrings ); } else { $refContent = array(); $fileName = ( substr($v['lang'],0,3)=='xx.' ) ? substr($v['lang'],3) : $v['lang']; $refFileName = $options['refLang'] . substr($fileName,$options['langLen']); $refStrings = array(); $refMeta = array( 'author' => '', 'date' => '', 'strings' => '', 'time' => '', 'version' => '' ); } // initialise the row $row = new StdClass(); $row->author = $refMeta['author']; $row->bom = 'UTF-8'; $row->checkedout = 0; $row->changed = 0; $row->date = $refMeta['date']; $row->extra = 0; $row->filename = $fileName; $row->id = $rowid++; $row->name = substr($row->filename,($options['langLen']+1),-4); $row->refexists = intval( isset($v['refLang']) ); $row->reffilename = $refFileName; $row->refstrings = $refMeta['strings']; $row->searchfound = 0; $row->status = 0; $row->strings = $refMeta['strings']; $row->time = $refMeta['time']; $row->unchanged = 0; $row->unpub_filename = 'xx.'.$row->filename; $row->version = $refMeta['version']; // 1: file is published // 2: file is unpublished // 3: file does not exist if ( JFile::exists($options['langPath'].DS.$row->filename) ) { $row->exists = 1; $row->path_file = $options['langPath'].DS.$row->filename; $row->published = 1; $row->writable = is_writable($row->path_file); } else if ( JFile::exists($options['langPath'].DS.$row->unpub_filename) ) { $row->exists = 1; $row->path_file = $options['langPath'].DS.$row->unpub_filename; $row->published = 0; $row->writable = is_writable($row->path_file); } else { $row->author = ''; $row->date = ''; $row->exists = 0; $row->path_file = $options['langPath'].DS.$row->unpub_filename; $row->published = 0; $row->status = 0; $row->version = ''; $row->writable = 1; } // get the checkout status of the selected file if ( $content = @file_get_contents($options['langPath'].DS.'chk.'.$row->filename)) { $row->checkedout = ( (strpos($content,'#'.$userid.'#')) || (strpos($content,'#0#')) ) ? 0 : 1; } // scan an existing language file if ( (!$options['isReference']) && ($row->exists) ) { $fileContent = file($row->path_file); $fileStrings = array(); $fileMeta = TranslationsHelper::getINIMeta( $fileContent, $fileStrings, $refStrings ); if ( $fileMeta['bom'] == 'UTF-8' ) { foreach ($fileMeta as $k=>$v) { $row->{$k} = $v; } } else { $row->bom = $fileMeta['bom']; $row->writable = 0; } } else { $fileContent = array(); $fileStrings = array(); $fileMeta = array(); } // search the files // $refContent and $fileContent are arrays containing each line of the reference and translation file if ( $options['dosearch'] ) { $row->searchfound_ref = preg_match_all($options['dosearch'], implode("\n",$refContent), $arr ); if (! $options['isReference'] ) { $row->searchfound_tran = preg_match_all($options['dosearch'], implode("\n",$fileContent), $arr ); } else { $row->searchfound_tran = $row->searchfound_ref; } $row->searchfound = $row->searchfound_ref + $row->searchfound_tran; } // set the datetime $row->datetime = $row->date.$row->time; // change the name if ($row->name == '') { $row->name = ' [core]'; } // store the file $rows[$row->name] = $row; } // build the fileset totals and filter out rows we don't need/want $options['fileset-files'] = 0; $options['fileset-exists'] = 0; $options['fileset-published'] = 0; $options['fileset-refstrings'] = 0; $options['fileset-changed'] = 0; foreach( $rows as $k=>$row) { // add to totals $options['fileset-files']++; $options['fileset-exists'] += $row->exists; $options['fileset-published'] += $row->published; $options['fileset-refstrings'] += $row->refstrings; $options['fileset-changed'] += $row->changed; // filter out searched items // filter out published or unpublished items // filter out status of items if ( ( ($options['dosearch']) && ($row->searchfound == 0) ) || ( ($options['filter_state']=='P') && ($row->published <> 1) ) || ( ($options['filter_state']=='U') && ($row->published <> 0) ) || ( ($options['filter_status']=='NS') && ($row->status > 0) ) || ( ($options['filter_status']=='IP') && (($row->status <= 0)||($row->status >= 100)) ) || ( ($options['filter_status']=='C') && ($row->status < 100) ) ) { unset($rows[$k]); } } // set fileset status if ($options['fileset-changed'] == 0) { $options['fileset-status'] = 0; } if ($options['fileset-refstrings'] == $options['fileset-changed']) { $options['fileset-status'] = 100; } else { $options['fileset-status'] = floor( ($options['fileset-changed']/$options['fileset-refstrings'])*100 ); } // build the pagination jimport('joomla.html.pagination'); $pageNav = new JPagination( count($rows), $options['limitstart'], $options['limit'], 'index.php?option=com_translationsmanager&task=files' ); // sort the $rows array $order_Int = (strtolower($lists['order_Dir'])=='desc') ? -1 : 1; JArrayHelper::sortObjects( $rows, $lists['order'], $order_Int ); // slice the array so we only show one page $rows = array_slice( $rows, $pageNav->limitstart, $pageNav->limit ); // call the html view $view = $this->getView( $this->_name, 'html'); $view->setLayout( 'files' ); $view->assignRef( 'data', $rows ); $view->assignRef( 'options', $options ); $view->assignRef( 'lists', $lists ); $view->assignRef( 'pagenav', $pageNav ); $view->display(); } /** * Show a List of installed Languages (XML files) */ function languages() { // variables global $mainframe; $options =& $this->getOptions(); // default languages $params = JComponentHelper::getParams('com_languages'); $default['A'] = $params->get('administrator','en-GB'); $default['I'] = $params->get('installation','en-GB'); $default['S'] = $params->get('site','en-GB'); // validate all the filters (specific to this view) // each filter key has a list of allowed values; the first is the default value // a blank value skips validation // the key "limit" allows any integer $allowed = array( 'filter_client' => '*|' . implode( '|', array_keys($options['clients']) ), 'filter_order' => 'tag', 'filter_order_Dir' => 'asc|desc', 'limit' => $mainframe->getCfg('list_limit') ); $filters = $this->_buildfilters( $allowed, 'com_translationsmanager.languages.' ); // copy to $options $options = array_merge( $options, $filters ); // copy to $lists $lists['order'] = $options['filter_order']; $lists['order_Dir'] = $options['filter_order_Dir']; // get the list of languages $rows = array(); foreach ($options['languages'] as $k=>$v) { $row = new StdClass(); $row->tag = substr($k,2); $row->client = strtoupper($k{0}); $row->client_lang = $k; $row->filename = $row->tag . '.xml'; // check filter if ($options['filter_client']!='*') { if ($row->client != $options['filter_client']) { continue; } } // check default status $row->isdefault = intval( $default[$row->client]==$row->tag ); // get the directory path if ($k{0}=='A') { $path = JPATH_ADMINISTRATOR; $row->client_name = JText::_('Administrator'); } else if ($k{0}=='I') { $path = JPATH_INSTALLATION; $row->client_name = JText::_('Installation'); } else { $path = JPATH_SITE; $row->client_name = JText::_('Site'); } $path .= DS.'language'.DS.$row->tag; // count the number of INI files (published or unpublished) $row->files = count( JFolder::files( $path, '(xx[.]|^)'.$row->tag.'.*ini$' ) ); // load and add XML attributes // force the tag $data = TranslationsHelper::getXMLMeta($path.DS.$row->filename); $data['tag'] = $row->tag; foreach($data as $k2=>$v2) { $row->$k2 = $v2; } // add to rows $rows[] = $row; } // build the pagination jimport('joomla.html.pagination'); $pageNav = new JPagination( count($rows), $options['limitstart'], $options['limit'], 'index.php?option=com_translationsmanager' ); // sort the $rows array $order_Int = (strtolower($lists['order_Dir'])=='desc') ? -1 : 1; JArrayHelper::sortObjects( $rows, $lists['order'], $order_Int ); // slice the array so we only show one page $rows = array_slice( $rows, $pageNav->limitstart, $pageNav->limit ); // call the html view $view = $this->getView( $this->_name, 'html'); $view->setLayout( 'languages' ); $view->assignRef( 'data', $rows ); $view->assignRef( 'options', $options ); $view->assignRef( 'lists', $lists ); $view->assignRef( 'pagenav', $pageNav ); $view->display(); } /** * Package INI files into an installation zip file */ function package() { // variables global $mainframe; $options =& $this->getOptions(); $files = array(); // set the zip path // optionally change the tag if there is a [tag=xx-XX] in the path $zippath = '/' . $options['config']->get( 'zippath', 'tmp/[tag].[client].zip' ); $ziptag = $options['lang']; if ( preg_match('/\[tag=([^\]]*)\]/',$zippath,$match) ) { $zippath = str_replace($match[0],'[tag]',$zippath); if ( preg_match('/^[a-z]{2}-[a-z]{2}$/i',$match[1]) ) { $ziptag = strtolower(substr($match[1],0,2)) . '-' . strtoupper(substr($match[1],-2)); $mainframe->enqueueMessage( sprintf( JText::_('ZIP Translate Tag'), $options['lang'], $ziptag ) ); } } // process all the files in the selected language directory into an array ready to be packaged // translate the language tag if configured jimport('joomla.filesystem.file'); foreach ( JFolder::files( $options['langPath'] ) as $k=>$filename ) { // 1: grab the XML data and info // 2a: skip checkout marker files // 2b: grab the INI data into the files array if ( $filename == $options['lang'].'.xml' ) { $xmlname = $filename; $xmldata = file_get_contents( $options['langPath'].DS.$filename ); $xmltime = filemtime( $options['langPath'].DS.$filename ); $xml = TranslationsHelper::getXMLMeta( $options['langPath'].DS.$filename ); $xml['client'] = $options['clientKey']; $xml['tag'] = $ziptag; $xmlname = str_replace($options['lang'],$ziptag,$xmlname); $xmldata = str_replace($options['lang'],$ziptag,$xmldata); } else if ( substr($filename,-4)=='.ini') { if ( substr($filename,0,4)=='chk.' ) { continue; } else { $k = ( substr($filename,0,3)=='xx.' ) ? substr($filename,3) : $filename; $k = str_replace($options['lang'],$ziptag,$k); $files[$k]['name'] = $k; $files[$k]['data'] = file_get_contents( $options['langPath'].DS.$filename ); $files[$k]['time'] = filemtime( $options['langPath'].DS.$filename ); } } } // check we have XML data and files if (!isset($xml)) { JError::raiseNotice( 500, sprintf( JText::_('ZIP No XML'), $options['clientKey'].'DS'.$options['lang'].'.xml' ) ); } else if (!count($files)) { JError::raiseNotice( 500, sprintf( JText::_('ZIP No Files'), $options['clientKey'] ) ); } else { // sort the files ksort($files); // build the XML install file $install = ' ' . $xml['name'] .' ' . $xml['tag'] .' ' . $xml['version'] .' ' . $xml['creationDate'] .' ' . $xml['author'] .' ' . $xml['authorEmail'] .' ' . $xml['authorUrl'] .' ' . $xml['copyright'] .' ' . $xml['license'] .' ' . $xml['description'] .' '; foreach ( $files as $k=>$v ) { $install .= ' ' . $v['name'] . ''; } $install .= ' ' . $xmlname . ' '; // finish the files array $files['xml']['name'] = $xmlname; $files['xml']['data'] = $xmldata; $files['xml']['date'] = $xmltime; $files['install']['name'] = 'install.xml'; $files['install']['data'] = $install; $files['install']['date'] = time(); // configure the package filename and type $type = substr( $zippath, strrpos( $zippath, '.' ) + 1 ); $zippath = str_replace( '[client]', $xml['client'], $zippath ); $zippath = str_replace( '[tag]', $xml['tag'], $zippath ); $ziproot = JPATH_ROOT.$zippath; $zipfile = substr( $zippath, strrpos( $zippath, DS ) + 1 ); $ziplink = JURI::root() . $zipfile; // run the packager jimport('joomla.filesystem.archive'); if ( !$packager =& JARchive::getAdapter( $type ) ) { JError::raiseWarning( 500, sprintf( JText::_('ZIP Adapter Failure'), $type ) ); } else if ( $packager->create( $ziproot, $files, array() ) ) { $mainframe->enqueueMessage( sprintf( JText::_('ZIP Create Success'), $ziplink, $zipfile ) ); } else { JError::raiseNotice( 500, sprintf( JText::_('ZIP Create Failure'), $ziplink ) ); } } // Redirect to the default page $mainframe->redirect( 'index.php?option=com_translationsmanager' ); } } ?>