110449332Schris<?php 210449332Schris/** 310449332Schris * Configuration Manager admin plugin 410449332Schris * 510449332Schris * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 610449332Schris * @author Christopher Smith <chris@jalakai.co.uk> 7685bdd2eSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 810449332Schris */ 910449332Schris 10*c6639e6aSAndreas Gohruse dokuwiki\plugin\config\core\Configuration; 1110449332Schris 1210449332Schris/** 1310449332Schris * All DokuWiki plugins to extend the admin function 1410449332Schris * need to inherit from this class 1510449332Schris */ 1610449332Schrisclass admin_plugin_config extends DokuWiki_Admin_Plugin { 1710449332Schris 18*c6639e6aSAndreas Gohr const METADATA = __DIR__ . 'settings/config.metadata.php'; 19*c6639e6aSAndreas Gohr const IMGDIR = DOKU_BASE.'lib/plugins/config/images/'; 20*c6639e6aSAndreas Gohr 2161e35c35SAndreas Gohr protected $_config = null; 2261e35c35SAndreas Gohr protected $_input = null; 2361e35c35SAndreas Gohr protected $_changed = false; // set to true if configuration has altered 2461e35c35SAndreas Gohr protected $_error = false; 2561e35c35SAndreas Gohr protected $_session_started = false; 2661e35c35SAndreas Gohr protected $_localised_prompts = false; 2710449332Schris 28253d4b48SGerrit Uitslag /** 29253d4b48SGerrit Uitslag * @return int 30253d4b48SGerrit Uitslag */ 3161e35c35SAndreas Gohr public function getMenuSort() { return 100; } 3210449332Schris 3310449332Schris /** 3410449332Schris * handle user request 3510449332Schris */ 3661e35c35SAndreas Gohr public function handle() { 37392c9b52SHakan Sandell global $ID, $INPUT; 3810449332Schris 39253d4b48SGerrit Uitslag if(!$this->_restore_session() || $INPUT->int('save') != 1 || !checkSecurityToken()) { 40253d4b48SGerrit Uitslag $this->_close_session(); 41253d4b48SGerrit Uitslag return; 42253d4b48SGerrit Uitslag } 4310449332Schris 44253d4b48SGerrit Uitslag if(is_null($this->_config)) { 45*c6639e6aSAndreas Gohr $this->_config = new Configuration(self::METADATA); 46253d4b48SGerrit Uitslag } 4710449332Schris 4810449332Schris // don't go any further if the configuration is locked 49253d4b48SGerrit Uitslag if($this->_config->locked) { 50253d4b48SGerrit Uitslag $this->_close_session(); 51253d4b48SGerrit Uitslag return; 52253d4b48SGerrit Uitslag } 5310449332Schris 54392c9b52SHakan Sandell $this->_input = $INPUT->arr('config'); 5510449332Schris 568f1011e8SPhy foreach ($this->_config->setting as $key => $value){ 570ea51e63SMatt Perry $input = isset($this->_input[$key]) ? $this->_input[$key] : null; 5810449332Schris if ($this->_config->setting[$key]->update($input)) { 5910449332Schris $this->_changed = true; 6010449332Schris } 6110449332Schris if ($this->_config->setting[$key]->error()) $this->_error = true; 6210449332Schris } 6310449332Schris 6410449332Schris if ($this->_changed && !$this->_error) { 6510449332Schris $this->_config->save_settings($this->getPluginName()); 6610449332Schris 6710449332Schris // save state & force a page reload to get the new settings to take effect 6810449332Schris $_SESSION['PLUGIN_CONFIG'] = array('state' => 'updated', 'time' => time()); 6910449332Schris $this->_close_session(); 703295f40aSAndreas Gohr send_redirect(wl($ID,array('do'=>'admin','page'=>'config'),true,'&')); 7110449332Schris exit(); 72e0e514e1SAndreas Gohr } elseif(!$this->_error) { 73e0e514e1SAndreas Gohr $this->_config->touch_settings(); // just touch to refresh cache 7410449332Schris } 7510449332Schris 7610449332Schris $this->_close_session(); 7710449332Schris } 7810449332Schris 7910449332Schris /** 8010449332Schris * output appropriate html 8110449332Schris */ 8261e35c35SAndreas Gohr public function html() { 83685bdd2eSBen Coburn $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 8410449332Schris global $lang; 85400497e1Schris global $ID; 8610449332Schris 87*c6639e6aSAndreas Gohr if (is_null($this->_config)) { $this->_config = new Configuration(self::METADATA); } 8889d74a2fSchris $this->setupLocale(true); 8910449332Schris 9010449332Schris print $this->locale_xhtml('intro'); 9110449332Schris 9224a33b42SAndreas Gohr ptln('<div id="config__manager">'); 9310449332Schris 9410449332Schris if ($this->_config->locked) 95e4a98f5cSAnika Henke ptln('<div class="info">'.$this->getLang('locked').'</div>'); 9610449332Schris elseif ($this->_error) 97e4a98f5cSAnika Henke ptln('<div class="error">'.$this->getLang('error').'</div>'); 9810449332Schris elseif ($this->_changed) 99e4a98f5cSAnika Henke ptln('<div class="success">'.$this->getLang('updated').'</div>'); 10010449332Schris 1015d85efc6SAdrian Lang // POST to script() instead of wl($ID) so config manager still works if 1025d85efc6SAdrian Lang // rewrite config is broken. Add $ID as hidden field to remember 1035d85efc6SAdrian Lang // current ID in most cases. 104f338aa80SAndreas Gohr ptln('<form action="'.script().'" method="post">'); 105f24af591SAnika Henke ptln('<div class="no"><input type="hidden" name="id" value="'.$ID.'" /></div>'); 106634d7150SAndreas Gohr formSecurityToken(); 1074fa2dffcSBen Coburn $this->_print_h1('dokuwiki_settings', $this->getLang('_header_dokuwiki')); 10810449332Schris 109253d4b48SGerrit Uitslag /** @var setting[] $undefined_settings */ 110685bdd2eSBen Coburn $undefined_settings = array(); 1114fa2dffcSBen Coburn $in_fieldset = false; 1124fa2dffcSBen Coburn $first_plugin_fieldset = true; 1134fa2dffcSBen Coburn $first_template_fieldset = true; 11410449332Schris foreach($this->_config->setting as $setting) { 115685bdd2eSBen Coburn if (is_a($setting, 'setting_hidden')) { 116685bdd2eSBen Coburn // skip hidden (and undefined) settings 117685bdd2eSBen Coburn if ($allow_debug && is_a($setting, 'setting_undefined')) { 118685bdd2eSBen Coburn $undefined_settings[] = $setting; 119685bdd2eSBen Coburn } else { 120685bdd2eSBen Coburn continue; 121685bdd2eSBen Coburn } 122685bdd2eSBen Coburn } else if (is_a($setting, 'setting_fieldset')) { 1234fa2dffcSBen Coburn // config setting group 1244fa2dffcSBen Coburn if ($in_fieldset) { 1254fa2dffcSBen Coburn ptln(' </table>'); 126e260f93bSAnika Henke ptln(' </div>'); 1274fa2dffcSBen Coburn ptln(' </fieldset>'); 1284fa2dffcSBen Coburn } else { 1294fa2dffcSBen Coburn $in_fieldset = true; 1304fa2dffcSBen Coburn } 131*c6639e6aSAndreas Gohr if ($first_plugin_fieldset && substr($setting->_key, 0, 10)=='plugin'.Configuration::KEYMARKER) { 1324fa2dffcSBen Coburn $this->_print_h1('plugin_settings', $this->getLang('_header_plugin')); 1334fa2dffcSBen Coburn $first_plugin_fieldset = false; 134*c6639e6aSAndreas Gohr } else if ($first_template_fieldset && substr($setting->_key, 0, 7)=='tpl'.Configuration::KEYMARKER) { 1354fa2dffcSBen Coburn $this->_print_h1('template_settings', $this->getLang('_header_template')); 1364fa2dffcSBen Coburn $first_template_fieldset = false; 1374fa2dffcSBen Coburn } 138685bdd2eSBen Coburn ptln(' <fieldset id="'.$setting->_key.'">'); 1394fa2dffcSBen Coburn ptln(' <legend>'.$setting->prompt($this).'</legend>'); 140c7b28ffdSAnika Henke ptln(' <div class="table">'); 1414fa2dffcSBen Coburn ptln(' <table class="inline">'); 1424fa2dffcSBen Coburn } else { 1434fa2dffcSBen Coburn // config settings 14410449332Schris list($label,$input) = $setting->html($this, $this->_error); 14510449332Schris 14664159a61SAndreas Gohr $class = $setting->is_default() 14764159a61SAndreas Gohr ? ' class="default"' 14864159a61SAndreas Gohr : ($setting->is_protected() ? ' class="protected"' : ''); 14964159a61SAndreas Gohr $error = $setting->error() 15064159a61SAndreas Gohr ? ' class="value error"' 15164159a61SAndreas Gohr : ' class="value"'; 15264159a61SAndreas Gohr $icon = $setting->caution() 153*c6639e6aSAndreas Gohr ? '<img src="'.self::IMGDIR.$setting->caution().'.png" '. 15464159a61SAndreas Gohr 'alt="'.$setting->caution().'" title="'.$this->getLang($setting->caution()).'" />' 15564159a61SAndreas Gohr : ''; 15610449332Schris 15710449332Schris ptln(' <tr'.$class.'>'); 158dde31035SAndreas Gohr ptln(' <td class="label">'); 1597ed33b2aSAnika Henke ptln(' <span class="outkey">'.$setting->_out_key(true, true).'</span>'); 160bccdba06SAndreas Gohr ptln(' '.$icon.$label); 161dde31035SAndreas Gohr ptln(' </td>'); 16210449332Schris ptln(' <td'.$error.'>'.$input.'</td>'); 16310449332Schris ptln(' </tr>'); 16410449332Schris } 1654fa2dffcSBen Coburn } 16610449332Schris 16710449332Schris ptln(' </table>'); 168c7b28ffdSAnika Henke ptln(' </div>'); 1694fa2dffcSBen Coburn if ($in_fieldset) { 1704fa2dffcSBen Coburn ptln(' </fieldset>'); 1714fa2dffcSBen Coburn } 17210449332Schris 173685bdd2eSBen Coburn // show undefined settings list 174685bdd2eSBen Coburn if ($allow_debug && !empty($undefined_settings)) { 175253d4b48SGerrit Uitslag /** 176253d4b48SGerrit Uitslag * Callback for sorting settings 177253d4b48SGerrit Uitslag * 178253d4b48SGerrit Uitslag * @param setting $a 179253d4b48SGerrit Uitslag * @param setting $b 180253d4b48SGerrit Uitslag * @return int if $a is lower/equal/higher than $b 181253d4b48SGerrit Uitslag */ 182253d4b48SGerrit Uitslag function _setting_natural_comparison($a, $b) { 183253d4b48SGerrit Uitslag return strnatcmp($a->_key, $b->_key); 184253d4b48SGerrit Uitslag } 185253d4b48SGerrit Uitslag 186685bdd2eSBen Coburn usort($undefined_settings, '_setting_natural_comparison'); 187685bdd2eSBen Coburn $this->_print_h1('undefined_settings', $this->getLang('_header_undefined')); 188685bdd2eSBen Coburn ptln('<fieldset>'); 189c7b28ffdSAnika Henke ptln('<div class="table">'); 190685bdd2eSBen Coburn ptln('<table class="inline">'); 191685bdd2eSBen Coburn $undefined_setting_match = array(); 192685bdd2eSBen Coburn foreach($undefined_settings as $setting) { 19364159a61SAndreas Gohr if ( 19464159a61SAndreas Gohr preg_match( 195*c6639e6aSAndreas Gohr '/^(?:plugin|tpl)'.Configuration::KEYMARKER.'.*?'.Configuration::KEYMARKER.'(.*)$/', 19664159a61SAndreas Gohr $setting->_key, 19764159a61SAndreas Gohr $undefined_setting_match 19864159a61SAndreas Gohr ) 19964159a61SAndreas Gohr ) { 200685bdd2eSBen Coburn $undefined_setting_key = $undefined_setting_match[1]; 201685bdd2eSBen Coburn } else { 202685bdd2eSBen Coburn $undefined_setting_key = $setting->_key; 203685bdd2eSBen Coburn } 204685bdd2eSBen Coburn ptln(' <tr>'); 20564159a61SAndreas Gohr ptln(' <td class="label"><span title="$meta[\''.$undefined_setting_key.'\']">$'. 20664159a61SAndreas Gohr $this->_config->_name.'[\''.$setting->_out_key().'\']</span></td>'); 207685bdd2eSBen Coburn ptln(' <td>'.$this->getLang('_msg_'.get_class($setting)).'</td>'); 208685bdd2eSBen Coburn ptln(' </tr>'); 209685bdd2eSBen Coburn } 210685bdd2eSBen Coburn ptln('</table>'); 211c7b28ffdSAnika Henke ptln('</div>'); 212685bdd2eSBen Coburn ptln('</fieldset>'); 213685bdd2eSBen Coburn } 214685bdd2eSBen Coburn 215685bdd2eSBen Coburn // finish up form 21610449332Schris ptln('<p>'); 21710449332Schris ptln(' <input type="hidden" name="do" value="admin" />'); 21810449332Schris ptln(' <input type="hidden" name="page" value="config" />'); 21910449332Schris 22010449332Schris if (!$this->_config->locked) { 22110449332Schris ptln(' <input type="hidden" name="save" value="1" />'); 222ae614416SAnika Henke ptln(' <button type="submit" name="submit" accesskey="s">'.$lang['btn_save'].'</button>'); 223ae614416SAnika Henke ptln(' <button type="reset">'.$lang['btn_reset'].'</button>'); 22410449332Schris } 22510449332Schris 22610449332Schris ptln('</p>'); 22710449332Schris 22810449332Schris ptln('</form>'); 22910449332Schris ptln('</div>'); 23010449332Schris } 23110449332Schris 23210449332Schris /** 23310449332Schris * @return boolean true - proceed with handle, false - don't proceed 23410449332Schris */ 23561e35c35SAndreas Gohr protected function _restore_session() { 23610449332Schris 23710449332Schris // dokuwiki closes the session before act_dispatch. $_SESSION variables are all set, 23810449332Schris // however they can't be changed without starting the session again 23910449332Schris if (!headers_sent()) { 24010449332Schris session_start(); 24110449332Schris $this->_session_started = true; 24210449332Schris } 24310449332Schris 24410449332Schris if (!isset($_SESSION['PLUGIN_CONFIG'])) return true; 24510449332Schris 24610449332Schris $session = $_SESSION['PLUGIN_CONFIG']; 24710449332Schris unset($_SESSION['PLUGIN_CONFIG']); 24810449332Schris 24910449332Schris // still valid? 25010449332Schris if (time() - $session['time'] > 120) return true; 25110449332Schris 25210449332Schris switch ($session['state']) { 25310449332Schris case 'updated' : 25410449332Schris $this->_changed = true; 25510449332Schris return false; 25610449332Schris } 25710449332Schris 25810449332Schris return true; 25910449332Schris } 26010449332Schris 26161e35c35SAndreas Gohr protected function _close_session() { 26210449332Schris if ($this->_session_started) session_write_close(); 26310449332Schris } 26410449332Schris 265253d4b48SGerrit Uitslag /** 266253d4b48SGerrit Uitslag * @param bool $prompts 267253d4b48SGerrit Uitslag */ 26861e35c35SAndreas Gohr public function setupLocale($prompts=false) { 26989d74a2fSchris 27089d74a2fSchris parent::setupLocale(); 27189d74a2fSchris if (!$prompts || $this->_localised_prompts) return; 27289d74a2fSchris 27389d74a2fSchris $this->_setup_localised_plugin_prompts(); 27489d74a2fSchris $this->_localised_prompts = true; 27589d74a2fSchris 27689d74a2fSchris } 27789d74a2fSchris 278253d4b48SGerrit Uitslag /** 279253d4b48SGerrit Uitslag * @return bool 280253d4b48SGerrit Uitslag */ 28161e35c35SAndreas Gohr protected function _setup_localised_plugin_prompts() { 28289d74a2fSchris global $conf; 28389d74a2fSchris 284746855cfSBen Coburn $langfile = '/lang/'.$conf['lang'].'/settings.php'; 28589d74a2fSchris $enlangfile = '/lang/en/settings.php'; 28689d74a2fSchris 28789d74a2fSchris if ($dh = opendir(DOKU_PLUGIN)) { 28889d74a2fSchris while (false !== ($plugin = readdir($dh))) { 28989d74a2fSchris if ($plugin == '.' || $plugin == '..' || $plugin == 'tmp' || $plugin == 'config') continue; 29089d74a2fSchris if (is_file(DOKU_PLUGIN.$plugin)) continue; 29189d74a2fSchris 29279e79377SAndreas Gohr if (file_exists(DOKU_PLUGIN.$plugin.$enlangfile)){ 293f1f77134SEsther Brunner $lang = array(); 29489d74a2fSchris @include(DOKU_PLUGIN.$plugin.$enlangfile); 29589d74a2fSchris if ($conf['lang'] != 'en') @include(DOKU_PLUGIN.$plugin.$langfile); 296f1f77134SEsther Brunner foreach ($lang as $key => $value){ 297*c6639e6aSAndreas Gohr $this->lang['plugin'.Configuration::KEYMARKER.$plugin.Configuration::KEYMARKER.$key] = $value; 298f1f77134SEsther Brunner } 29989d74a2fSchris } 3004fa2dffcSBen Coburn 3014fa2dffcSBen Coburn // fill in the plugin name if missing (should exist for plugins with settings) 302*c6639e6aSAndreas Gohr if (!isset($this->lang['plugin'.Configuration::KEYMARKER.$plugin.Configuration::KEYMARKER.'plugin_settings_name'])) { 303*c6639e6aSAndreas Gohr $this->lang['plugin'.Configuration::KEYMARKER.$plugin.Configuration::KEYMARKER.'plugin_settings_name'] = 304cd3ed83cSMatthias Schulte ucwords(str_replace('_', ' ', $plugin)); 3054fa2dffcSBen Coburn } 30689d74a2fSchris } 30789d74a2fSchris closedir($dh); 30889d74a2fSchris } 30989d74a2fSchris 3104a778400SEsther Brunner // the same for the active template 3114a778400SEsther Brunner $tpl = $conf['template']; 3124a778400SEsther Brunner 31379e79377SAndreas Gohr if (file_exists(tpl_incdir().$enlangfile)){ 3144a778400SEsther Brunner $lang = array(); 315bc9d46afSAndreas Gohr @include(tpl_incdir().$enlangfile); 316bc9d46afSAndreas Gohr if ($conf['lang'] != 'en') @include(tpl_incdir().$langfile); 3174a778400SEsther Brunner foreach ($lang as $key => $value){ 318*c6639e6aSAndreas Gohr $this->lang['tpl'.Configuration::KEYMARKER.$tpl.Configuration::KEYMARKER.$key] = $value; 3194a778400SEsther Brunner } 3204a778400SEsther Brunner } 3214a778400SEsther Brunner 3224fa2dffcSBen Coburn // fill in the template name if missing (should exist for templates with settings) 323*c6639e6aSAndreas Gohr if (!isset($this->lang['tpl'.Configuration::KEYMARKER.$tpl.Configuration::KEYMARKER.'template_settings_name'])) { 324*c6639e6aSAndreas Gohr $this->lang['tpl'.Configuration::KEYMARKER.$tpl.Configuration::KEYMARKER.'template_settings_name'] = 325cd3ed83cSMatthias Schulte ucwords(str_replace('_', ' ', $tpl)); 3264fa2dffcSBen Coburn } 3274fa2dffcSBen Coburn 32889d74a2fSchris return true; 32989d74a2fSchris } 33089d74a2fSchris 3314fa2dffcSBen Coburn /** 3324fa2dffcSBen Coburn * Generates a two-level table of contents for the config plugin. 3334fa2dffcSBen Coburn * 3344fa2dffcSBen Coburn * @author Ben Coburn <btcoburn@silicodon.net> 335253d4b48SGerrit Uitslag * 336253d4b48SGerrit Uitslag * @return array 3374fa2dffcSBen Coburn */ 33861e35c35SAndreas Gohr public function getTOC() { 339*c6639e6aSAndreas Gohr if (is_null($this->_config)) { $this->_config = new Configuration(self::METADATA); } 340b8595a66SAndreas Gohr $this->setupLocale(true); 341b8595a66SAndreas Gohr 342685bdd2eSBen Coburn $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here. 343685bdd2eSBen Coburn 3444fa2dffcSBen Coburn // gather toc data 345685bdd2eSBen Coburn $has_undefined = false; 3464fa2dffcSBen Coburn $toc = array('conf'=>array(), 'plugin'=>array(), 'template'=>null); 3474fa2dffcSBen Coburn foreach($this->_config->setting as $setting) { 3484fa2dffcSBen Coburn if (is_a($setting, 'setting_fieldset')) { 349*c6639e6aSAndreas Gohr if (substr($setting->_key, 0, 10)=='plugin'.Configuration::KEYMARKER) { 3504fa2dffcSBen Coburn $toc['plugin'][] = $setting; 351*c6639e6aSAndreas Gohr } else if (substr($setting->_key, 0, 7)=='tpl'.Configuration::KEYMARKER) { 3524fa2dffcSBen Coburn $toc['template'] = $setting; 3534fa2dffcSBen Coburn } else { 3544fa2dffcSBen Coburn $toc['conf'][] = $setting; 3554fa2dffcSBen Coburn } 356685bdd2eSBen Coburn } else if (!$has_undefined && is_a($setting, 'setting_undefined')) { 357685bdd2eSBen Coburn $has_undefined = true; 3584fa2dffcSBen Coburn } 3594fa2dffcSBen Coburn } 3604fa2dffcSBen Coburn 361e1b31a95SBen Coburn // build toc 362b8595a66SAndreas Gohr $t = array(); 363b8595a66SAndreas Gohr 364cbfba956SMichael Hamann $check = false; 365cbfba956SMichael Hamann $title = $this->getLang('_configuration_manager'); 366cbfba956SMichael Hamann $t[] = html_mktocitem(sectionID($title, $check), $title, 1); 367b8595a66SAndreas Gohr $t[] = html_mktocitem('dokuwiki_settings', $this->getLang('_header_dokuwiki'), 1); 368253d4b48SGerrit Uitslag /** @var setting $setting */ 369e1b31a95SBen Coburn foreach($toc['conf'] as $setting) { 370e1b31a95SBen Coburn $name = $setting->prompt($this); 371b8595a66SAndreas Gohr $t[] = html_mktocitem($setting->_key, $name, 2); 372e1b31a95SBen Coburn } 373e1b31a95SBen Coburn if (!empty($toc['plugin'])) { 374b8595a66SAndreas Gohr $t[] = html_mktocitem('plugin_settings', $this->getLang('_header_plugin'), 1); 375e1b31a95SBen Coburn } 376e1b31a95SBen Coburn foreach($toc['plugin'] as $setting) { 377e1b31a95SBen Coburn $name = $setting->prompt($this); 378b8595a66SAndreas Gohr $t[] = html_mktocitem($setting->_key, $name, 2); 379e1b31a95SBen Coburn } 380e1b31a95SBen Coburn if (isset($toc['template'])) { 381b8595a66SAndreas Gohr $t[] = html_mktocitem('template_settings', $this->getLang('_header_template'), 1); 382e1b31a95SBen Coburn $setting = $toc['template']; 383e1b31a95SBen Coburn $name = $setting->prompt($this); 384b8595a66SAndreas Gohr $t[] = html_mktocitem($setting->_key, $name, 2); 385e1b31a95SBen Coburn } 386e1b31a95SBen Coburn if ($has_undefined && $allow_debug) { 387b8595a66SAndreas Gohr $t[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1); 388e1b31a95SBen Coburn } 389e1b31a95SBen Coburn 390b8595a66SAndreas Gohr return $t; 3914fa2dffcSBen Coburn } 3924fa2dffcSBen Coburn 393253d4b48SGerrit Uitslag /** 394253d4b48SGerrit Uitslag * @param string $id 395253d4b48SGerrit Uitslag * @param string $text 396253d4b48SGerrit Uitslag */ 39761e35c35SAndreas Gohr protected function _print_h1($id, $text) { 39863e967bdSAnika Henke ptln('<h1 id="'.$id.'">'.$text.'</h1>'); 3994fa2dffcSBen Coburn } 4004fa2dffcSBen Coburn 40161e35c35SAndreas Gohr /** 40261e35c35SAndreas Gohr * Adds a translation to this plugin's language array 40361e35c35SAndreas Gohr * 40461e35c35SAndreas Gohr * @param string $key 40561e35c35SAndreas Gohr * @param string $value 40661e35c35SAndreas Gohr */ 40761e35c35SAndreas Gohr public function addLang($key, $value) { 40861e35c35SAndreas Gohr if (!$this->localised) $this->setupLocale(); 40961e35c35SAndreas Gohr $this->lang[$key] = $value; 41061e35c35SAndreas Gohr } 41110449332Schris} 412