[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Definition of classes used by language customization admin tool 19 * 20 * @package tool 21 * @subpackage customlang 22 * @copyright 2010 David Mudrak <david@moodle.com> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 /** 29 * Provides various utilities to be used by the plugin 30 * 31 * All the public methods here are static ones, this class can not be instantiated 32 */ 33 class tool_customlang_utils { 34 35 /** 36 * Rough number of strings that are being processed during a full checkout. 37 * This is used to estimate the progress of the checkout. 38 */ 39 const ROUGH_NUMBER_OF_STRINGS = 16500; 40 41 /** @var array cache of {@link self::list_components()} results */ 42 protected static $components = null; 43 44 /** 45 * This class can not be instantiated 46 */ 47 private function __construct() { 48 } 49 50 /** 51 * Returns a list of all components installed on the server 52 * 53 * @return array (string)legacyname => (string)frankenstylename 54 */ 55 public static function list_components() { 56 57 $list['moodle'] = 'core'; 58 59 $coresubsystems = core_component::get_core_subsystems(); 60 ksort($coresubsystems); // should be but just in case 61 foreach ($coresubsystems as $name => $location) { 62 $list[$name] = 'core_'.$name; 63 } 64 65 $plugintypes = core_component::get_plugin_types(); 66 foreach ($plugintypes as $type => $location) { 67 $pluginlist = core_component::get_plugin_list($type); 68 foreach ($pluginlist as $name => $ununsed) { 69 if ($type == 'mod') { 70 // Plugin names are now automatically validated. 71 $list[$name] = $type.'_'.$name; 72 } else { 73 $list[$type.'_'.$name] = $type.'_'.$name; 74 } 75 } 76 } 77 78 return $list; 79 } 80 81 /** 82 * Updates the translator database with the strings from files 83 * 84 * This should be executed each time before going to the translation page 85 * 86 * @param string $lang language code to checkout 87 * @param progress_bar $progressbar optionally, the given progress bar can be updated 88 */ 89 public static function checkout($lang, progress_bar $progressbar = null) { 90 global $DB; 91 92 // make sure that all components are registered 93 $current = $DB->get_records('tool_customlang_components', null, 'name', 'name,version,id'); 94 foreach (self::list_components() as $component) { 95 if (empty($current[$component])) { 96 $record = new stdclass(); 97 $record->name = $component; 98 if (!$version = get_component_version($component)) { 99 $record->version = null; 100 } else { 101 $record->version = $version; 102 } 103 $DB->insert_record('tool_customlang_components', $record); 104 } elseif ($version = get_component_version($component)) { 105 if (is_null($current[$component]->version) or ($version > $current[$component]->version)) { 106 $DB->set_field('tool_customlang_components', 'version', $version, array('id' => $current[$component]->id)); 107 } 108 } 109 } 110 unset($current); 111 112 // initialize the progress counter - stores the number of processed strings 113 $done = 0; 114 $strinprogress = get_string('checkoutinprogress', 'tool_customlang'); 115 116 // reload components and fetch their strings 117 $stringman = get_string_manager(); 118 $components = $DB->get_records('tool_customlang_components'); 119 foreach ($components as $component) { 120 $sql = "SELECT stringid, id, lang, componentid, original, master, local, timemodified, timecustomized, outdated, modified 121 FROM {tool_customlang} s 122 WHERE lang = ? AND componentid = ? 123 ORDER BY stringid"; 124 $current = $DB->get_records_sql($sql, array($lang, $component->id)); 125 $english = $stringman->load_component_strings($component->name, 'en', true, true); 126 if ($lang == 'en') { 127 $master =& $english; 128 } else { 129 $master = $stringman->load_component_strings($component->name, $lang, true, true); 130 } 131 $local = $stringman->load_component_strings($component->name, $lang, true, false); 132 133 foreach ($english as $stringid => $stringoriginal) { 134 $stringmaster = isset($master[$stringid]) ? $master[$stringid] : null; 135 $stringlocal = isset($local[$stringid]) ? $local[$stringid] : null; 136 $now = time(); 137 138 if (!is_null($progressbar)) { 139 $done++; 140 $donepercent = floor(min($done, self::ROUGH_NUMBER_OF_STRINGS) / self::ROUGH_NUMBER_OF_STRINGS * 100); 141 $progressbar->update_full($donepercent, $strinprogress); 142 } 143 144 if (isset($current[$stringid])) { 145 $needsupdate = false; 146 $currentoriginal = $current[$stringid]->original; 147 $currentmaster = $current[$stringid]->master; 148 $currentlocal = $current[$stringid]->local; 149 150 if ($currentoriginal !== $stringoriginal or $currentmaster !== $stringmaster) { 151 $needsupdate = true; 152 $current[$stringid]->original = $stringoriginal; 153 $current[$stringid]->master = $stringmaster; 154 $current[$stringid]->timemodified = $now; 155 $current[$stringid]->outdated = 1; 156 } 157 158 if ($stringmaster !== $stringlocal) { 159 $needsupdate = true; 160 $current[$stringid]->local = $stringlocal; 161 $current[$stringid]->timecustomized = $now; 162 } 163 164 if ($needsupdate) { 165 $DB->update_record('tool_customlang', $current[$stringid]); 166 continue; 167 } 168 169 } else { 170 $record = new stdclass(); 171 $record->lang = $lang; 172 $record->componentid = $component->id; 173 $record->stringid = $stringid; 174 $record->original = $stringoriginal; 175 $record->master = $stringmaster; 176 $record->timemodified = $now; 177 $record->outdated = 0; 178 if ($stringmaster !== $stringlocal) { 179 $record->local = $stringlocal; 180 $record->timecustomized = $now; 181 } else { 182 $record->local = null; 183 $record->timecustomized = null; 184 } 185 186 $DB->insert_record('tool_customlang', $record); 187 } 188 } 189 } 190 191 if (!is_null($progressbar)) { 192 $progressbar->update_full(100, get_string('checkoutdone', 'tool_customlang')); 193 } 194 } 195 196 /** 197 * Exports the translator database into disk files 198 * 199 * @param mixed $lang language code 200 */ 201 public static function checkin($lang) { 202 global $DB, $USER, $CFG; 203 require_once($CFG->libdir.'/filelib.php'); 204 205 if ($lang !== clean_param($lang, PARAM_LANG)) { 206 return false; 207 } 208 209 // get all customized strings from updated components 210 $sql = "SELECT s.*, c.name AS component 211 FROM {tool_customlang} s 212 JOIN {tool_customlang_components} c ON s.componentid = c.id 213 WHERE s.lang = ? 214 AND (s.local IS NOT NULL OR s.modified = 1) 215 ORDER BY componentid, stringid"; 216 $strings = $DB->get_records_sql($sql, array($lang)); 217 218 $files = array(); 219 foreach ($strings as $string) { 220 if (!is_null($string->local)) { 221 $files[$string->component][$string->stringid] = $string->local; 222 } 223 } 224 225 fulldelete(self::get_localpack_location($lang)); 226 foreach ($files as $component => $strings) { 227 self::dump_strings($lang, $component, $strings); 228 } 229 230 $DB->set_field_select('tool_customlang', 'modified', 0, 'lang = ?', array($lang)); 231 $sm = get_string_manager(); 232 $sm->reset_caches(); 233 } 234 235 /** 236 * Returns full path to the directory where local packs are dumped into 237 * 238 * @param string $lang language code 239 * @return string full path 240 */ 241 protected static function get_localpack_location($lang) { 242 global $CFG; 243 244 return $CFG->langlocalroot.'/'.$lang.'_local'; 245 } 246 247 /** 248 * Writes strings into a local language pack file 249 * 250 * @param string $component the name of the component 251 * @param array $strings 252 */ 253 protected static function dump_strings($lang, $component, $strings) { 254 global $CFG; 255 256 if ($lang !== clean_param($lang, PARAM_LANG)) { 257 debugging('Unable to dump local strings for non-installed language pack .'.s($lang)); 258 return false; 259 } 260 if ($component !== clean_param($component, PARAM_COMPONENT)) { 261 throw new coding_exception('Incorrect component name'); 262 } 263 if (!$filename = self::get_component_filename($component)) { 264 debugging('Unable to find the filename for the component '.s($component)); 265 return false; 266 } 267 if ($filename !== clean_param($filename, PARAM_FILE)) { 268 throw new coding_exception('Incorrect file name '.s($filename)); 269 } 270 list($package, $subpackage) = core_component::normalize_component($component); 271 $packageinfo = " * @package $package"; 272 if (!is_null($subpackage)) { 273 $packageinfo .= "\n * @subpackage $subpackage"; 274 } 275 $filepath = self::get_localpack_location($lang); 276 $filepath = $filepath.'/'.$filename; 277 if (!is_dir(dirname($filepath))) { 278 check_dir_exists(dirname($filepath)); 279 } 280 281 if (!$f = fopen($filepath, 'w')) { 282 debugging('Unable to write '.s($filepath)); 283 return false; 284 } 285 fwrite($f, <<<EOF 286 <?php 287 288 // This file is part of Moodle - http://moodle.org/ 289 // 290 // Moodle is free software: you can redistribute it and/or modify 291 // it under the terms of the GNU General Public License as published by 292 // the Free Software Foundation, either version 3 of the License, or 293 // (at your option) any later version. 294 // 295 // Moodle is distributed in the hope that it will be useful, 296 // but WITHOUT ANY WARRANTY; without even the implied warranty of 297 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 298 // GNU General Public License for more details. 299 // 300 // You should have received a copy of the GNU General Public License 301 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 302 303 /** 304 * Local language pack from $CFG->wwwroot 305 * 306 $packageinfo 307 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 308 */ 309 310 defined('MOODLE_INTERNAL') || die(); 311 312 313 EOF 314 ); 315 316 foreach ($strings as $stringid => $text) { 317 if ($stringid !== clean_param($stringid, PARAM_STRINGID)) { 318 debugging('Invalid string identifier '.s($stringid)); 319 continue; 320 } 321 fwrite($f, '$string[\'' . $stringid . '\'] = '); 322 fwrite($f, var_export($text, true)); 323 fwrite($f, ";\n"); 324 } 325 fclose($f); 326 @chmod($filepath, $CFG->filepermissions); 327 } 328 329 /** 330 * Returns the name of the file where the component's local strings should be exported into 331 * 332 * @param string $component normalized name of the component, eg 'core' or 'mod_workshop' 333 * @return string|boolean filename eg 'moodle.php' or 'workshop.php', false if not found 334 */ 335 protected static function get_component_filename($component) { 336 if (is_null(self::$components)) { 337 self::$components = self::list_components(); 338 } 339 $return = false; 340 foreach (self::$components as $legacy => $normalized) { 341 if ($component === $normalized) { 342 $return = $legacy.'.php'; 343 break; 344 } 345 } 346 return $return; 347 } 348 349 /** 350 * Returns the number of modified strings checked out in the translator 351 * 352 * @param string $lang language code 353 * @return int 354 */ 355 public static function get_count_of_modified($lang) { 356 global $DB; 357 358 return $DB->count_records('tool_customlang', array('lang'=>$lang, 'modified'=>1)); 359 } 360 361 /** 362 * Saves filter data into a persistant storage such as user session 363 * 364 * @see self::load_filter() 365 * @param stdclass $data filter values 366 * @param stdclass $persistant storage object 367 */ 368 public static function save_filter(stdclass $data, stdclass $persistant) { 369 if (!isset($persistant->tool_customlang_filter)) { 370 $persistant->tool_customlang_filter = array(); 371 } 372 foreach ($data as $key => $value) { 373 if ($key !== 'submit') { 374 $persistant->tool_customlang_filter[$key] = serialize($value); 375 } 376 } 377 } 378 379 /** 380 * Loads the previously saved filter settings from a persistent storage 381 * 382 * @see self::save_filter() 383 * @param stdclass $persistant storage object 384 * @return stdclass filter data 385 */ 386 public static function load_filter(stdclass $persistant) { 387 $data = new stdclass(); 388 if (isset($persistant->tool_customlang_filter)) { 389 foreach ($persistant->tool_customlang_filter as $key => $value) { 390 $data->{$key} = unserialize($value); 391 } 392 } 393 return $data; 394 } 395 } 396 397 /** 398 * Represents the action menu of the tool 399 */ 400 class tool_customlang_menu implements renderable { 401 402 /** @var menu items */ 403 protected $items = array(); 404 405 public function __construct(array $items = array()) { 406 global $CFG; 407 408 foreach ($items as $itemkey => $item) { 409 $this->add_item($itemkey, $item['title'], $item['url'], empty($item['method']) ? 'post' : $item['method']); 410 } 411 } 412 413 /** 414 * Returns the menu items 415 * 416 * @return array (string)key => (object)[->(string)title ->(moodle_url)url ->(string)method] 417 */ 418 public function get_items() { 419 return $this->items; 420 } 421 422 /** 423 * Adds item into the menu 424 * 425 * @param string $key item identifier 426 * @param string $title localized action title 427 * @param moodle_url $url action handler 428 * @param string $method form method 429 */ 430 public function add_item($key, $title, moodle_url $url, $method) { 431 if (isset($this->items[$key])) { 432 throw new coding_exception('Menu item already exists'); 433 } 434 if (empty($title) or empty($key)) { 435 throw new coding_exception('Empty title or item key not allowed'); 436 } 437 $item = new stdclass(); 438 $item->title = $title; 439 $item->url = $url; 440 $item->method = $method; 441 $this->items[$key] = $item; 442 } 443 } 444 445 /** 446 * Represents the translation tool 447 */ 448 class tool_customlang_translator implements renderable { 449 450 /** @const int number of rows per page */ 451 const PERPAGE = 100; 452 453 /** @var int total number of the rows int the table */ 454 public $numofrows = 0; 455 456 /** @var moodle_url */ 457 public $handler; 458 459 /** @var string language code */ 460 public $lang; 461 462 /** @var int page to display, starting with page 0 */ 463 public $currentpage = 0; 464 465 /** @var array of stdclass strings to display */ 466 public $strings = array(); 467 468 /** @var stdclass */ 469 protected $filter; 470 471 public function __construct(moodle_url $handler, $lang, $filter, $currentpage = 0) { 472 global $DB; 473 474 $this->handler = $handler; 475 $this->lang = $lang; 476 $this->filter = $filter; 477 $this->currentpage = $currentpage; 478 479 if (empty($filter) or empty($filter->component)) { 480 // nothing to do 481 $this->currentpage = 1; 482 return; 483 } 484 485 list($insql, $inparams) = $DB->get_in_or_equal($filter->component, SQL_PARAMS_NAMED); 486 487 $csql = "SELECT COUNT(*)"; 488 $fsql = "SELECT s.*, c.name AS component"; 489 $sql = " FROM {tool_customlang_components} c 490 JOIN {tool_customlang} s ON s.componentid = c.id 491 WHERE s.lang = :lang 492 AND c.name $insql"; 493 494 $params = array_merge(array('lang' => $lang), $inparams); 495 496 if (!empty($filter->customized)) { 497 $sql .= " AND s.local IS NOT NULL"; 498 } 499 500 if (!empty($filter->modified)) { 501 $sql .= " AND s.modified = 1"; 502 } 503 504 if (!empty($filter->stringid)) { 505 $sql .= " AND s.stringid = :stringid"; 506 $params['stringid'] = $filter->stringid; 507 } 508 509 if (!empty($filter->substring)) { 510 $sql .= " AND (".$DB->sql_like('s.original', ':substringoriginal', false)." OR 511 ".$DB->sql_like('s.master', ':substringmaster', false)." OR 512 ".$DB->sql_like('s.local', ':substringlocal', false).")"; 513 $params['substringoriginal'] = '%'.$filter->substring.'%'; 514 $params['substringmaster'] = '%'.$filter->substring.'%'; 515 $params['substringlocal'] = '%'.$filter->substring.'%'; 516 } 517 518 if (!empty($filter->helps)) { 519 $sql .= " AND ".$DB->sql_like('s.stringid', ':help', false); //ILIKE 520 $params['help'] = '%\_help'; 521 } else { 522 $sql .= " AND ".$DB->sql_like('s.stringid', ':link', false, true, true); //NOT ILIKE 523 $params['link'] = '%\_link'; 524 } 525 526 $osql = " ORDER BY c.name, s.stringid"; 527 528 $this->numofrows = $DB->count_records_sql($csql.$sql, $params); 529 $this->strings = $DB->get_records_sql($fsql.$sql.$osql, $params, ($this->currentpage) * self::PERPAGE, self::PERPAGE); 530 } 531 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |