/**
  * Create Edit or Save a Translation File
  */
 function edit_language()
 {
     global $option;
     // import file functions
     jimport('joomla.filesystem.file');
     // variables
     global $mainframe;
     $options = Language_manager::getOptions();
     $options['newprocess'] = 0;
     // build the search highlight array
     $options['filter_search'] = $mainframe->getUserStateFromRequest($option . '.files.filter_search', 'filter_search', '');
     // 2: otherwise verify that we have a filename
     // 3: otherwise validate the checkout status of the selected file
     if (empty($options['filename'])) {
         $mainframe->enqueueMessage(JText::_('You must select a file to edit'));
         $mainframe->redirect('index.php?option=' . $option . '&task=language_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 = '<a href="index.php?option=' . $option . '&task=checkin&id=' . $options['filename'] . '" title="' . JText::_('Force Checkin') . '" style="font-size:smaller">[' . JText::_('Checkin') . ']</a>';
                 $mainframe->enqueueMessage(sprintf(JText::_('checked out by'), $options['filename'], $username, $checkin));
                 $mainframe->redirect('index.php?option=' . $option . '&task=language_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'])) {
         $mainframe->enqueueMessage(sprintf(JText::_('Values Required'), implode(', ', $options['field_error_list'])));
         $options['task'] = 'language_edit';
     }
     // create a new file or save an existing file
     if ($options['task'] == 'apply_language' || $options['task'] == 'save_language') {
         // 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'] = 'language_edit';
         } 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_language') {
         Language_manager::multitask('checkin', $options['filename'], 'language_files', false);
     } else {
         Language_manager_html::Show_edit($editData, $editMeta, $options);
         if (!$options['newprocess']) {
             Language_manager::multitask('checkout', $options['filename'], false, false);
         }
     }
 }
示例#2
0
 /**
  * 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'] = '<input name="filter_search" id="filter_search" class="inputbox" "type="text" value="' . htmlspecialchars($options['filter_search'], ENT_QUOTES) . '" onchange="this.form.submit();" size="15" />';
     // 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&amp;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();
 }