/** * 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); } } }
/** * 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&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(); }