|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00026 defined('MOODLE_INTERNAL') || die(); 00027 00033 class tool_customlang_utils { 00034 00039 const ROUGH_NUMBER_OF_STRINGS = 16500; 00040 00042 protected static $components = null; 00043 00047 private function __construct() { 00048 } 00049 00055 public static function list_components() { 00056 00057 $list['moodle'] = 'core'; 00058 00059 $coresubsystems = get_core_subsystems(); 00060 ksort($coresubsystems); // should be but just in case 00061 foreach ($coresubsystems as $name => $location) { 00062 if ($name != 'moodle.org') { 00063 $list[$name] = 'core_'.$name; 00064 } 00065 } 00066 00067 $plugintypes = get_plugin_types(); 00068 foreach ($plugintypes as $type => $location) { 00069 $pluginlist = get_plugin_list($type); 00070 foreach ($pluginlist as $name => $ununsed) { 00071 if ($type == 'mod') { 00072 if (array_key_exists($name, $list)) { 00073 throw new Exception('Activity module and core subsystem name collision'); 00074 } 00075 $list[$name] = $type.'_'.$name; 00076 } else { 00077 $list[$type.'_'.$name] = $type.'_'.$name; 00078 } 00079 } 00080 } 00081 00082 return $list; 00083 } 00084 00093 public static function checkout($lang, progress_bar $progressbar = null) { 00094 global $DB; 00095 00096 // make sure that all components are registered 00097 $current = $DB->get_records('tool_customlang_components', null, 'name', 'name,version,id'); 00098 foreach (self::list_components() as $component) { 00099 if (empty($current[$component])) { 00100 $record = new stdclass(); 00101 $record->name = $component; 00102 if (!$version = get_component_version($component)) { 00103 $record->version = null; 00104 } else { 00105 $record->version = $version; 00106 } 00107 $DB->insert_record('tool_customlang_components', $record); 00108 } elseif ($version = get_component_version($component)) { 00109 if (is_null($current[$component]->version) or ($version > $current[$component]->version)) { 00110 $DB->set_field('tool_customlang_components', 'version', $version, array('id' => $current[$component]->id)); 00111 } 00112 } 00113 } 00114 unset($current); 00115 00116 // initialize the progress counter - stores the number of processed strings 00117 $done = 0; 00118 $strinprogress = get_string('checkoutinprogress', 'tool_customlang'); 00119 00120 // reload components and fetch their strings 00121 $stringman = get_string_manager(); 00122 $components = $DB->get_records('tool_customlang_components'); 00123 foreach ($components as $component) { 00124 $sql = "SELECT stringid, id, lang, componentid, original, master, local, timemodified, timecustomized, outdated, modified 00125 FROM {tool_customlang} s 00126 WHERE lang = ? AND componentid = ? 00127 ORDER BY stringid"; 00128 $current = $DB->get_records_sql($sql, array($lang, $component->id)); 00129 $english = $stringman->load_component_strings($component->name, 'en', true, true); 00130 if ($lang == 'en') { 00131 $master =& $english; 00132 } else { 00133 $master = $stringman->load_component_strings($component->name, $lang, true, true); 00134 } 00135 $local = $stringman->load_component_strings($component->name, $lang, true, false); 00136 00137 foreach ($english as $stringid => $stringoriginal) { 00138 $stringmaster = isset($master[$stringid]) ? $master[$stringid] : null; 00139 $stringlocal = isset($local[$stringid]) ? $local[$stringid] : null; 00140 $now = time(); 00141 00142 if (!is_null($progressbar)) { 00143 $done++; 00144 $donepercent = floor(min($done, self::ROUGH_NUMBER_OF_STRINGS) / self::ROUGH_NUMBER_OF_STRINGS * 100); 00145 $progressbar->update_full($donepercent, $strinprogress); 00146 } 00147 00148 if (isset($current[$stringid])) { 00149 $needsupdate = false; 00150 $currentoriginal = $current[$stringid]->original; 00151 $currentmaster = $current[$stringid]->master; 00152 $currentlocal = $current[$stringid]->local; 00153 00154 if ($currentoriginal !== $stringoriginal or $currentmaster !== $stringmaster) { 00155 $needsupdate = true; 00156 $current[$stringid]->original = $stringoriginal; 00157 $current[$stringid]->master = $stringmaster; 00158 $current[$stringid]->timemodified = $now; 00159 $current[$stringid]->outdated = 1; 00160 } 00161 00162 if ($stringmaster !== $stringlocal) { 00163 $needsupdate = true; 00164 $current[$stringid]->local = $stringlocal; 00165 $current[$stringid]->timecustomized = $now; 00166 } 00167 00168 if ($needsupdate) { 00169 $DB->update_record('tool_customlang', $current[$stringid]); 00170 continue; 00171 } 00172 00173 } else { 00174 $record = new stdclass(); 00175 $record->lang = $lang; 00176 $record->componentid = $component->id; 00177 $record->stringid = $stringid; 00178 $record->original = $stringoriginal; 00179 $record->master = $stringmaster; 00180 $record->timemodified = $now; 00181 $record->outdated = 0; 00182 if ($stringmaster !== $stringlocal) { 00183 $record->local = $stringlocal; 00184 $record->timecustomized = $now; 00185 } else { 00186 $record->local = null; 00187 $record->timecustomized = null; 00188 } 00189 00190 $DB->insert_record('tool_customlang', $record); 00191 } 00192 } 00193 } 00194 00195 if (!is_null($progressbar)) { 00196 $progressbar->update_full(100, get_string('checkoutdone', 'tool_customlang')); 00197 } 00198 } 00199 00205 public static function checkin($lang) { 00206 global $DB, $USER, $CFG; 00207 require_once($CFG->libdir.'/filelib.php'); 00208 00209 if ($lang !== clean_param($lang, PARAM_LANG)) { 00210 return false; 00211 } 00212 00213 // get all customized strings from updated components 00214 $sql = "SELECT s.*, c.name AS component 00215 FROM {tool_customlang} s 00216 JOIN {tool_customlang_components} c ON s.componentid = c.id 00217 WHERE s.lang = ? 00218 AND (s.local IS NOT NULL OR s.modified = 1) 00219 ORDER BY componentid, stringid"; 00220 $strings = $DB->get_records_sql($sql, array($lang)); 00221 00222 $files = array(); 00223 foreach ($strings as $string) { 00224 if (!is_null($string->local)) { 00225 $files[$string->component][$string->stringid] = $string->local; 00226 } 00227 } 00228 00229 fulldelete(self::get_localpack_location($lang)); 00230 foreach ($files as $component => $strings) { 00231 self::dump_strings($lang, $component, $strings); 00232 } 00233 00234 $DB->set_field_select('tool_customlang', 'modified', 0, 'lang = ?', array($lang)); 00235 $sm = get_string_manager(); 00236 $sm->reset_caches(); 00237 } 00238 00245 protected static function get_localpack_location($lang) { 00246 global $CFG; 00247 00248 return $CFG->langlocalroot.'/'.$lang.'_local'; 00249 } 00250 00257 protected static function dump_strings($lang, $component, $strings) { 00258 global $CFG; 00259 00260 if ($lang !== clean_param($lang, PARAM_LANG)) { 00261 debugging('Unable to dump local strings for non-installed language pack .'.s($lang)); 00262 return false; 00263 } 00264 if ($component !== clean_param($component, PARAM_COMPONENT)) { 00265 throw new coding_exception('Incorrect component name'); 00266 } 00267 if (!$filename = self::get_component_filename($component)) { 00268 debugging('Unable to find the filename for the component '.s($component)); 00269 return false; 00270 } 00271 if ($filename !== clean_param($filename, PARAM_FILE)) { 00272 throw new coding_exception('Incorrect file name '.s($filename)); 00273 } 00274 list($package, $subpackage) = normalize_component($component); 00275 $packageinfo = " * @package $package"; 00276 if (!is_null($subpackage)) { 00277 $packageinfo .= "\n * @subpackage $subpackage"; 00278 } 00279 $filepath = self::get_localpack_location($lang); 00280 $filepath = $filepath.'/'.$filename; 00281 if (!is_dir(dirname($filepath))) { 00282 check_dir_exists(dirname($filepath)); 00283 } 00284 00285 if (!$f = fopen($filepath, 'w')) { 00286 debugging('Unable to write '.s($filepath)); 00287 return false; 00288 } 00289 fwrite($f, <<<EOF 00290 <?php 00291 00292 // This file is part of Moodle - http://moodle.org/ 00293 // 00294 // Moodle is free software: you can redistribute it and/or modify 00295 // it under the terms of the GNU General Public License as published by 00296 // the Free Software Foundation, either version 3 of the License, or 00297 // (at your option) any later version. 00298 // 00299 // Moodle is distributed in the hope that it will be useful, 00300 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00301 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00302 // GNU General Public License for more details. 00303 // 00304 // You should have received a copy of the GNU General Public License 00305 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00306 00314 defined('MOODLE_INTERNAL') || die(); 00315 00316 00317 EOF 00318 ); 00319 00320 foreach ($strings as $stringid => $text) { 00321 if ($stringid !== clean_param($stringid, PARAM_STRINGID)) { 00322 debugging('Invalid string identifier '.s($stringid)); 00323 continue; 00324 } 00325 fwrite($f, '$string[\'' . $stringid . '\'] = '); 00326 fwrite($f, var_export($text, true)); 00327 fwrite($f, ";\n"); 00328 } 00329 fclose($f); 00330 } 00331 00338 protected static function get_component_filename($component) { 00339 if (is_null(self::$components)) { 00340 self::$components = self::list_components(); 00341 } 00342 $return = false; 00343 foreach (self::$components as $legacy => $normalized) { 00344 if ($component === $normalized) { 00345 $return = $legacy.'.php'; 00346 break; 00347 } 00348 } 00349 return $return; 00350 } 00351 00358 public static function get_count_of_modified($lang) { 00359 global $DB; 00360 00361 return $DB->count_records('tool_customlang', array('lang'=>$lang, 'modified'=>1)); 00362 } 00363 00371 public static function save_filter(stdclass $data, stdclass $persistant) { 00372 if (!isset($persistant->tool_customlang_filter)) { 00373 $persistant->tool_customlang_filter = array(); 00374 } 00375 foreach ($data as $key => $value) { 00376 if ($key !== 'submit') { 00377 $persistant->tool_customlang_filter[$key] = serialize($value); 00378 } 00379 } 00380 } 00381 00389 public static function load_filter(stdclass $persistant) { 00390 $data = new stdclass(); 00391 if (isset($persistant->tool_customlang_filter)) { 00392 foreach ($persistant->tool_customlang_filter as $key => $value) { 00393 $data->{$key} = unserialize($value); 00394 } 00395 } 00396 return $data; 00397 } 00398 } 00399 00403 class tool_customlang_menu implements renderable { 00404 00406 protected $items = array(); 00407 00408 public function __construct(array $items = array()) { 00409 global $CFG; 00410 00411 foreach ($items as $itemkey => $item) { 00412 $this->add_item($itemkey, $item['title'], $item['url'], empty($item['method']) ? 'post' : $item['method']); 00413 } 00414 } 00415 00421 public function get_items() { 00422 return $this->items; 00423 } 00424 00433 public function add_item($key, $title, moodle_url $url, $method) { 00434 if (isset($this->items[$key])) { 00435 throw new coding_exception('Menu item already exists'); 00436 } 00437 if (empty($title) or empty($key)) { 00438 throw new coding_exception('Empty title or item key not allowed'); 00439 } 00440 $item = new stdclass(); 00441 $item->title = $title; 00442 $item->url = $url; 00443 $item->method = $method; 00444 $this->items[$key] = $item; 00445 } 00446 } 00447 00451 class tool_customlang_translator implements renderable { 00452 00454 const PERPAGE = 100; 00455 00457 public $numofrows = 0; 00458 00460 public $handler; 00461 00463 public $lang; 00464 00466 public $currentpage = 0; 00467 00469 public $strings = array(); 00470 00472 protected $filter; 00473 00474 public function __construct(moodle_url $handler, $lang, $filter, $currentpage = 0) { 00475 global $DB; 00476 00477 $this->handler = $handler; 00478 $this->lang = $lang; 00479 $this->filter = $filter; 00480 $this->currentpage = $currentpage; 00481 00482 if (empty($filter) or empty($filter->component)) { 00483 // nothing to do 00484 $this->currentpage = 1; 00485 return; 00486 } 00487 00488 list($insql, $inparams) = $DB->get_in_or_equal($filter->component, SQL_PARAMS_NAMED); 00489 00490 $csql = "SELECT COUNT(*)"; 00491 $fsql = "SELECT s.id, s.*, c.name AS component"; 00492 $sql = " FROM {tool_customlang_components} c 00493 JOIN {tool_customlang} s ON s.componentid = c.id 00494 WHERE s.lang = :lang 00495 AND c.name $insql"; 00496 00497 $params = array_merge(array('lang' => $lang), $inparams); 00498 00499 if (!empty($filter->customized)) { 00500 $sql .= " AND s.local IS NOT NULL"; 00501 } 00502 00503 if (!empty($filter->modified)) { 00504 $sql .= " AND s.modified = 1"; 00505 } 00506 00507 if (!empty($filter->stringid)) { 00508 $sql .= " AND s.stringid = :stringid"; 00509 $params['stringid'] = $filter->stringid; 00510 } 00511 00512 if (!empty($filter->substring)) { 00513 $sql .= " AND (".$DB->sql_like('s.original', ':substringoriginal', false)." OR 00514 ".$DB->sql_like('s.master', ':substringmaster', false)." OR 00515 ".$DB->sql_like('s.local', ':substringlocal', false).")"; 00516 $params['substringoriginal'] = '%'.$filter->substring.'%'; 00517 $params['substringmaster'] = '%'.$filter->substring.'%'; 00518 $params['substringlocal'] = '%'.$filter->substring.'%'; 00519 } 00520 00521 if (!empty($filter->helps)) { 00522 $sql .= " AND ".$DB->sql_like('s.stringid', ':help', false); //ILIKE 00523 $params['help'] = '%\_help'; 00524 } else { 00525 $sql .= " AND ".$DB->sql_like('s.stringid', ':link', false, true, true); //NOT ILIKE 00526 $params['link'] = '%\_link'; 00527 } 00528 00529 $osql = " ORDER BY c.name, s.stringid"; 00530 00531 $this->numofrows = $DB->count_records_sql($csql.$sql, $params); 00532 $this->strings = $DB->get_records_sql($fsql.$sql.$osql, $params, ($this->currentpage) * self::PERPAGE, self::PERPAGE); 00533 } 00534 }