PageRenderTime 65ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/tmp/install_4fbc2968d8307/corePHP-community_acl-3e2dffd/administrator/components/com_community_acl/community_acl.language.php

https://github.com/viollarr/alab
PHP | 2000 lines | 1482 code | 179 blank | 339 comment | 329 complexity | 3f59f1157714452f7d964a0aace34020 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, AGPL-3.0, Apache-2.0, BSD-3-Clause, GPL-3.0
  1. <?php
  2. defined('_JEXEC') or die('Restricted access');
  3. class Language_manager extends JObject {
  4. /**
  5. * Build the filters for a view
  6. * @param array an associative array of allowed fields and values
  7. * @param string the namespace for this view
  8. * @return array The Configuration in an array
  9. */
  10. function _buildfilters( $allowed=array(), $namespace='' )
  11. {
  12. // initialise
  13. global $mainframe, $option;
  14. $filters = array();
  15. if ($namespace) {
  16. $namespace = trim($namespace,'.') . '.';
  17. } else {
  18. $namespace = $option.'.';
  19. }
  20. // get the limitstart for this namespace
  21. $filters['limitstart'] = $mainframe->getUserStateFromRequest( $namespace . 'limitstart', 'limitstart', 0 );
  22. // then validate all the filters for this namespace
  23. foreach ($allowed as $k=>$v) {
  24. // values are all changed to lower case
  25. $values = explode('|',$v);
  26. foreach ( $values as $k2=>$v2 ) {
  27. $values[$k2] = strtolower($v2);
  28. }
  29. // A: get the old/current value
  30. $old = $mainframe->getUserState( 'request.' . $namespace . $k );
  31. // B: get the new value from the user input
  32. $new = $mainframe->getUserStateFromRequest( $namespace . $k, $k, $values[0] );
  33. // C: check that the new (lowercase) value is valid
  34. if ($k=='limit') {
  35. $new = (is_numeric($new)) ? abs($new) : $values[0];
  36. } else if ( $v && array_search(strtolower($new),$values) === false ) {
  37. $new = $values[0];
  38. }
  39. // D: reset the page to #1 if the value has changed
  40. if ( $old != $new ) {
  41. $options['limitstart'] = 0;
  42. }
  43. // set the value
  44. $filters[$k] = $new;
  45. }
  46. // return
  47. return $filters;
  48. }
  49. /**
  50. * Get the configuration options.
  51. * @return array The Configuration in an array
  52. */
  53. function getOptions () {
  54. return Language_manager::_buildoptions();
  55. }
  56. /**
  57. * Build the configuration options.
  58. * @return array The Configuration in an array
  59. */
  60. function _buildoptions ()
  61. {
  62. // initialise configuration variables
  63. global $mainframe, $task, $option;
  64. //$task = strtolower($this->_task);
  65. $options['config'] = JComponentHelper::getParams( $option.'1' );
  66. $options['autoCorrect'] = $options['config']->get( 'autoCorrect', 'a^=ďż˝' );
  67. $options['backticks'] = $options['config']->get( 'backticks', 0 );
  68. $options['cid'] = JRequest::getVar( 'cid', array(''), '', 'array' );
  69. $options['client_lang'] = $mainframe->getUserStateFromRequest($option.'.client_lang','client_lang','');
  70. $options['globalChanges'] = $options['config']->get('globalChanges', 0 );
  71. $options['limitstart'] = $mainframe->getUserStateFromRequest($option.'.limitstart','limitstart','');
  72. $options['newprocess'] = JRequest::getVar('newprocess',0,'','integer' );
  73. $options['refLang'] = $options['config']->get( 'refLanguage', 'en-GB' );
  74. $options['refLangMissing'] = false;
  75. $options['searchStyle'] = $options['config']->get( 'searchStyle', 'background-color:yellow;' );
  76. $options['task'] = strtolower($task);
  77. // initialise a list of available languages
  78. $options['languages'] = array();
  79. $options['clients'] = array();
  80. $options['clients']['S'] = JText::_('Site');
  81. foreach (JLanguage::getKnownLanguages(JPATH_SITE) as $k=>$v) {
  82. $options['languages']['S_'.$k] = $options['clients']['S'] . ' - '.$v['name'];
  83. }
  84. $options['clients']['A'] = JText::_('Administrator');
  85. foreach (JLanguage::getKnownLanguages(JPATH_ADMINISTRATOR) as $k=>$v) {
  86. $options['languages']['A_'.$k] = $options['clients']['A'] . ' - '.$v['name'];
  87. }
  88. if (JFolder::exists(JPATH_INSTALLATION)) {
  89. $options['clients']['I'] = JText::_('Installation');
  90. foreach (JLanguage::getKnownLanguages(JPATH_INSTALLATION) as $k=>$v) {
  91. $options['languages']['I_'.$k] = $options['clients']['I'] . ' - '.$v['name'];
  92. }
  93. }
  94. // validate client_lang (split, reassemble with cases, check against allowed values, on failure default to first allowed value)
  95. $cl_split = preg_split("/[^a-z]/i",$options['client_lang']);
  96. if($options['client_lang'])
  97. $options['client_lang'] = strtoupper($cl_split[0]) . '_' . strtolower($cl_split[1]) . '-' . strtoupper($cl_split[2]);
  98. if (!isset($options['languages'][$options['client_lang']])) {
  99. $options['client_lang'] = key($options['languages']);
  100. }
  101. // set client variables
  102. $options['client'] = $options['client_lang']{0};
  103. if ($options['client']=='A') {
  104. $options['basePath'] = JPATH_ADMINISTRATOR;
  105. $options['clientKey'] = 'administrator';
  106. } else if ($options['client']=='I') {
  107. $options['basePath'] = JPATH_INSTALLATION;
  108. $options['clientKey'] = 'installation';
  109. } else {
  110. $options['basePath'] = JPATH_SITE;
  111. $options['clientKey'] = 'site';
  112. }
  113. $options['clientName'] = JText::_( $options['clientKey'] );
  114. // validate that the reference language exists on this client
  115. if (!isset($options['languages'][$options['client'].'_'.$options['refLang']])) {
  116. // initialise to en-GB
  117. $use = 'en-GB';
  118. // look for the first key index containing the reference language string
  119. foreach($options['languages'] as $k=>$v) {
  120. if ($k{0}==$options['client']) {
  121. $use = substr($k,-4);
  122. break;
  123. }
  124. }
  125. // set back to $options key
  126. $options['refLang'] = $use;
  127. }
  128. // set language variables
  129. $options['lang'] = substr($options['client_lang'],2);
  130. $options['langLen'] = strlen($options['lang']);
  131. $options['langName'] = $options['languages'][$options['client_lang']];
  132. $options['langPath'] = JLanguage::getLanguagePath( $options['basePath'], $options['lang'] );
  133. $options['refLangLen'] = strlen($options['refLang']);
  134. $options['refLangPath'] = JLanguage::getLanguagePath( $options['basePath'], $options['refLang'] );
  135. // set reference language variables
  136. $options['isReference'] = intval( $options['lang']==$options['refLang'] );
  137. // validate the cid array
  138. if ( !is_array( $options['cid'] )) {
  139. if (!empty($options['cid'])) $options['cid'] = array($options['cid']);
  140. else $options['cid'] = array('');
  141. }
  142. // process the cid array to validate filenames
  143. foreach($options['cid'] as $k=>$v ){
  144. if ($v) {
  145. // strip unpublished prefix
  146. if (substr($v,0,3)=='xx.') $v = substr($v,3);
  147. // strip files that don't match the selected language
  148. if (substr($v,0,$options['langLen'])!=$options['lang']) unset($options['cid'][$k]);
  149. // otherwise set back to $options
  150. else $options['cid'][$k] = $v;
  151. }
  152. }
  153. // set the filename
  154. $options['filename'] = $options['cid'][0];
  155. // build the autocorrect array
  156. $autoCorrect = array();
  157. if ($options['autoCorrect']) {
  158. foreach(explode(';',$options['autoCorrect']) as $v){
  159. list($k2,$v2)=explode('=',$v);
  160. $k2 = trim($k2);
  161. $v2 = trim($v2);
  162. if(($k2)&&($v2)) {
  163. $autoCorrect[$k2] = $v2;
  164. }
  165. }
  166. }
  167. $options['autoCorrect'] = $autoCorrect;
  168. // return the options array
  169. return $options;
  170. }
  171. /**
  172. * Processing File(s)
  173. * @param array $options The configuration array for the component
  174. * @param string $task a specific task (overrides $options)
  175. * @param mixed $file a specific filename or array of filenames to process (overrides $options)
  176. * @param string $redirect_task the task to use when redirecting (blank means no redirection)
  177. * @param boolean $report whether or not to report processing success/failure
  178. */
  179. function multitask( $task=null, $file=null, $redirect_task='language_files', $report=true )
  180. {
  181. global $option;
  182. // variables
  183. $options = Language_manager::getOptions();
  184. //$task = strtolower( is_null($task) ? $this->_task : $task );
  185. // validate the task
  186. if ($task=='cancel') {
  187. $task = 'checkin';
  188. $redirect_task = 'language_files';
  189. $report = false;
  190. }
  191. // validate the filename
  192. // 1: use a specific file or files
  193. // 2: use the client_lang
  194. // 3: check that we have at least one file
  195. if ($file) {
  196. $options['cid'] = (is_array($file)) ? $file : array($file);
  197. } else if ( (empty($options['cid'][0])) && ($task!='checkin') ) {
  198. echo "<script> alert('". JText::_('Please make a selection from the list to') . ' ' . JText::_(str_replace('xml','',$task)) ."'); window.history.go(-1);</script>\n";
  199. exit();
  200. }
  201. // initialise file classes
  202. jimport('joomla.filesystem.file');
  203. // initialise checkout file content
  204. if ($task=='checkout') {
  205. $user = & JFactory::getUser();
  206. $chk_file_content = time() . '#' . $user->get('id','0') . '#' . $user->get('name','[ Unknown User ]');
  207. }
  208. // initialise variables
  209. global $mainframe;
  210. $file_list = array();
  211. $nofile_list = array();
  212. $inifile_list = array();
  213. $last = '';
  214. // process each passed file name (always the 'real' filename)
  215. foreach ($options['cid'] as $file) {
  216. // validate the filename language prefix
  217. if ( preg_match('/^[a-z]{2,3}-[A-Z]{2}[.].*/',$file) ) {
  218. // get the language and language path
  219. $lang = substr($file,0,$options['langLen']);
  220. $langPath = JLanguage::getLanguagePath( $options['basePath'], $lang );
  221. // ensure that XML files are only affected by XML tasks
  222. if ( (substr($file,-4)=='.xml') && (substr($task,-3)!='xml') ) {
  223. // continue without error warning
  224. continue;
  225. }
  226. // get file path-names
  227. $chk_file = 'chk.'.$file;
  228. $pub_file = $file;
  229. $unpub_file = 'xx.'.$file;
  230. // check for an unpublished file
  231. if (JFile::exists($langPath.DS.$unpub_file)) {
  232. $file = $unpub_file;
  233. }
  234. // check the file exists
  235. else if (!JFile::exists($langPath.DS.$file)) {
  236. // error and continue
  237. $nofile_list[$file] = $file;
  238. continue;
  239. }
  240. // cancel/checkin a file
  241. // checkout a file
  242. // delete a file
  243. // delete an XML file
  244. // publish a file
  245. // unpublish a file
  246. // otherwise break because the task isn't recognised
  247. if ( ($task=='checkin') && (JFile::exists($langPath.DS.$chk_file)) ) {
  248. $do = JFile::delete( $langPath.DS.$chk_file );
  249. } else if ($task=='checkout') {
  250. $do = Jfile::write( $langPath.DS.$chk_file, $chk_file_content );
  251. } else if ($task=='remove') {
  252. $do = JFile::delete( $langPath.DS.$file );
  253. } else if ($task=='publish') {
  254. $do = JFile::move( $file, $pub_file, $langPath );
  255. } else if ($task=='unpublish') {
  256. $do = JFile::move( $file, $unpub_file, $langPath );
  257. } else {
  258. break;
  259. }
  260. // build an array of things to hide form the filename
  261. $filename_hide = array();
  262. // add the function to the file list on success
  263. if ($do) {
  264. $file_list[$file] = str_replace( 'xx.'.$lang, $lang,substr($file,0,-4) );
  265. }
  266. }
  267. }
  268. if ($report) {
  269. // report processing success
  270. if (count($file_list)) {
  271. $mainframe->enqueueMessage(sprintf(JText::_($task.' success'), count($file_list), implode(', ',$file_list) ) );
  272. }
  273. // report existing ini files
  274. if (count($inifile_list)) {
  275. $mainframe->enqueueMessage(sprintf(JText::_($task.' inifile'), count($inifile_list), implode(', ',$inifile_list) ) );
  276. }
  277. }
  278. // redirect
  279. if ($redirect_task) {
  280. $mainframe->redirect( 'index.php?option='.$option.'&client_lang='.$options['client_lang'].'&task='.$redirect_task );
  281. }
  282. }
  283. function list_languages() {
  284. // variables
  285. global $mainframe, $option;
  286. $options = Language_manager::getOptions();
  287. // default languages
  288. $params = JComponentHelper::getParams('com_languages');
  289. $default['A'] = $params->get('administrator','en-GB');
  290. $default['I'] = $params->get('installation','en-GB');
  291. $default['S'] = $params->get('site','en-GB');
  292. // validate all the filters (specific to this view)
  293. // each filter key has a list of allowed values; the first is the default value
  294. // a blank value skips validation
  295. // the key "limit" allows any integer
  296. $allowed = array(
  297. 'filter_client' => '*|' . implode( '|', array_keys($options['clients']) ),
  298. 'filter_order' => 'tag',
  299. 'filter_order_Dir' => 'asc|desc',
  300. 'limit' => $mainframe->getCfg('list_limit')
  301. );
  302. $filters = Language_manager::_buildfilters( $allowed, $option.'.languages.' );
  303. // copy to $options
  304. $options = array_merge( $options, $filters );
  305. // copy to $lists
  306. $lists['order'] = $options['filter_order'];
  307. $lists['order_Dir'] = $options['filter_order_Dir'];
  308. // get the list of languages
  309. $rows = array();
  310. foreach ($options['languages'] as $k=>$v) {
  311. $row = new StdClass();
  312. $row->tag = substr($k,2);
  313. $row->client = strtoupper($k{0});
  314. $row->client_lang = $k;
  315. $row->filename = $row->tag . '.xml';
  316. // check filter
  317. if ($options['filter_client']!='*') {
  318. if ($row->client != $options['filter_client']) {
  319. continue;
  320. }
  321. }
  322. // check default status
  323. $row->isdefault = intval( $default[$row->client]==$row->tag );
  324. // get the directory path
  325. if ($k{0}=='A') {
  326. $path = JPATH_ADMINISTRATOR;
  327. $row->client_name = JText::_('Administrator');
  328. } else if ($k{0}=='I') {
  329. $path = JPATH_INSTALLATION;
  330. $row->client_name = JText::_('Installation');
  331. } else {
  332. $path = JPATH_SITE;
  333. $row->client_name = JText::_('Site');
  334. }
  335. $path .= DS.'language'.DS.$row->tag;
  336. // count the number of INI files (published or unpublished)
  337. //echo '(xx[.]|^)'.$row->tag.'.*ini$';die;
  338. $opt_name = substr($option, 4);
  339. $row->files = count( JFolder::files( $path, '(xx[.]|^)'.$row->tag.'.*'.$opt_name.'.*ini$' ) );
  340. // load and add XML attributes
  341. // force the tag
  342. $data = TranslationsHelper::getXMLMeta($path.DS.$row->filename);
  343. $data['tag'] = $row->tag;
  344. foreach($data as $k2=>$v2) {
  345. $row->$k2 = $v2;
  346. }
  347. // add to rows
  348. $rows[] = $row;
  349. }
  350. // build the pagination
  351. jimport('joomla.html.pagination');
  352. $pageNav = new JPagination( count($rows), $options['limitstart'], $options['limit'], 'index.php?option='.$option.'&task=language' );
  353. // sort the $rows array
  354. $order_Int = (strtolower($lists['order_Dir'])=='desc') ? -1 : 1;
  355. JArrayHelper::sortObjects( $rows, $lists['order'], $order_Int );
  356. // slice the array so we only show one page
  357. $rows = array_slice( $rows, $pageNav->limitstart, $pageNav->limit );
  358. // call the html view
  359. Language_manager_html::Show_languages($rows, $options, $lists, $pageNav);
  360. }
  361. function list_files()
  362. {
  363. global $option;
  364. // filesystem functions
  365. jimport('joomla.filesystem.folder');
  366. jimport('joomla.filesystem.file');
  367. // variables
  368. global $mainframe;
  369. $options = Language_manager::getOptions();
  370. $user = &JFactory::getUser();
  371. $userid = $user->get('id',0);
  372. // build client_lang select box
  373. foreach ($options['languages'] as $k=>$v) {
  374. $sel_lang[] = JHTML::_( 'select.option', $k, $v );
  375. }
  376. $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'] );
  377. // validate all the filters (specific to this view)
  378. $allowed = array(
  379. 'client_lang' => '',
  380. 'filter_search' => '',
  381. 'filter_state' => '*|U|P',
  382. 'filter_status' => '*|NS|IP|C',
  383. 'filter_order' => 'name|status|strings|version|datetime|author',
  384. 'filter_order_Dir' => 'asc|desc',
  385. 'limit' => $mainframe->getCfg('list_limit')
  386. );
  387. $filters = Language_manager::_buildfilters( $allowed, $option.'.files.' );
  388. // copy to $options
  389. $options = array_merge( $options, $filters );
  390. // copy to $lists
  391. $lists['order'] = $options['filter_order'];
  392. $lists['order_Dir'] = $options['filter_order_Dir'];
  393. // validate and build the filter_search box
  394. $options['dosearch'] = '';
  395. if ($options['filter_search']) {
  396. // 1: turn it into a case-insensitive regexp
  397. // 2: check and use a submitted regexp
  398. // 3: invalid regexp
  399. if ($options['filter_search']{0}!='/') {
  400. $options['dosearch'] = '/.*'.trim($options['filter_search'],'/').'.*/i';
  401. } else if ( @preg_match($options['filter_search'],'') !== false ) {
  402. $options['dosearch'] = $options['filter_search'];
  403. } else {
  404. $mainframe->enqueueMessage( JText::_('Search') . ': ' . sprintf( JText::_('Invalid RegExp'), htmlentities($options['filter_search']) ), 'error' );
  405. $options['filter_search'] = '';
  406. }
  407. }
  408. $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" />';
  409. // build the filter_state select box
  410. $extra = 'class="inputbox" size="1" onchange="document.adminForm.submit();"';
  411. $sel_state[] = JHTML::_( 'select.option', '*', JText::_( 'Any State' ) );
  412. $sel_state[] = JHTML::_( 'select.option', 'P', JText::_( 'Published' ) );
  413. $sel_state[] = JHTML::_( 'select.option', 'U', JText::_( 'Not Published' ) );
  414. $lists['state'] = JHTML::_( 'select.genericlist', $sel_state, 'filter_state', $extra, 'value', 'text', $options['filter_state'] );
  415. // build the filter_status select box
  416. $sel_status[] = JHTML::_( 'select.option', '*', JText::_( 'Any Status' ) );
  417. $sel_status[] = JHTML::_( 'select.option', 'NS', JText::_( 'Not Started' ) );
  418. $sel_status[] = JHTML::_( 'select.option', 'IP', JText::_( 'In Progress' ) );
  419. $sel_status[] = JHTML::_( 'select.option', 'C', JText::_( 'Complete' ) );
  420. if ($options['isReference']) {
  421. $options['filter_status'] = '*';
  422. }
  423. if ($options['lang'] == $options['refLang']) {
  424. $extra .= ' disabled';
  425. }
  426. $lists['status'] = JHTML::_( 'select.genericlist', $sel_status, 'filter_status', $extra, 'value', 'text', $options['filter_status'] );
  427. // create objects for loading data
  428. $refLangLoader = new JLanguage( $options['refLang'] );
  429. $LangLoader = ( $options['lang'] == $options['refLang'] ) ? $refLangLoader : new JLanguage( $options['lang'] );
  430. // load all the the ini filenames (published or unpublished) from the reference directory
  431. // load the same from the selected language directory
  432. $opt_name = substr($option, 4);
  433. $refLangFiles = JFolder::files( $options['refLangPath'] , '^(xx|'.$options['refLang'].')[.].*'.$opt_name.'[.].*ini$' );
  434. if ($options['isReference']) {
  435. $LangFiles = array_flip( $refLangFiles );
  436. } else {
  437. $LangFiles = JFolder::files( $options['langPath'] , '^(xx|'.$options['lang'].')[.].*'.$opt_name.'[.].*ini$' );
  438. $LangFiles = array_flip( $LangFiles );
  439. }
  440. // build a composite filename list, keyed using the filename without language tag
  441. $allFiles = array();
  442. foreach ( $refLangFiles as $v ) {
  443. $k = preg_replace('/^(xx[.])*'.$options['refLang'].'[.]/','',$v);
  444. $allFiles[$k]['refLang'] = $v;
  445. }
  446. foreach ( $LangFiles as $v=>$k ) {
  447. $k = preg_replace('/^(xx[.])*'.$options['lang'].'[.]/','',$v);
  448. $allFiles[$k]['lang'] = $v;
  449. }
  450. // get default metadata for the selected language
  451. $xmlData = TranslationsHelper::getXMLMeta( $options['langPath'].DS.$options['lang'].'.xml' );
  452. // process the reference language INI files and compare them against the files for the selected language
  453. $rows = array ();
  454. $rowid = 1;
  455. foreach ($allFiles as $k=>$v) {
  456. // get the content, bare filename, Meta and Strings from the reference language INI file
  457. // in some cases there may not be a reference language INI file
  458. if (isset($v['refLang'])) {
  459. $refContent = file( $options['refLangPath'].DS.$v['refLang'] );
  460. $refFileName = ( substr($v['refLang'],0,3)=='xx.' ) ? substr($v['refLang'],3) : $v['refLang'];
  461. $fileName = $options['lang'] . substr($refFileName,$options['refLangLen']);
  462. $refStrings = array();
  463. $refMeta = TranslationsHelper::getINIMeta( $refContent, $refStrings );
  464. } else {
  465. $refContent = array();
  466. $fileName = ( substr($v['lang'],0,3)=='xx.' ) ? substr($v['lang'],3) : $v['lang'];
  467. $refFileName = $options['refLang'] . substr($fileName,$options['langLen']);
  468. $refStrings = array();
  469. $refMeta = array(
  470. 'author' => '',
  471. 'date' => '',
  472. 'strings' => '',
  473. 'time' => '',
  474. 'version' => ''
  475. );
  476. }
  477. // initialise the row
  478. $row = new StdClass();
  479. $row->author = $refMeta['author'];
  480. $row->bom = 'UTF-8';
  481. $row->checkedout = 0;
  482. $row->changed = 0;
  483. $row->date = $refMeta['date'];
  484. $row->extra = 0;
  485. $row->filename = $fileName;
  486. $row->id = $rowid++;
  487. $row->name = substr($row->filename,($options['langLen']+1),-4);
  488. $row->refexists = intval( isset($v['refLang']) );
  489. $row->reffilename = $refFileName;
  490. $row->refstrings = $refMeta['strings'];
  491. $row->searchfound = 0;
  492. $row->status = 0;
  493. $row->strings = $refMeta['strings'];
  494. $row->time = $refMeta['time'];
  495. $row->unchanged = 0;
  496. $row->unpub_filename = 'xx.'.$row->filename;
  497. $row->version = $refMeta['version'];
  498. // 1: file is published
  499. // 2: file is unpublished
  500. // 3: file does not exist
  501. if ( JFile::exists($options['langPath'].DS.$row->filename) ) {
  502. $row->exists = 1;
  503. $row->path_file = $options['langPath'].DS.$row->filename;
  504. $row->published = 1;
  505. $row->writable = is_writable($row->path_file);
  506. } else if ( JFile::exists($options['langPath'].DS.$row->unpub_filename) ) {
  507. $row->exists = 1;
  508. $row->path_file = $options['langPath'].DS.$row->unpub_filename;
  509. $row->published = 0;
  510. $row->writable = is_writable($row->path_file);
  511. } else {
  512. $row->author = '';
  513. $row->date = '';
  514. $row->exists = 0;
  515. $row->path_file = $options['langPath'].DS.$row->unpub_filename;
  516. $row->published = 0;
  517. $row->status = 0;
  518. $row->version = '';
  519. $row->writable = 1;
  520. }
  521. // get the checkout status of the selected file
  522. if ( $content = @file_get_contents($options['langPath'].DS.'chk.'.$row->filename)) {
  523. $row->checkedout = ( (strpos($content,'#'.$userid.'#')) || (strpos($content,'#0#')) ) ? 0 : 1;
  524. }
  525. // scan an existing language file
  526. if ( (!$options['isReference']) && ($row->exists) ) {
  527. $fileContent = file($row->path_file);
  528. $fileStrings = array();
  529. $fileMeta = TranslationsHelper::getINIMeta( $fileContent, $fileStrings, $refStrings );
  530. if ( $fileMeta['bom'] == 'UTF-8' ) {
  531. foreach ($fileMeta as $k=>$v) {
  532. $row->{$k} = $v;
  533. }
  534. } else {
  535. $row->bom = $fileMeta['bom'];
  536. $row->writable = 0;
  537. }
  538. } else {
  539. $fileContent = array();
  540. $fileStrings = array();
  541. $fileMeta = array();
  542. }
  543. // search the files
  544. // $refContent and $fileContent are arrays containing each line of the reference and translation file
  545. if ( $options['dosearch'] ) {
  546. $row->searchfound_ref = preg_match_all($options['dosearch'], implode("\n",$refContent), $arr );
  547. if (! $options['isReference'] ) {
  548. $row->searchfound_tran = preg_match_all($options['dosearch'], implode("\n",$fileContent), $arr );
  549. } else {
  550. $row->searchfound_tran = $row->searchfound_ref;
  551. }
  552. $row->searchfound = $row->searchfound_ref + $row->searchfound_tran;
  553. }
  554. // set the datetime
  555. $row->datetime = $row->date.$row->time;
  556. // change the name
  557. if ($row->name == '') {
  558. $row->name = ' [core]';
  559. }
  560. // store the file
  561. $rows[$row->name] = $row;
  562. }
  563. // build the fileset totals and filter out rows we don't need/want
  564. $options['fileset-files'] = 0;
  565. $options['fileset-exists'] = 0;
  566. $options['fileset-published'] = 0;
  567. $options['fileset-refstrings'] = 0;
  568. $options['fileset-changed'] = 0;
  569. foreach( $rows as $k=>$row) {
  570. // add to totals
  571. $options['fileset-files']++;
  572. $options['fileset-exists'] += $row->exists;
  573. $options['fileset-published'] += $row->published;
  574. $options['fileset-refstrings'] += $row->refstrings;
  575. $options['fileset-changed'] += $row->changed;
  576. // filter out searched items
  577. // filter out published or unpublished items
  578. // filter out status of items
  579. if (
  580. ( ($options['dosearch']) && ($row->searchfound == 0) )
  581. || ( ($options['filter_state']=='P') && ($row->published <> 1) )
  582. || ( ($options['filter_state']=='U') && ($row->published <> 0) )
  583. || ( ($options['filter_status']=='NS') && ($row->status > 0) )
  584. || ( ($options['filter_status']=='IP') && (($row->status <= 0)||($row->status >= 100)) )
  585. || ( ($options['filter_status']=='C') && ($row->status < 100) )
  586. ) {
  587. unset($rows[$k]);
  588. }
  589. }
  590. // set fileset status
  591. if ($options['fileset-changed'] == 0) {
  592. $options['fileset-status'] = 0;
  593. }
  594. if ($options['fileset-refstrings'] == $options['fileset-changed']) {
  595. $options['fileset-status'] = 100;
  596. } else {
  597. $options['fileset-status'] = floor( ($options['fileset-changed']/$options['fileset-refstrings'])*100 );
  598. }
  599. // build the pagination
  600. jimport('joomla.html.pagination');
  601. $pageNav = new JPagination( count($rows), $options['limitstart'], $options['limit'], 'index.php?option='.$option.'&amp;task=language_files' );
  602. // sort the $rows array
  603. $order_Int = (strtolower($lists['order_Dir'])=='desc') ? -1 : 1;
  604. JArrayHelper::sortObjects( $rows, $lists['order'], $order_Int );
  605. // slice the array so we only show one page
  606. $rows = array_slice( $rows, $pageNav->limitstart, $pageNav->limit );
  607. // call the html view
  608. Language_manager_html::Show_files($rows, $options, $lists, $pageNav);
  609. }
  610. /**
  611. * Create Edit or Save a Translation File
  612. */
  613. function edit_language()
  614. {
  615. global $option;
  616. // import file functions
  617. jimport('joomla.filesystem.file');
  618. // variables
  619. global $mainframe;
  620. $options = Language_manager::getOptions();
  621. $options['newprocess'] = 0;
  622. // build the search highlight array
  623. $options['filter_search'] = $mainframe->getUserStateFromRequest( $option.'.files.filter_search', 'filter_search', '' );
  624. // 2: otherwise verify that we have a filename
  625. // 3: otherwise validate the checkout status of the selected file
  626. if (empty($options['filename'])) {
  627. $mainframe->enqueueMessage( JText::_('You must select a file to edit') );
  628. $mainframe->redirect( 'index.php?option='.$option.'&task=language_files' );
  629. } else if ( $content = @file_get_contents($options['langPath'].DS.'chk.'.$options['filename'])) {
  630. list ($timestamp,$userid,$username) = explode( '#', $content.'##' );
  631. $user = & JFactory::getUser();
  632. // validate the checkout
  633. if (
  634. ( (time()-$timestamp) < 3600 )
  635. && ( $userid <> 0 )
  636. && ( $userid <> $user->get('id','0') )
  637. ) {
  638. // report and redirect
  639. $checkin = '<a href="index.php?option='.$option.'&task=checkin&id='.$options['filename'].'" title="'. JText::_( 'Force Checkin' ) . '" style="font-size:smaller">[' . JText::_( 'Checkin' ) . ']</a>';
  640. $mainframe->enqueueMessage(sprintf(JText::_('checked out by'), $options['filename'], $username, $checkin ) );
  641. $mainframe->redirect( 'index.php?option='.$option.'&task=language_files' );
  642. }
  643. }
  644. // set the reference language filename from the selected filename
  645. $options['refFilename'] = str_replace($options['lang'],$options['refLang'],$options['filename']);
  646. // find the published reference language file
  647. // default to an unpublished reference file
  648. if ( JFile::exists($options['refLangPath'].DS.$options['refFilename']) ) {
  649. $options['ref_path_file'] = $options['refLangPath'].DS.$options['refFilename'];
  650. } else {
  651. $options['ref_path_file'] = $options['refLangPath'].DS.'xx.'.$options['refFilename'];
  652. }
  653. // find the published selected language file
  654. // default to an unpublished new file
  655. if ( JFile::exists($options['langPath'].DS.$options['filename']) ) {
  656. $options['path_file'] = $options['langPath'].DS.$options['filename'];
  657. } else {
  658. $options['path_file'] = $options['langPath'].DS.'xx.'.$options['filename'];
  659. }
  660. // STRINGS: initialise $editData from the reference language file contents
  661. // $editData is an analogue of the reference file
  662. // header lines are skipped
  663. // comments and blank lines are strings with an integer index
  664. // key=value pairs are arrays with the key as an index
  665. $editData = array();
  666. $header = 0;
  667. $refStrings = array();
  668. if ( $refContent = @file($options['ref_path_file']) ) {
  669. foreach ($refContent as $k=>$v) {
  670. $v = trim($v);
  671. // grab the comments (but skip up to 6 lines before we have any strings in the file)
  672. // grab the strings
  673. if ( (empty($v))||($v{0}=='#')||($v{0}==';') ) {
  674. if($header++>6) $editData[$k] = $v;
  675. } else if(strpos($v,'=')) {
  676. $header = 7;
  677. list($key,$value) = explode('=',$v,2);
  678. $key = strtoupper($key);
  679. $refStrings[$key] = $value;
  680. $editData[$key] = array('ref'=>$value,'edit'=>$value);
  681. if ($options['isReference']) {
  682. $editData[$key]['lang_file'] = $value;
  683. }
  684. }
  685. }
  686. }
  687. // STRINGS: load the selected file contents and process into $editData
  688. // only when the selected language is not the same as the reference language
  689. if ($options['isReference']) {
  690. $fileContent = $refContent;
  691. $fileStrings = array();
  692. $fileMeta = TranslationsHelper::getINIMeta( $fileContent, $fileStrings );
  693. $editStrings = $fileStrings;
  694. } else if ( $fileContent = @file($options['path_file']) ) {
  695. $fileStrings = array();
  696. $fileMeta = TranslationsHelper::getINIMeta( $fileContent, $fileStrings );
  697. $editStrings = $fileStrings;
  698. foreach ( $fileStrings as $k=>$v ) {
  699. $editData[$k]['edit'] = $v;
  700. $editData[$k]['lang_file'] = $v;
  701. }
  702. } else {
  703. $fileContent = array();
  704. $fileStrings = array();
  705. $fileMeta = array( 'headertype'=>1, 'owner'=>'ff', 'complete'=>0 );
  706. $editStrings = array();
  707. }
  708. // STRINGS: load the user form contents and process into $editData
  709. $editFormOnly = array();
  710. if ($FormKeys = JRequest::getVar( 'ffKeys', array(), '', 'ARRAY', JREQUEST_ALLOWRAW )) {
  711. $FormValues = JRequest::getVar( 'ffValues', array(), '', 'ARRAY', JREQUEST_ALLOWRAW );
  712. // process each key=value pair from the form into $editData
  713. foreach ($FormKeys as $k=>$v) {
  714. if ( ($v) && (isset($FormValues[$k])) ) {
  715. $key = strtoupper(trim(stripslashes($v)));
  716. $value = trim(stripslashes(str_replace('\n',"\n",$FormValues[$k])));
  717. $editStrings[$key] = $value;
  718. $editData[$key]['edit'] = $value;
  719. $editData[$key]['user_form'] = $value;
  720. }
  721. }
  722. // every element of $editData must have a form entry
  723. foreach($editData as $k=>$v){
  724. if ( is_array($v) && !isset($v['user_form']) ) {
  725. unset($editStrings[$k]);
  726. unset($editData[$k]);
  727. }
  728. }
  729. }
  730. // META: get the XML and status meta then initialise
  731. $options['XMLmeta'] = TranslationsHelper::getXMLMeta($options['langPath'].DS.$options['lang'].'.xml');
  732. $statusMeta = TranslationsHelper::getINIstatus( $refStrings, $editStrings );
  733. $editMeta = array_merge( $options['XMLmeta'], $fileMeta, $statusMeta );
  734. $editMeta['filename'] = $options['filename'];
  735. // META: apply any user form values
  736. foreach($editMeta as $k=>$v) {
  737. $editMeta[$k] = JRequest::getVar($k,$v,'','string');
  738. }
  739. // META: require meta values
  740. foreach(array('version','author') as $v) {
  741. if(empty($editMeta[$v])) {
  742. $options['field_error_list'][$v] = JText::_($v);
  743. }
  744. }
  745. // ERRORS: report any errors and change the task
  746. if ((!empty($options['field_error_list']))) {
  747. $mainframe->enqueueMessage( sprintf( JText::_('Values Required'), implode(', ',$options['field_error_list']) ) );
  748. $options['task'] = 'language_edit';
  749. }
  750. // create a new file or save an existing file
  751. if (($options['task']=='apply_language')||($options['task']=='save_language')) {
  752. // ensure the file does not already exist when we are creating a new file
  753. if ( ($options['newprocess'])&&(JFile::exists($options['path_file'])) ) {
  754. // report error and set task flag
  755. $mainframe->enqueueMessage( sprintf(JText::_('Language INI Exists'),$options['newfilename']) );
  756. $options['task'] = 'language_edit';
  757. }
  758. // otherwise save the file
  759. else {
  760. // check the complete status
  761. // we set the complete value to the number of strings that are 'unchanged'
  762. // so that if the reference INI file should change the 'complete' flag is unset/broken
  763. $editMeta['complete'] = JRequest::getVar( 'complete', '', 'post', 'string' );
  764. $editMeta['complete'] = ( $editMeta['complete'] == 'COMPLETE' ) ? $editMeta['unchanged'] : 0;
  765. // build the header
  766. if ($editMeta['headertype']==1) {
  767. $saveContent = '# $Id: ' . $options['filename'] . ' ' . $editMeta['version'] . ' ' . date('Y-m-d H:i:s') . ' ' . $editMeta['owner'] . ' ~' . $editMeta['complete'] . ' $';
  768. } else {
  769. $saveContent = '# version ' . $editMeta['version'] . ' ' . date('Y-m-d H:i:s') . ' ~' . $editMeta['complete'];
  770. }
  771. $saveContent .= "\n" . '# author ' . $editMeta['author'];
  772. $saveContent .= "\n" . '# copyright ' . $editMeta['copyright'];
  773. $saveContent .= "\n" . '# license ' . $editMeta['license'];
  774. $saveContent .= "\n\n" . '# Note : All ini files need to be saved as UTF-8';
  775. $saveContent .= "\n\n";
  776. // process the $editData array to get the remaining content
  777. $changedStrings = array();
  778. $header = 0;
  779. foreach ($editData as $k=>$v) {
  780. // 1: add a blank line or comment
  781. // 2: add a key=value line (no need to addslashes on quote marks)
  782. if (!is_array($v)) {
  783. $saveContent .= $v . "\n";
  784. } else {
  785. // change newlines in the value
  786. $value = preg_replace( '/(\r\n)|(\n\r)|(\n)/', '\n', $v['edit'] );
  787. // change single-quotes or backticks in the value
  788. if ($options['backticks']>0) {
  789. $value = strtr( $value, "'", '`' );
  790. } else if ($options['backticks']<0) {
  791. $value = strtr( $value, '`', "'" );
  792. }
  793. // set back to $editData
  794. $editData[$k]['edit'] = $value;
  795. // add to file content
  796. $saveContent .= $k . '=' . $value . "\n";
  797. // if the string is in the selected language file
  798. if (isset($v['lang_file'])) {
  799. // and it has changed (via the user form)
  800. if ($v['lang_file'] != $v['edit']) {
  801. // log the change in a translation array
  802. $changedStrings[ "\n".$k.'='.$v['lang_file'] ] = "\n".$k.'='.$v['edit'];
  803. }
  804. }
  805. }
  806. }
  807. // if there is no reference Language File, automatically initialise/create one which is the same as the selected language file
  808. if ($options['refLangMissing']) {
  809. if ( JFile::write( $options['refLangPath'].DS.$options['refLangFile'], trim($saveContent) ) ) {
  810. $mainframe->enqueueMessage(sprintf(JText::_('Language INI Created'), $options['refLangFile'] ) );
  811. }
  812. }
  813. // 1: write the selected language file and clear newprocess flag
  814. // 2: report failure
  815. if ( JFile::write( $options['path_file'], trim($saveContent) ) ) {
  816. $mainframe->enqueueMessage(sprintf(JText::_('Language INI '.(($options['newprocess'])?'Created':'Saved') ),$options['clientName'],$options['filename'] ) );
  817. $options['newprocess'] = 0;
  818. } else {
  819. $mainframe->enqueueMessage( sprintf(JText::_('Could not write to file'),$options['path_file']) );
  820. }
  821. // process changed strings globally across all the the ini files from the selected language directory
  822. if ( (count($changedStrings)) && ($options['globalChanges']) ) {
  823. $write = 0;
  824. $writeFiles = array();
  825. if ($files = JFolder::files($options['langPath'])) {
  826. foreach ($files as $file) {
  827. // skip non-INI files
  828. // skip this file
  829. // skip this file (unpublished)
  830. // skip checked out files
  831. if (
  832. (strtolower(substr($file,-4)!='.ini'))
  833. || ($file==$options['filename'])
  834. || ($file=='xx.'.$options['filename'])
  835. || (array_search($options['langPath'].DS.'chk.'.$file,$files))
  836. ) {
  837. continue;
  838. }
  839. // otherwise grab the file content
  840. if ($content = file_get_contents($options['langPath'].DS.$file)) {
  841. // parse the changed strings
  842. $new_content = strtr( $content, $changedStrings );
  843. // check for changes then write to the file
  844. if ($new_content != $content) {
  845. if ( JFile::write( $options['langPath'].DS.$file, trim($new_content) ) ) {
  846. $writeFiles[$write++] = $file;
  847. }
  848. }
  849. }
  850. }
  851. }
  852. // report
  853. if ($write) {
  854. $mainframe->enqueueMessage( sprintf(JText::_('Global String Change'), $write, implode('; ',$writeFiles) ) );
  855. }
  856. }
  857. }
  858. }
  859. // 1: checkin when we are saving (this will redirect also)
  860. // 2: call the html when we are editing or applying (and checkout existing files)
  861. if ($options['task'] == 'save_language') {
  862. Language_manager::multitask( 'checkin', $options['filename'], 'language_files', false );
  863. } else {
  864. Language_manager_html::Show_edit($editData, $editMeta, $options);
  865. if (!$options['newprocess']) {
  866. Language_manager::multitask( 'checkout', $options['filename'], false, false );
  867. }
  868. }
  869. }
  870. }
  871. class Language_manager_html {
  872. function Show_languages($data, $options, $lists, $pagenav) {
  873. global $option;
  874. // TOOLBAR
  875. JToolbarHelper::title( JText::_( 'Language Manager' ), 'langmanager.png' );
  876. JToolbarHelper::custom('language_files','edit','','View Files');
  877. ?>
  878. <div>
  879. <form action="index.php" method="post" name="adminForm">
  880. <input type="hidden" name="<?php echo JUtility::getToken(); ?>" value="1" />
  881. <input type="hidden" name="option" value="<?php echo $option;?>" />
  882. <input type="hidden" name="task" value="language" />
  883. <input type="hidden" name="boxchecked" value="1" />
  884. <input type="hidden" name="filter_order" value="<?php echo $lists['order']; ?>" />
  885. <input type="hidden" name="filter_order_Dir" value="<?php echo $lists['order_Dir']; ?>" />
  886. <table class="adminlist" id="languages">
  887. <thead>
  888. <tr>
  889. <th width="20">&nbsp;</th>
  890. <th width="15%"><?php echo JText::_( 'Client' ); ?></th>
  891. <th width="20%"><?php echo JHTML::_( 'grid.sort', 'Language', 'tag', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  892. <th width="5%"><?php echo JText::_( 'Default' ); ?></th>
  893. <th width="5%"><?php echo JText::_( 'Files' ); ?></th>
  894. <th width="5%"><?php echo JText::_( 'Version' ); ?></th>
  895. <th width="60"><?php echo JText::_( 'Date' ); ?></th>
  896. <th width="20%"><?php echo JText::_( 'Author' ); ?></th>
  897. </tr>
  898. </thead>
  899. <tfoot>
  900. <td width="100%" colspan="9"><?php echo $pagenav->getListFooter(); ?></td>
  901. </tfoot>
  902. <tbody>
  903. <?php
  904. // process the rows (each is an XML language file)
  905. $k = 0;
  906. for ($i=0, $n=count( $data ); $i < $n; $i++) {
  907. $row =& $data[$i];
  908. ?>
  909. <tr class="row<?php echo $i; ?>">
  910. <td width="20">
  911. <?php echo '<input type="radio" name="client_lang" value="' . $row->client_lang . '" ' . ( ($row->client_lang==$options['client_lang']) ? 'checked ' : '' ); ?> />
  912. </td>
  913. <td width="15%">
  914. <b><?php echo $row->client_name ;?></b>
  915. </td>
  916. <td width="25%">
  917. <?php echo Language_manager_html::getTooltip( '['.$row->tag.'] &nbsp; '.$row->name, $row->description, $row->name, '' ); ?>
  918. </td>
  919. <td align="center">
  920. <?php echo ($row->isdefault) ? '<img src="templates/khepri/images/menu/icon-16-default.png" alt="'.JText::_('Default').'" />' : '&nbsp;'; ?>
  921. </td>
  922. <td align="center">
  923. <?php echo '<a href="index.php?option='.$option.'&amp;task=language_files&amp;client_lang=' . $row->client_lang .'">' . Language_manager_html::getTooltip( $row->files, null, 'View Files', 'TC' ) . '</a>'; ?>
  924. </td>
  925. <td align="center">
  926. <?php echo $row->version; ?>
  927. </td>
  928. <td align="center">
  929. <?php echo $row->creationDate; ?>
  930. </td>
  931. <td align="center">
  932. <?php echo $row->author; ?>
  933. </td>
  934. </tr>
  935. <?php
  936. }
  937. ?>
  938. </tbody>
  939. </table>
  940. </form>
  941. </div>
  942. <?php
  943. }
  944. function Show_files($data, $options, $lists, $pagenav) {
  945. global $option;
  946. // TOOLBAR
  947. $langName = ' <small><small> : ' . $options['langName'] . '</small></small>';
  948. JToolbarHelper::title( JText::_( 'Language Files' ) . $langName, 'langmanager.png' );
  949. JToolbarHelper::custom('language','upload.png','upload_f2.png','Languages',false);
  950. JToolbarHelper::divider();
  951. JToolbarHelper::unpublishList('language_unpublish');
  952. JToolbarHelper::publishList('language_publish');
  953. JToolbarHelper::deleteList(JText::_('Confirm Delete INI'), 'remove_language');
  954. JToolbarHelper::editList('edit_language');
  955. ?>
  956. <div >
  957. <form action="index.php" method="post" name="adminForm">
  958. <input type="hidden" name="<?php echo JUtility::getToken(); ?>" value="1" />
  959. <input type="hidden" name="option" value="<?php echo $option;?>" />
  960. <input type="hidden" name="task" value="language_files" />
  961. <input type="hidden" name="boxchecked" value="0" />
  962. <input type="hidden" name="filter_order" value="<?php echo $lists['order']; ?>" />
  963. <input type="hidden" name="filter_order_Dir" value="<?php echo $lists['order_Dir']; ?>" />
  964. <table width="100%">
  965. <tr>
  966. <td><b><?php echo JText::_( 'Language' ); ?>:</b></td>
  967. <td><?php echo $lists['client_lang']; ?></td>
  968. <?php
  969. if (!$options['isReference']) {
  970. echo '<td align="left"><div style="border:solid silver 1px;background:white;width:100px;height:8px;"><div style="height:100%; width:' . $options['fileset-status'] . 'px;background:green;"></div></div></td><td><b>'. $options['fileset-status'] .'%&nbsp;</b></td>';
  971. echo '<td width="100%" align="left"><div style="font-size:smaller">'. sprintf( JText::_('of translated'), $options['fileset-changed'], $options['fileset-refstrings'] ) .'<br>'. sprintf( JText::_('of published'), $options['fileset-exists'], $options['fileset-published'], $options['fileset-files'] ) .'</td>';
  972. }
  973. else {
  974. echo '<td width="100%" align="left"><div style="font-size:smaller"><div style="color:red">'. JText::_('Warning Default Language') .'</div>'. sprintf( JText::_('of published'), $options['fileset-published'], $options['fileset-exists'], $options['fileset-files'] ) .'</div></td>';
  975. }
  976. ?>
  977. <td align="right" nowrap="nowrap">
  978. <?php
  979. $html = '<img src="images/search_f2.png" align="absmiddle" width="16" height="16" alt="?" style="cursor:pointer" onclick="if(e=getElementById(\'filter_search\')){e.form.submit();}">';
  980. echo '<div style="border:1px solid gray;background-color:#e9e9e9"> &nbsp; ' . Language_manager_html::getTooltip( $html, 'Search Translation Files', 'Search', 'TC' ) . ' ';
  981. echo $lists['search'].' &nbsp; </div>';
  982. ?>
  983. </td>
  984. <td align="right"><?php echo $lists['state']; ?></td>
  985. <td align="right"><?php echo $lists['status']; ?></td>
  986. </tr>
  987. </table>
  988. <table class="adminlist" id="files">
  989. <thead>
  990. <tr>
  991. <th width="20"><?php echo JText::_( 'Num' ); ?></th>
  992. <th width="20"><input type="checkbox" name="toggle" value="" onclick="checkAll(<?php echo count( $data ); ?>);" /></th>
  993. <th width="25%"><?php echo JHTML::_( 'grid.sort', 'File', 'name', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  994. <th width="40"><?php echo JText::_( 'State' ); ?></th>
  995. <th width="100"><?php echo JHTML::_( 'grid.sort', 'Status', 'status', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  996. <th width="100"><?php echo JHTML::_( 'grid.sort', 'Strings', 'strings', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  997. <th width="40"><?php echo JHTML::_( 'grid.sort', 'Version', 'version', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  998. <th width="40"><?php echo JHTML::_( 'grid.sort', 'Date', 'datetime', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  999. <th width="20%"><?php echo JHTML::_( 'grid.sort', 'Author', 'author', $lists['order_Dir'], $lists['order'], $options['task'] ); ?></th>
  1000. </tr>
  1001. </thead>
  1002. <tfoot>
  1003. <td width="100%" colspan="9">
  1004. <?php echo $pagenav->getListFooter(); ?>
  1005. </td>
  1006. </tfoot>
  1007. <tbody>
  1008. <?php
  1009. // process the rows (each is an INI translation file)
  1010. for ($i=0, $n=count( $data ); $i < $n; $i++) {
  1011. $row =& $data[$i];
  1012. $link = 'index.php?option='.$option.'&task=edit_language&client_lang='.$options['client_lang'].'&cid[]='. $row->filename;
  1013. ?>
  1014. <tr class="row<?php echo $i; ?>">
  1015. <td width="20">
  1016. <?php echo $pagenav->getRowOffset( $i ); ?>
  1017. </td>
  1018. <td width="20">
  1019. <?php
  1020. // only select writable files
  1021. if ($row->checkedout) {
  1022. echo '<img src="images/checked_out.png" title="'.JText::_( 'Checked Out' ).'" alt="x" />';
  1023. } else if ($row->writable) {
  1024. echo '<input type="checkbox" id="cb'.$i.'" name="cid[]" value="'.$row->filename.'" onclick="isChecked(this.checked);" />';
  1025. } else {
  1026. echo '&nbsp;';
  1027. }
  1028. ?>
  1029. </td>
  1030. <td width="25%">
  1031. <?php
  1032. // edit all files
  1033. if ($row->writable) {
  1034. echo '<a href="' . $link . '" title="' . JText::_( 'Edit' ) . '">' . $row->name . '</a>';
  1035. } else {
  1036. echo $row->name;
  1037. }
  1038. if ( $row->bom != 'UTF-8' ) {
  1039. echo ' &nbsp; <a href="http://en.wikipedia.org/wiki/UTF-8" target="_blank"><b style="font-size:smaller;color:red">' . Language_manager_html::getTooltip( $row->bom, null, 'Not UTF-8', 'TC' ) . '</b></a>';
  1040. }
  1041. // search matches
  1042. if ($row->searchfound) {
  1043. $row->searchtext = htmlspecialchars($options['filter_search'],ENT_QUOTES);
  1044. if ($row->searchfound_ref) {
  1045. echo '<div style="font-size:smaller;color:red"> &nbsp; ' . sprintf( JText::_('matches ref file'), $row->searchfound_ref, $row->searchtext ) . '</div>';
  1046. }
  1047. if ($row->searchfound_tran) {
  1048. echo '<div style="font-size:smaller;color:green"> &nbsp; ' . sprintf( JText::_('matches tran file'), $row->searchfound_tran, $row->searchtext ) . '</div>';
  1049. }
  1050. }
  1051. ?>
  1052. </td>
  1053. <td align="center">
  1054. <?php
  1055. // only publish / unpublish writable files
  1056. if (!$row->exists) {
  1057. echo Language_manager_html::getTooltip( '<img src="images/disabled.png" alt="x" />', null, 'Does Not Exist', 'TC' );
  1058. } else if ($row->writable) {
  1059. echo JHTML::_( 'grid.published', $row, $i, 'publish_g.png', 'publish_r.png', 'language_' );
  1060. } else if ($row->published) {
  1061. echo '<img src="images/publish_g.png" alt="'.JText::_( 'Published' ).'" />';
  1062. } else {
  1063. echo '<img src="images/publish_r.png" alt="'.JText::_( 'Not Published' ).'" />';
  1064. }
  1065. ?>
  1066. </td>
  1067. <td width="100" align="center">
  1068. <?php
  1069. // no reference file
  1070. // status is inapplicable
  1071. // status is 100 (complete)
  1072. // status is 0 (not started)
  1073. // status is in progress
  1074. if ( $row->bom != 'UTF-8' ) {
  1075. echo Language_manager_html::getTooltip( '<a href="http://en.wikipedia.org/wiki/UTF-8" target="_blank"><img src="'.substr_replace(JURI::root(), '', -1, 1).'/includes/js/ThemeOffice/warning.png" alt="!" /></a>', null, 'Not UTF-8', 'TC' );
  1076. } else if (!$row->refexists) {
  1077. echo Language_manager_html::getTooltip( '<img src="images/disabled.png" alt="x" />', null, 'No Reference File', 'TC' );
  1078. } else if ($options['isReference']) {
  1079. echo Language_manager_html::getTooltip( '<img src="images/disabled.png" alt="x" />', null, 'This is the Reference Language', 'TC' );
  1080. } else if ($row->status == 100) {
  1081. echo Language_manager_html::getTooltip( '<img src="images/tick.png" alt="1000%" />', null, 'Complete', 'TC' );
  1082. } else if ($row->status == 0) {
  1083. echo Language_manager_html::getTooltip( '<img src="images/publish_x.png" alt="0%" />', null, 'Not Started', 'TC' );
  1084. } else {
  1085. echo '<span title="'. JText::_('In Progress') .': '. $row->changed . ' '. JText::_('Changed') .'">' . $row->status . '%<div style="text-align:left;border:solid silver 1px;width:100px;height:2px;"><div style="height:100%; width:' . $row->status . '%;background:green;"></div></div></span>';
  1086. }
  1087. ?>
  1088. </td>
  1089. <td align="center">
  1090. <?php
  1091. if ($options['isReference']) {
  1092. $status = $row->strings;
  1093. } else {
  1094. if ($row->changed==$row->refstrings) {
  1095. $status = $row->refstrings;
  1096. } else {
  1097. $status = $row->changed . '/' . $row->refstrings;
  1098. }
  1099. if($row->extra) {
  1100. $status .= ' +' . $row->extra;
  1101. }
  1102. }
  1103. if ($row->changed==0) {
  1104. $tip = null;
  1105. $caption = 'Not Started';
  1106. $jtext = 'TC';
  1107. } else if ($row->unchanged + $row->missing + $row->extra == 0) {
  1108. $tip = null;
  1109. $caption = 'Complete';
  1110. $jtext = 'TC';
  1111. } else {
  1112. $tip = '';
  1113. $tip .= ($row->unchanged==0) ? '' : sprintf(JText::_('Overlib Unchanged'), $row->unchanged) . '<br>';
  1114. $tip .= ($row->missing==0) ? '' : sprintf(JText::_('Overlib Missing'), $row->missing) . '<br>';
  1115. $tip .= ($row->extra==0) ? '' : sprintf(JText::_('Overlib Extra'), $row->extra) . '<br>';
  1116. $caption = sprintf(JText::_('Overlib Strings'), $row->refstrings);
  1117. $jtext = '';
  1118. }
  1119. echo Language_manager_html::getTooltip( $status, $tip, $caption, $jtext );
  1120. ?>
  1121. </td>
  1122. <td align="center">
  1123. <?php echo $row->version; ?>
  1124. </td>
  1125. <td align="center">
  1126. <?php echo '<span title="' . $row->time .'">' . $row->date . '</span>'; ?>
  1127. </td>
  1128. <td align="center">
  1129. <?php echo $row->author; ?>
  1130. </td>
  1131. </tr>
  1132. <?php
  1133. }
  1134. ?>
  1135. </tbody>
  1136. </table>
  1137. </form>
  1138. </div>
  1139. <?php
  1140. }
  1141. function Show_edit($data, $meta, $options) {
  1142. global $option;
  1143. // CONFIGURATION
  1144. $metaTokens = array (
  1145. 'version' => 10,
  1146. 'author' => 80,
  1147. 'copyright' => 80,
  1148. 'license' => 80,
  1149. );
  1150. // TOOLBAR
  1151. $newprocess = JRequest::getVar('newprocess',0,'','integer' );
  1152. $action = 'Edit';
  1153. JToolbarHelper::title(JText::_($action.' INI'),'langmanager.png');
  1154. JToolbarHelper::save('save_language');
  1155. JToolbarHelper::apply('apply_language');
  1156. JToolbarHelper::cancel('cancel_language');
  1157. ?>
  1158. <style type="text/css" >
  1159. #fftranslation legend {
  1160. color:black;
  1161. }
  1162. #fftranslation tr {
  1163. vertical-align:top;
  1164. }
  1165. td.ffMeta b i {
  1166. color:red;
  1167. }
  1168. td.ffMetaToken {
  1169. background-color: #f6f6f6;
  1170. border-bottom: 1px solid #e9e9e9;
  1171. border-right: 1px solid #e9e9e9;
  1172. color: #666;
  1173. font-weight: bold;
  1174. text-align: right;
  1175. vertical-align:top;
  1176. width:150px;
  1177. }
  1178. td.ffKeys {
  1179. background-color: #f6f6f6;
  1180. border:solid black 1px;
  1181. color: #666;
  1182. font-weight: bold;
  1183. text-align: right;
  1184. width:250px;
  1185. }
  1186. td.ffKeys input {
  1187. width:200px;
  1188. }
  1189. td.ffCounter {
  1190. color:gray;
  1191. font-size:smaller;
  1192. width:10px;
  1193. }
  1194. td.ffToken{
  1195. background-color: #f6f6f6;
  1196. border-bottom: 1px solid #e9e9e9;
  1197. border-right: 1px solid #e9e9e9;
  1198. color: #666;
  1199. font-weight: bold;
  1200. text-align: right;
  1201. width:50%;
  1202. }
  1203. span.ffToken {
  1204. font-weight:normal;
  1205. }
  1206. td.ffValue{
  1207. width:50%;
  1208. }
  1209. .ffChanged, .ffError, .ffExtra, .ffUnchanged {
  1210. width:90%;
  1211. padding-left:2px;
  1212. vertical-align:top;
  1213. }
  1214. .ffError {
  1215. border-left:solid red 2px;
  1216. }
  1217. .ffExtra {
  1218. border-left:solid green 2px;
  1219. }
  1220. .ffUnchanged {
  1221. border-left:solid red 2px;
  1222. }
  1223. .ffCopy {
  1224. float:right;
  1225. margin-top:2px;
  1226. }
  1227. .ffReset {
  1228. margin-top:2px;
  1229. margin-right:2px;
  1230. }
  1231. </style>
  1232. <script language="javascript" type="text/javascript">
  1233. var ffacElement;
  1234. var ffacList = new Array();
  1235. var ffacOldName = '';
  1236. var ffacOldValue = '';
  1237. function ffAutoCorrect(element) {
  1238. // initialise variables on first call, then timeout for one second
  1239. if (typeof(element) == 'object') {
  1240. ffacElement = element;
  1241. element = null;
  1242. ffacOldName = ffacElement.name;
  1243. ffacOldValue = ffacElement.value;
  1244. setTimeout("ffAutoCorrect()",1000);
  1245. }
  1246. // process on second call, only if name and value are unchanged
  1247. else if ( (ffacElement.name == ffacOldName) && (ffacElement.value == ffacOldValue) ) {
  1248. // get element length
  1249. el = ffacElement.value.length;
  1250. // process the AutoCorrect List
  1251. for (s in ffacList) {
  1252. // skip non-strings
  1253. if ( typeof(ffacList[s]) != "string" ) continue;
  1254. // get search string length
  1255. sl = s.length;
  1256. // check element is at least as long as search string
  1257. if (el>=sl) {
  1258. // check for matching string at end of element
  1259. if ( ffacElement.value.slice(el-sl) == s ) {
  1260. // replace matching string
  1261. ffacElement.value = ffacElement.value.slice(0,el-sl) + ffacList[s];
  1262. // return after making the replacement
  1263. return;
  1264. }
  1265. }
  1266. }
  1267. }
  1268. }
  1269. /**
  1270. * ffAppendRow
  1271. * Append a row (src) to the end of a table (table)
  1272. */
  1273. function ffAppendRow(table,src) {
  1274. if ( document.getElementById(table) && document.getElementById(src) ) {
  1275. // add new row at end of table
  1276. var newTR = document.getElementById(table).insertRow(-1);
  1277. // IE won't let us set the innerHTML of a row object, we need to copy the cells and their properties from the source
  1278. var cells = document.getElementById(src).cells;
  1279. var props = new Array('width','align','valign','colSpan','innerHTML','className');
  1280. for(var td=0;td<cells.length;td++){
  1281. // add new cell at the end of the row, then copy the properties
  1282. var newTD = newTR.insertCell(-1);
  1283. for (var p=0;p<props.length;p++) {
  1284. var prop = props[p];
  1285. if (cells[td][prop]) newTD[prop] = cells[td][prop];
  1286. }
  1287. }
  1288. }
  1289. }
  1290. /**
  1291. * ffCheckDisable
  1292. * Disable the fields linked to a checkbox (chk) by ID (id)
  1293. */
  1294. var ffchkconfirm = true;
  1295. var ffchkmessage = 'Are you sure you want to delete this phrase?';
  1296. function ffCheckDisable(chk,id) {
  1297. if ((!chk) || (!id)) return;
  1298. // 1: box has been checked - turn off flag
  1299. // 2: box has been cleared - flag is on
  1300. if (! chk.checked) {
  1301. ffchkconfirm = true;
  1302. } else if (ffchkconfirm) {
  1303. chk.checked = ffchkconfirm = window.confirm(ffchkmessage);
  1304. }
  1305. // set the key and input form
  1306. chk.form['key'+id].disabled = chk.form['value'+id].disabled = chk.checked;
  1307. }
  1308. /**
  1309. * ffCopySpanToInput
  1310. * Copy the reference value to an input box
  1311. */
  1312. function ffCopyRef2Val(i) {
  1313. src = 'ref' + i;
  1314. dst = 'value' + i;
  1315. if ( document.getElementById(src) && document.getElementById(dst) ) {
  1316. document.getElementById(dst).value = document.getElementById(src).innerHTML;
  1317. }
  1318. }
  1319. /**
  1320. * ffReset
  1321. * Reset the value of a form field to its default value
  1322. */
  1323. function ffResetVal(id) {
  1324. if ( document.getElementById(id) ) {
  1325. document.getElementById(id).value = document.getElementById(id).defaultValue;
  1326. }
  1327. }
  1328. function submitbutton(pressbutton) {
  1329. if (pressbutton == "cancel_language") {
  1330. submitform(pressbutton);
  1331. return;
  1332. }
  1333. var form = document.adminForm;
  1334. submitform(pressbutton);
  1335. }
  1336. // set a timeout to refresh the page
  1337. window.setTimeout ('if( window.confirm("<?php echo JText::_( 'Apply Reminder', 1 ); ?>" ) ) submitform("apply");', 300000);
  1338. // initialise ffAutoCorrect array
  1339. <?php foreach ($options['autoCorrect'] as $k=>$v) echo "ffacList['$k'] = '$v';\n"; ?>
  1340. // initialise ffCheckDisable message
  1341. ffchkmessage = '<?php echo ( $options['isReference'] ? JText::_('Warning Default Language',1) . '\n' : '' ) . JText::_('Confirm Delete String',1); ?>';
  1342. </script>
  1343. <div>
  1344. <form action="index.php" method="post" name="adminForm">
  1345. <input type="hidden" name="<?php echo JUtility::getToken(); ?>" value="1" />
  1346. <input type="hidden" name="option" value="<?php echo $option;?>" />
  1347. <input type="hidden" name="task" value="" />
  1348. <input type="hidden" name="client_lang" value="<?php echo $options['client_lang']; ?>" />
  1349. <input type="hidden" name="newprocess" value="<?php echo $options['newprocess']; ?>" />
  1350. <input type="hidden" name="limitstart" value="<?php echo $options['limitstart']; ?>" />
  1351. <div class="col100">
  1352. <fieldset class="adminform">
  1353. <legend><?php echo JText::_( 'Details' ) ; ?></legend>
  1354. <table class="admintable" width="100%">
  1355. <tr>
  1356. <td class="ffMetaToken"><?php echo Language_manager_html::getTooltip('Language'); ?></td>
  1357. <td class="ffMeta" nowrap><b><?php echo $options['langName'];?></b> <?php if ($options['isReference']) echo ' <i>['.JText::_('Warning Default Language').']</i></b>'; ?></td>
  1358. <td class="ffKeys" rowspan="3" nowrap>
  1359. <?php echo Language_manager_html::getTooltip('Key'); ?> &nbsp;
  1360. <input class="ffChanged" type="text" readonly value="<?php echo JText::_('String Changed'); ?>"><br>
  1361. <input class="ffUnchanged" type="text" readonly value="<?php echo JText::_('String Unchanged'); ?>"><br>
  1362. <input class="ffExtra" type="text" readonly value="<?php echo JText::_('String Extra'); ?>">
  1363. </td>
  1364. </tr>
  1365. <tr>
  1366. <td class="ffMetaToken">
  1367. <?php echo Language_manager_html::getTooltip('Filename'); ?>
  1368. </td>
  1369. <td>
  1370. <b><?php
  1371. // 1: NEW FILE = text input (with error CSS)
  1372. // 2: EXISTING = hidden input
  1373. if ($options['newprocess']) {
  1374. echo '<input ' . ( ( ($options['task']!='add') && (isset($options['field_error_list']['filename'])) ) ? 'class="ffError"' : '' ) . ' type="text" class="inputbox" size="30" name="newfilename" value="' . htmlspecialchars($options['newfilename']) . '" />';
  1375. } else {
  1376. echo '<input type="hidden" name="cid[]" value="'. htmlspecialchars($options['filename']) .'" />' . $options['filename'];
  1377. }
  1378. ?></b>
  1379. </td>
  1380. </tr>
  1381. <?php
  1382. // show Meta
  1383. foreach ( $metaTokens as $k=>$v ) {
  1384. $img = '<img src="templates/khepri/images/menu/icon-16-default.png" alt="*" onclick="document.adminForm.'. $k .'.value=\''. htmlspecialchars($options['XMLmeta'][$k]) .'\'" />';
  1385. echo '
  1386. <tr>
  1387. <td class="ffMetaToken">
  1388. <label for="' . $k . '">' . Language_manager_html::getTooltip( ucfirst($k) ) . '</label>
  1389. </td>
  1390. <td colspan="2">
  1391. <input ' . ( ( ($options['task']!='add') && (isset($options['field_error_list'][$k])) ) ? 'class="ffError"' : '' ) . ' type="text" size="'.$v.'" name="'.$k.'" id="'.$k.'" value="'.$meta[$k].'" onkeyup="ffAutoCorrect(this)" />' . Language_manager_html::getTooltip( $img, $options['XMLmeta'][$k], sprintf( JText::_('Use The Default'), JText::_($k) ), false ) . '
  1392. </td>
  1393. </tr>';
  1394. }
  1395. // show Status/Complete
  1396. if (!$options['isReference']) {
  1397. $status = sprintf( JText::_('of translated'), $meta['changed'], $meta['refstrings'], $meta['extra'] );
  1398. if ($meta['extra']) $status .= ', '. sprintf( JText::_('extra strings'), $meta['extra'] );
  1399. echo '
  1400. <tr>
  1401. <td class="ffMetaToken">
  1402. <label for="complete">' . Language_manager_html::getTooltip( 'Status' ) . '</label>
  1403. </td>
  1404. <td colspan="2">
  1405. <b>'. $meta['status'] .'%</b> &nbsp; ['. $status .'] &nbsp; <input class="ffCheckbox" type="checkbox" name="complete" value="COMPLETE" />'. Language_manager_html::getTooltip( 'Mark as Complete' ) . '
  1406. </td>
  1407. </tr>
  1408. ';
  1409. }
  1410. ?>
  1411. </table>
  1412. </fieldset>
  1413. </div>
  1414. <div class="clr"></div>
  1415. <?php
  1416. // Configure the search highlighting
  1417. $search = array();
  1418. if ($options['searchStyle']) {
  1419. $replace = '<span style="'.$options['searchStyle'].'">$0</span>';
  1420. foreach(explode(' ',$options['filter_search']) as $v) {
  1421. if ($v) {
  1422. $search[] = '/'.$v.'/i';
  1423. }
  1424. }
  1425. }
  1426. // process the file data into sections and HTML strings
  1427. $i = 0;
  1428. $heading = 0;
  1429. $output = array();
  1430. foreach($data as $k=>$v) {
  1431. // 1: strings are comments or lines from the INI file (change the section name if we have a comment)
  1432. // 2: arrays are key=value lines from the INI file
  1433. if ( is_string($v) ) {
  1434. if (!empty($v)) {
  1435. $heading = trim($v,';# ');
  1436. }
  1437. } else {
  1438. // initialise the row object
  1439. $row = new stdClass();
  1440. $row->cb = '';
  1441. $row->css = 'class="ffChanged"';
  1442. $row->edit = $v['edit'];
  1443. $row->i = ++$i;
  1444. $row->key = htmlspecialchars($k,ENT_QUOTES);
  1445. $row->match = 0;
  1446. $row->ref = (!isset($v['ref'])) ? null : $v['ref'];
  1447. $row->refshow = htmlspecialchars($row->ref);
  1448. // prepare form elements and styles
  1449. // 1: there is no reference language entry for this string
  1450. // 2: this is the reference language file
  1451. // 3: the reference language entry has not been changed
  1452. // 4: the reference language entry has been changed
  1453. if (is_null($row->ref)) {
  1454. $row->refshow = '<span class="ffToken">['.$row->key.']</span>';
  1455. $row->cb = '<input class="ffCheckbox" type="checkbox" onclick="javascript:ffCheckDisable(this,'.$i.');" />';
  1456. $row->css = 'class="ffExtra"';
  1457. } else if ($options['isReference']) {
  1458. $row->cb = '<input class="ffCheckbox" type="checkbox" onclick="javascript:ffCheckDisable(this,'.$i.');" />';
  1459. $row->css = 'class="ffChanged"';
  1460. } else if ($row->ref == $row->edit) {
  1461. $row->css = 'class="ffUnchanged"';
  1462. }
  1463. // highlight search terms
  1464. if (count($search)) {
  1465. $chk = preg_replace( $search, $replace, $row->refshow );
  1466. if ( $row->refshow != $chk ) {
  1467. $row->match++;
  1468. $row->refshow = $chk;
  1469. } else {
  1470. $chk = preg_replace( $search, $replace, $row->edit );
  1471. if ( $row->edit != $chk ) {
  1472. $row->match++;
  1473. } else {
  1474. $chk = preg_replace( $search, $replace, $row->key );
  1475. if ( $row->key != $chk ) {
  1476. $row->match++;
  1477. }
  1478. }
  1479. }
  1480. }
  1481. // store the input
  1482. if ( (strlen($row->ref)>80) || (strlen($row->edit)>80) ) {
  1483. $row->input = '<textarea '. $row->css .' name="ffValues[]" id="value'.$i.'" cols="80" rows="4" onkeyup="ffAutoCorrect(this)">'. htmlspecialchars( $row->edit, ENT_QUOTES ) .'</textarea>';
  1484. } else {
  1485. $row->input = '<input '. $row->css .' name="ffValues[]" id="value'.$i.'" type="text" size="80" value="'. htmlspecialchars( $row->edit, ENT_QUOTES ) .'" onkeyup="ffAutoCorrect(this)" />';
  1486. }
  1487. // store to the $extra or the $sections array
  1488. if ( (!$row->ref) && (!$options['isReference']) ) {
  1489. $extra[$k] = $row;
  1490. } else {
  1491. $sections[$heading][$k] = $row;
  1492. }
  1493. }
  1494. }
  1495. // add on any extra phrases at the end
  1496. if (isset($extra)) {
  1497. $sections['extra'] = $extra;
  1498. }
  1499. if (isset($sections)) {
  1500. // process the output data by section and then by row
  1501. foreach($sections as $k=>$v){
  1502. // section legend
  1503. $legend = (empty($k)) ? '' : '<legend>' . JText::_($k) . '</legend>';
  1504. // section help
  1505. $help = '';
  1506. if ($k) {
  1507. $help_key = $k . ' DESC';
  1508. $help = JText::_($help_key);
  1509. $help = ($help==$help_key) ? '' : '<tr valign="top"><td colspan="4">' . $help . '</td></tr>';
  1510. }
  1511. // section delete column (if there are any 'delete' checkboxes in the section)
  1512. foreach ( $v as $v2 ) {
  1513. if ($v2->cb) {
  1514. $help .= '<tr valign="bottom"><td colspan="2"></td><td nowrap align="right"><b>' . Language_manager_html::getTooltip( 'Delete', null, 'Delete Phrase' ) . '</b></td></tr>';
  1515. break;
  1516. }
  1517. }
  1518. ?>
  1519. <div class="col100">
  1520. <fieldset class="adminform">
  1521. <?php echo $legend; ?>
  1522. <table class="admintable" width="100%">
  1523. <?php
  1524. echo $help;
  1525. $i=1;
  1526. foreach($v as $row){
  1527. ?>
  1528. <tr valign="top" id="row<?php echo $row->i; ?>">
  1529. <td class="ffCounter">
  1530. <?php echo ($row->match) ? '<span style="' . $options['searchStyle'] . ';width:100%">' . $i++ . '</span>' : $i++; ?>
  1531. </td>
  1532. <td class="ffToken">
  1533. <?php
  1534. if (!is_null($row->ref)) {
  1535. echo '<a class="ffCopy" href="javascript:ffCopyRef2Val(' . $row->i . ')">' . Language_manager_html::getTooltip( '<img src="../images/M_images/arrow.png" alt="&gt;" />', null, 'COPY STRING', 'TC') . '</a>';
  1536. }
  1537. ?>
  1538. <input type="hidden" name="ffKeys[]" value="<?php echo $row->key ?>" id="key<?php echo $row->i ?>"/><?php echo Language_manager_html::getTooltip( '<span id="ref' . $row->i .'">' . $row->refshow . '</span>', $row->key, JText::_('Key'), false); ?>
  1539. </td>
  1540. <td class="ffValue" nowrap valign="middle">
  1541. <?php
  1542. echo $row->input;
  1543. echo '<a class="ffReset" href="javascript:ffResetVal(\'value' . $row->i . '\')">' . Language_manager_html::getTooltip( '<img src="'.substr_replace(JURI::root(), '', -1, 1).'/includes/js/ThemeOffice/arrow_rtl.png" vspace="middle" alt="&lt;" />', null, 'RESET STRING', 'TC') . '</a>';
  1544. echo $row->cb;
  1545. ?>
  1546. </td>
  1547. </tr>
  1548. <?php
  1549. }
  1550. ?>
  1551. </table>
  1552. </fieldset>
  1553. </div>
  1554. <div class="clr"></div>
  1555. <?php
  1556. }
  1557. }
  1558. ?>
  1559. <div class="col100">
  1560. <fieldset class="adminform">
  1561. <legend><?php echo JText::_('New Phrases'); ?></legend>
  1562. <table class="admintable" width="100%" id="extraTable">
  1563. <tr valign="top">
  1564. <td colspan="4"><?php echo JText::_('New Phrases DESC'); ?></td>
  1565. </tr>
  1566. <tr>
  1567. <td><div id="ffExtra"></div></td>
  1568. </tr>
  1569. </table>
  1570. <a href="javascript:ffAppendRow('extraTable','extraRow');"><b>[+]</b> <?php echo JText::_('Add phrases'); ?></a>
  1571. </fieldset>
  1572. </div>
  1573. <div class="clr"></div>
  1574. <div id="ffAddField" style="display:none">
  1575. <table class="admintable" width="100%">
  1576. <tr valign="top" id="extraRow">
  1577. <td class="ffToken">
  1578. [new key] <input class="ffUnchanged" name="ffKeys[]" type="text" size="80" value="" style="width:50%" onchange="this.value=this.value.replace(/[=]/,'').toUpperCase()" />
  1579. </td>
  1580. <td class="ffValue">
  1581. <input class="ffChanged" name="ffValues[]" type="text" size="80" value="" />
  1582. </td>
  1583. </tr>
  1584. </table>
  1585. </div>
  1586. </form>
  1587. </div>
  1588. <?php
  1589. }
  1590. function getTooltip ( $html, $tip=null, $caption=null, $jtext = 'HTC' )
  1591. {
  1592. // behaviour flag
  1593. $behavior = false;
  1594. // prepare JText config
  1595. $jtext = ' ' . strtoupper($jtext);
  1596. // 1: lookup an Automatic JText tip and caption
  1597. // 2: lookup an Automatic JText caption
  1598. // 3: lookup JText $tip and $caption
  1599. if ($jtext) {
  1600. if (is_null($tip)) {
  1601. $caption_key = ($caption) ? $caption : $html;
  1602. $tip_key = $caption_key . ' DESC';
  1603. $caption = strpos($jtext,'C') ? JText::_($caption_key) : $caption_key;
  1604. $tip = strpos($jtext,'T') ? JText::_($tip_key) : $tip_key;
  1605. $tip = ($tip==$tip_key) ? '' : $tip;
  1606. } else if (is_null($caption)) {
  1607. $caption = strpos($jtext,'C') ? JText::_($html) : $html;
  1608. } else {
  1609. $caption = strpos($jtext,'C') ? JText::_($caption) : $caption;
  1610. $tip = strpos($jtext,'T') ? JText::_($tip) : $tip;
  1611. }
  1612. // lookup JText $html
  1613. $html = strpos($jtext,'H') ? JText::_($html) : $html;
  1614. }
  1615. // add the tooltip to the html
  1616. if (($tip) || ($caption!=$html)) {
  1617. // apply title to tip
  1618. if (!$tip) {
  1619. $tip = $caption;
  1620. $caption = '';
  1621. }
  1622. if (!$behavior) {
  1623. JHTML::_('behavior.tooltip');
  1624. $behavior = true;
  1625. }
  1626. // build tooltip span
  1627. $html = '<span class="editlinktip hasTip" title="' . ( $caption ? htmlspecialchars($caption) . '::' : '' ) . htmlspecialchars($tip) . '">' . $html . '</span>';
  1628. }
  1629. // return
  1630. return $html;
  1631. }
  1632. }
  1633. class TranslationsHelper
  1634. {
  1635. /**
  1636. * Get Meta Info from language translation file content.
  1637. * @param mixed The contents of the file using file() or get_file_contents().
  1638. * @param array A blank array, strings will be returned by association
  1639. * @param array Optional associative array of reference strings
  1640. * @return array The Meta Info in an array
  1641. */
  1642. function getINIMeta( $content, &$strings, $ref_strings = null )
  1643. {
  1644. // convert a string to an array
  1645. if (is_string($content)) {
  1646. $content = explode("\n",$content,10);
  1647. } else if (!is_array($content)) {
  1648. $content = array();
  1649. }
  1650. // look for a Byte-Order-Marker at the start of the file
  1651. $file['bom'] = 'UTF-8';
  1652. if ($content) {
  1653. $bom = strtolower(bin2hex(substr($content[0],0,4)));
  1654. if ( $bom == '0000feff' ) {
  1655. $file['bom'] = 'UTF-32 BE';
  1656. } else if ( $bom == 'feff0000' ) {
  1657. $file['bom'] = 'UTF-32 LE';
  1658. } else if ( substr($bom,0,4) == 'feff' ) {
  1659. $file['bom'] = 'UTF-16 BE';
  1660. } else if ( substr($bom,0,4) == 'fffe' ) {
  1661. $file['bom'] = 'UTF-16 LE';
  1662. }
  1663. }
  1664. // parse the top line from one of these two formats
  1665. // # $Id: en-GB.mod_poll.ini 6167 2007-01-04 01:16:01Z eddiea $
  1666. // # version 1.5.0 2007-01-25 10:40:16 ~0 +0
  1667. if (strpos($content[0],'.ini')) {
  1668. $line = preg_replace('/^.*[.]ini[ ]+/','',$content[0]);
  1669. list( $file['version'], $file['date'], $file['time'], $file['owner'], $file['complete'] ) = explode( ' ', $line . ' ', 6 );
  1670. $file['headertype'] = 1;
  1671. } else {
  1672. $line = preg_replace('/^.*version/i','',$content[0]);
  1673. $line = trim($line);
  1674. list( $file['version'], $file['date'], $file['time'], $file['complete'] ) = explode( ' ', $line . ' ', 5 );
  1675. $file['owner'] = '';
  1676. $file['headertype'] = 2;
  1677. }
  1678. // tidy up the values
  1679. $file['complete'] = preg_replace('/[^0-9]/', '', $file['complete']);
  1680. $file['author'] = preg_replace('/^.*author[ ]+/i', '', trim($content[1],'# ') );
  1681. $file['copyright'] = preg_replace('/^.*copyright[ ]+/i', '', trim($content[2],'# ') );
  1682. $file['license'] = preg_replace('/^.*license[ ]+/i', '', trim($content[3],'# ') );
  1683. // parse the strings in the file into an associative array
  1684. $strings = array();
  1685. foreach ($content as $line) {
  1686. $line = trim($line);
  1687. // 1: skip comments and blanks
  1688. // 2: get the ucase key and value
  1689. if ((empty($line))||($line{0}=='#')||($line{0}==';')) {
  1690. continue;
  1691. } else if (strpos($line,'=')) {
  1692. list($key,$value) = explode('=',$line,2);
  1693. $key = strtoupper($key);
  1694. $strings[$key] = $value;
  1695. }
  1696. }
  1697. // get the status compared to the ref strings
  1698. $file = array_merge( $file, TranslationsHelper::getINIstatus( $ref_strings, $strings ) );
  1699. // set a complete flag
  1700. if ( ( $file['complete'] == $file['unchanged'] ) && ( $file['missing'] == 0 ) ) {
  1701. $file['status'] = 100;
  1702. }
  1703. // return
  1704. return $file;
  1705. }
  1706. /**
  1707. * Get Meta Info from language translation file content.
  1708. * @param array The reference strings in an associative array
  1709. * @param array The language strings in an associative array
  1710. * @return array The Meta Info in an array
  1711. */
  1712. function getINIstatus( $ref_strings, $strings )
  1713. {
  1714. // initialise
  1715. $file = array();
  1716. $file['changed'] = 0;
  1717. $file['extra'] = 0;
  1718. $file['missing'] = 0;
  1719. $file['refstrings'] = count($ref_strings);
  1720. $file['status'] = 0;
  1721. $file['strings'] = count($strings);
  1722. $file['unchanged'] = 0;
  1723. // count changes
  1724. if (!$file['strings']) {
  1725. $file['missing'] = $file['refstrings'];
  1726. } else if (!$file['refstrings']) {
  1727. $file['extra'] = $file['strings'];
  1728. } else {
  1729. // count the changes
  1730. $all_strings = array_merge($ref_strings,$strings);
  1731. foreach($all_strings as $k=>$v){
  1732. if (!isset($ref_strings[$k])) {
  1733. $file['extra']++;
  1734. } else if (!isset($strings[$k])) {
  1735. $file['missing']++;
  1736. } else if ($v!=$ref_strings[$k]) {
  1737. $file['changed']++;
  1738. } else {
  1739. $file['unchanged']++;
  1740. }
  1741. }
  1742. }
  1743. // set status
  1744. if ($file['changed'] == 0) {
  1745. $file['status'] = 0;
  1746. } else if ($file['strings'] == $file['changed']) {
  1747. $file['status'] = 100;
  1748. } else {
  1749. $file['status'] = min(100,floor( ($file['changed']/$file['strings'])*100 ));
  1750. }
  1751. // return
  1752. return $file;
  1753. }
  1754. /**
  1755. * Get Meta Info from an XML language file (extends Joomla method to handle mixed/lower cases)
  1756. * @param string $xmlFile The file to parse including the path.
  1757. * @return array The Meta Info in an array
  1758. */
  1759. function getXMLMeta( $xmlFile ) {
  1760. $xmlData = array(
  1761. 'author' => '',
  1762. 'authorEmail' => '',
  1763. 'authorUrl' => '',
  1764. 'client' => '',
  1765. 'copyright' => '',
  1766. 'creationDate' => '',
  1767. 'date' => date('Y-m-d'),
  1768. 'description' => '',
  1769. 'license' => '',
  1770. 'name' => '',
  1771. 'tag' => '',
  1772. 'time' => date('H:m:i'),
  1773. 'version' => '',
  1774. );
  1775. // load the XML file and run some tests to ensure that it exists and is a metafile
  1776. $xml = & JFactory::getXMLParser('Simple');
  1777. if (is_file($xmlFile)) {
  1778. if ( $xml->loadFile($xmlFile) ) {
  1779. if ($xml->document->name() == 'metafile') {
  1780. // all the nodes in the XML file will come through as lowercase keys
  1781. // process the $xmlData array against the XML object tree
  1782. foreach ($xmlData as $k=>$v) {
  1783. $k_lc = strtolower($k);
  1784. $element = & $xml->document->{$k}[0];
  1785. if ($element) {
  1786. $xmlData[$k] = $element->data();
  1787. } else {
  1788. $element = & $xml->document->{$k_lc}[0];
  1789. if ($element) {
  1790. $xmlData[$k] = $element->data();
  1791. } else {
  1792. $xmlData[$k] = $v;
  1793. }
  1794. }
  1795. }
  1796. }
  1797. }
  1798. // patch the date
  1799. if ( (empty($xmlData['date'])) && (!empty($xmlData['creationdate'])) ) $xmlData['date'] = $xmlData['creationdate'];
  1800. }
  1801. // return
  1802. return $xmlData;
  1803. }
  1804. /**
  1805. * Transform a translation phrase.
  1806. * @param string $s The phrase to transform.
  1807. * @param array $options The configuration array for the component.
  1808. * @return string The transformed phrase
  1809. */
  1810. function strtr($s,$options) {
  1811. // backticks
  1812. if ($options['backticks']>0) {
  1813. $s = strtr($s,"'",'`');
  1814. } else if ($options['backticks']<0) {
  1815. $s = strtr($s,'`',"'");
  1816. }
  1817. // return
  1818. return $s;
  1819. }
  1820. }
  1821. ?>