[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/admin/ -> lang.php (source)

   1  <?PHP // $Id: lang.php,v 1.106.2.11 2008/07/21 15:21:51 mudrd8mz Exp $
   2      /**
   3      * Display the admin/language menu and process strings translation.
   4      *
   5      * @param string $mode the mode of the script: null, "compare", "missing"
   6      * @param string $currentfile the filename of the English file to edit (if mode==compare)
   7      * @param bool $uselocal save translations into *_local pack?
   8      */
   9  
  10      $dbg = '';  // debug output;
  11  
  12      require_once ('../config.php');
  13      require_once($CFG->libdir.'/adminlib.php');
  14  
  15      admin_externalpage_setup('langedit');
  16  
  17      $context = get_context_instance(CONTEXT_SYSTEM);
  18  
  19      define('LANG_SUBMIT_REPEAT', 1);            // repeat displaying submit button?
  20      define('LANG_SUBMIT_REPEAT_EVERY', 20);     // if so, after how many lines?
  21      define('LANG_DISPLAY_MISSING_LINKS', 1);    // display "go to first/next missing string" links?
  22      define('LANG_DEFAULT_FILE', '');            // default file to translate. Empty allowed
  23      define('LANG_DEFAULT_HELPFILE', '');        // default helpfile to translate. Empty allowed
  24      define('LANG_LINK_MISSING_STRINGS', 1);     // create links from "missing" page to "compare" page?
  25      define('LANG_DEFAULT_USELOCAL', 0);         // should *_utf8_local be used by default?
  26      define('LANG_MISSING_TEXT_MAX_LEN', 60);    // maximum length of the missing text to display
  27      define('LANG_KEEP_ORPHANS', 1);             // keep orphaned strings (i.e. strings w/o English reference)
  28      define('LANG_SEARCH_EXTRA', 1);             // search lang files in extra locations
  29      define('LANG_ALWAYS_TEXTAREA', 1);          // always use <textarea> even for short strings MDL-15738
  30  
  31      $mode = optional_param('mode', '', PARAM_ALPHA);
  32      if ($mode == 'helpfiles') {
  33          // use different PARAM_ options according to mode
  34          $currentfile = optional_param('currentfile', LANG_DEFAULT_HELPFILE, PARAM_PATH);
  35      } else {
  36          $currentfile = optional_param('currentfile', LANG_DEFAULT_FILE, PARAM_FILE);
  37      }
  38      $uselocal = optional_param('uselocal', -1, PARAM_INT);
  39  
  40      if ($uselocal == -1) {
  41          if (isset($SESSION->langtranslateintolocal)) {
  42              $uselocal = $SESSION->langtranslateintolocal;
  43          } else {
  44              $uselocal = LANG_DEFAULT_USELOCAL;
  45          }
  46      } else {
  47          $SESSION->langtranslateintolocal = $uselocal;
  48      }
  49  
  50      if (!has_capability('moodle/site:langeditmaster', $context, $USER->id, false)) {
  51          // Force using _local
  52          $uselocal = 1;
  53      }
  54  
  55      if (!has_capability('moodle/site:langeditmaster', $context, $USER->id, false) && (!$uselocal)) {
  56          print_error('cannoteditmasterlang');
  57      }
  58  
  59      if ((!has_capability('moodle/site:langeditlocal', $context, $USER->id, false)) && ($uselocal)) {
  60          print_error('cannotcustomizelocallang');
  61      }
  62  
  63      $strlanguage = get_string("language");
  64      $strcurrentlanguage = get_string("currentlanguage");
  65      $strmissingstrings = get_string("missingstrings");
  66      $streditstrings = get_string("editstrings", 'admin');
  67      $stredithelpdocs = get_string("edithelpdocs", 'admin');
  68      $strthislanguage = get_string("thislanguage");
  69      $strgotofirst = get_string('gotofirst','admin');
  70      $strfilestoredin = get_string('filestoredin', 'admin');
  71      $strfilestoredinhelp = get_string('filestoredinhelp', 'admin');
  72      $strswitchlang = get_string('switchlang', 'admin');
  73      $strchoosefiletoedit = get_string('choosefiletoedit', 'admin');
  74      $streditennotallowed = get_string('langnoeditenglish', 'admin');
  75      $strfilecreated = get_string('filecreated', 'admin');
  76      $strprev = get_string('previous');
  77      $strnext = get_string('next');
  78      $strlocalstringcustomization = get_string('localstringcustomization', 'admin');
  79      $strlangpackmaintaining = get_string('langpackmaintaining', 'admin');
  80      $strnomissingstrings = get_string('nomissingstrings', 'admin');
  81      $streditingnoncorelangfile = get_string('editingnoncorelangfile', 'admin');
  82      $strlanglocalpackage = get_string('langlocalpackage', 'admin');
  83      $strlangmasterpackage = get_string('langmasterpackage', 'admin');
  84      $strlangmasterenglish = get_string('langmasterenglish', 'admin');
  85  
  86      $currentlang = current_language();
  87  
  88      switch ($mode) {
  89          case "missing":
  90              // Missing array keys are not bugs here but missing strings
  91              error_reporting(E_ALL ^ E_NOTICE);
  92              $title = $strmissingstrings;
  93              break;
  94          case "compare":
  95              $title = $streditstrings;
  96              break;
  97          case "helpfiles":
  98              $title = $stredithelpdocs;
  99          default:
 100              $title = $strlanguage;
 101              break;
 102      }
 103      $navlinks[] = array('name' => $strlanguage, 'link' => "$CFG->wwwroot/$CFG->admin/lang.php", 'type' => 'misc');
 104      $navigation = build_navigation($navlinks);
 105  
 106      admin_externalpage_print_header();
 107  
 108      // Prepare and render menu tabs
 109      $firstrow = array();
 110      $secondrow = array();
 111      $inactive = NULL;
 112      $activated = NULL;
 113      $currenttab = $mode;
 114      if ($uselocal) {
 115          $inactive = array('uselocal');
 116          $activated = array('uselocal');
 117      } else {
 118          $inactive = array('usemaster');
 119          $activated = array('usemaster');
 120      }
 121      if (has_capability('moodle/site:langeditlocal', $context, $USER->id, false)) {
 122          $firstrow[] = new tabobject('uselocal',
 123              "$CFG->wwwroot/$CFG->admin/lang.php?mode=$mode&amp;currentfile=$currentfile&amp;uselocal=1",
 124              $strlocalstringcustomization );
 125      }
 126      if (has_capability('moodle/site:langeditmaster', $context, $USER->id, false)) {
 127          $firstrow[] = new tabobject('usemaster',
 128              "$CFG->wwwroot/$CFG->admin/lang.php?mode=$mode&amp;currentfile=$currentfile&amp;uselocal=0",
 129              $strlangpackmaintaining );
 130      }
 131      $secondrow[] = new tabobject('missing', "$CFG->wwwroot/$CFG->admin/lang.php?mode=missing", $strmissingstrings );
 132      $secondrow[] = new tabobject('compare', "$CFG->wwwroot/$CFG->admin/lang.php?mode=compare", $streditstrings );
 133      $secondrow[] = new tabobject('helpfiles', "$CFG->wwwroot/$CFG->admin/lang.php?mode=helpfiles", $stredithelpdocs );
 134      $tabs = array($firstrow, $secondrow);
 135      print_tabs($tabs, $currenttab, $inactive, $activated);
 136  
 137  
 138      if (!$mode) {
 139          // TODO this is a very nice place to put some translation statistics
 140          print_box_start();
 141          $currlang = current_language();
 142          $langs = get_list_of_languages(false, true);
 143          popup_form ("$CFG->wwwroot/$CFG->admin/lang.php?lang=", $langs, "chooselang", $currlang, "", "", "", false, 'self', $strcurrentlanguage.':');
 144          print_box_end();
 145          admin_externalpage_print_footer();
 146          exit;
 147      }
 148  
 149      // Get a list of all the root files in the English directory
 150  
 151      $langbase = $CFG->dataroot . '/lang';
 152      $enlangdir = "$CFG->dirroot/lang/en_utf8";
 153      if ($currentlang == 'en_utf8') {
 154          $langdir = $enlangdir;
 155      } else {
 156          $langdir = "$langbase/$currentlang";
 157      }
 158      $locallangdir = "$langbase/{$currentlang}_local";
 159      $saveto = $uselocal ? $locallangdir : $langdir;
 160  
 161      if (($mode == 'missing') || ($mode == 'compare')) {
 162          // get the list of all English stringfiles
 163          $stringfiles = lang_standard_locations();
 164          if (LANG_SEARCH_EXTRA) {
 165              $stringfiles += lang_extra_locations();
 166          }
 167          if (count($stringfiles) == 0) {
 168              error("Could not find English language pack!");
 169          }
 170      } elseif ($mode == 'helpfiles') {
 171          $helpfiles = lang_help_standard_locations();
 172          if (LANG_SEARCH_EXTRA) {
 173              $helpfiles += lang_help_extra_locations();
 174          }
 175          if (count($helpfiles) == 0) {
 176              error("Could not find help files in the English language pack!");
 177          }
 178      }
 179  
 180  
 181  
 182      if ($mode == 'missing') {
 183          if (!file_exists($langdir)) {
 184              error ('to edit this language pack, you need to put it in '.$CFG->dataroot.'/lang');
 185          }
 186  
 187          // Following variables store the HTML output to be echo-ed
 188          $m = '';
 189          $o = '';
 190  
 191          $m_x = false;
 192  
 193          // Total number of strings and missing strings
 194          $totalcounter->strings = 0;
 195          $totalcounter->missing = 0;       
 196  
 197          // For each file, check that a counterpart exists, then check all the strings
 198          foreach ($stringfiles as $stringfile) {
 199              $location = $stringfile['location'];
 200              $plugin = $stringfile['plugin'];
 201              $prefix = $stringfile['prefix'];
 202              $filename = $stringfile['filename'];
 203              unset($string);
 204              
 205              // Get some information about file locations:
 206              //  $enfilepath = the path to the English file distributed either in the core space or in plugin space
 207              //  $trfilepath = the path to the translated file distributed either in the lang pack or in plugin space
 208              //  $lcfilepath = the path to the _local customization
 209              //  $trfilename = the filename of the translated version of the file (including prefix for non-core files)
 210              if ($location || $plugin) {
 211                  // non-core file in an extra location
 212                  $enfilepath = "$CFG->dirroot/$location/$plugin/lang/en_utf8/$filename";
 213                  $trfilepath = "$CFG->dirroot/$location/$plugin/lang/$currentlang/$filename";
 214                  $lcfilepath = "$locallangdir/$filename";
 215                  $trfilename = $filename;
 216                  if (!$m_x) {
 217                      $m .= '<hr />';
 218                      $m_x = true;
 219                  }
 220              } else {
 221                  // core file in standard location
 222                  $enfilepath = "$CFG->dirroot/lang/en_utf8/$filename";
 223                  $trfilepath = "$langdir/$filename";
 224                  $lcfilepath = "$locallangdir/$filename";
 225                  $trfilename = $filename;
 226              }
 227              // $enstring = English strings distributed either in the core space or in plugin space
 228              include($enfilepath);
 229              $enstring = isset($string) ? $string : array();
 230              unset($string);
 231              ksort($enstring);
 232              
 233              //$lcstring = local customizations
 234              $lcstring = array();
 235              if (file_exists($lcfilepath)) {
 236                  include($lcfilepath);
 237                  $localfileismissing = 0;
 238                  if (isset($string) && is_array($string)) {
 239                      $lcstring = $string;
 240                  }
 241                  unset($string);
 242                  ksort($lcstring);
 243              } else {
 244                  $localfileismissing = 1;
 245              }
 246  
 247              // $string = translated strings distibuted either in core lang pack or in plugin space
 248              $string = array();
 249              if (file_exists($trfilepath)) {
 250                  include($trfilepath);
 251                  $fileismissing = 0;
 252              } else {
 253                  $fileismissing = 1;
 254                  $o .= notify(get_string("filemissing", "", $trfilepath), "notifyproblem", "center", true);
 255              }
 256  
 257              $missingcounter = 0;
 258  
 259              $first = true; // first missing string found in the file
 260              // For all English strings in the current file check distributed translations and _local customizations
 261              foreach ($enstring as $key => $value) {
 262                  $totalcounter->strings++;
 263                  $missingstring = false;
 264                  $missinglocalstring = false;
 265                  $translationsdiffer = false;
 266                  if (empty($string[$key]) and $string[$key] != "0") { // MDL-4735
 267                      // string is missing in distributed pack
 268                      $missingstring = true;
 269                  }
 270                  if (empty($lcstring[$key]) and $lcstring[$key] != "0") { // MDL-4735
 271                      // string is missing in _local customization
 272                      $missinglocalstring = true;
 273                  }
 274                  if (!$missingstring && !$missinglocalstring && ($lcstring[$key] != $string[$key])) {
 275                      $translationsdiffer = true;
 276                  }
 277                  if ($missingstring || $translationsdiffer) {
 278                      $value = htmlspecialchars($value);
 279                      $value = str_replace("$"."a", "\\$"."a", $value);
 280                      $value = str_replace("%%","%",$value);
 281                      if ($first) {
 282                          $m .= "<a href=\"lang.php?mode=missing#$trfilename\">$trfilename";
 283                          $m .= $fileismissing ? '*' : '';
 284                          $m .= '</a> &nbsp; ';
 285                          $o .= "<p><a name=\"$trfilename\"></a><b>".
 286                              get_string("stringsnotset","", $trfilepath)."</b></p><pre>";
 287                          $first = false;
 288                          $somethingfound = true;
 289                      }
 290                      if ($missingstring) {
 291                          $missingcounter++;
 292                          $totalcounter->missing++;
 293                      }
 294                      if ($translationsdiffer) {
 295                          $missingcounter++;
 296                      }
 297                      if (LANG_LINK_MISSING_STRINGS && ($missingstring || $translationsdiffer)) {
 298                          $missinglinkstart = "<a href=\"lang.php?mode=compare&amp;currentfile=$filename#$key\">";
 299                          $missinglinkend = '</a>';
 300                      } else {
 301                          $missinglinkstart = '';
 302                          $missinglinkend = '';
 303                      }
 304                      if (strlen($value) > LANG_MISSING_TEXT_MAX_LEN) {
 305                          $value = lang_xhtml_save_substr($value, 0, LANG_MISSING_TEXT_MAX_LEN) . ' ...'; // MDL-8852
 306                      }
 307                      if ($translationsdiffer) {
 308                          $o .= '// ';
 309                      }
 310                      $o .= "$"."string['".$missinglinkstart.$key.$missinglinkend."'] = \"$value\";";
 311                      if ($translationsdiffer) {
 312                          $o .= '    // differs from the translation in _local';
 313                      } elseif (!$missinglocalstring) {
 314                          $o .= '    // translated only in _local';
 315                      }
 316                      $o .= "\n";
 317                  }
 318              }
 319              if (!$first) {
 320                  $o .= '</pre><hr />';
 321              }
 322          }
 323  
 324          if ($totalcounter->missing > 0) {
 325              $totalcounter->missingpercent = sprintf('%02.1f', ($totalcounter->missing / $totalcounter->strings * 100));
 326              print_heading(get_string('numberofstrings', 'admin', $totalcounter), '', 4);
 327          } else {
 328              print_heading($strnomissingstrings, '', 4, 'notifysuccess');
 329          }
 330  
 331          if ($m <> '') {
 332              print_box($m, 'filenames');
 333          }
 334  
 335          echo $o;
 336  
 337          if (! $files = get_directory_list("$CFG->dirroot/lang/en_utf8/help", "CVS")) {
 338              error("Could not find English language help files!");
 339          }
 340  
 341          foreach ($files as $filekey => $file) {    // check all the help files.
 342              if (!file_exists("$langdir/help/$file")) {
 343                  notify(get_string("filemissing", "", "$langdir/help/$file"), 'notifyproblem');
 344                  $somethingfound = true;
 345                  continue;
 346              }
 347          }
 348  
 349          if (! $files = get_directory_list("$CFG->dirroot/lang/en_utf8/docs", "CVS")) {
 350              error("Could not find English language docs files!");
 351          }
 352          foreach ($files as $filekey => $file) {    // check all the docs files.
 353              if (!file_exists("$langdir/docs/$file")) {
 354                  notify(get_string("filemissing", "", "$langdir/docs/$file"), 'notifyproblem');
 355                  $somethingfound = true;
 356                  continue;
 357              }
 358          }
 359  
 360          if (!empty($somethingfound)) {
 361              print_continue("lang.php");
 362          } else {
 363              notice(get_string("languagegood"), "lang.php" );
 364          }
 365  
 366      } else if ($mode == 'compare') {
 367  
 368          if (!file_exists($langbase) ){
 369              if (!lang_make_directory($langbase) ){
 370                  error('ERROR: Could not create base lang directory ' . $langbase);
 371              } else {
 372                  echo '<div class="notifysuccess">Created directory '.
 373                                                       $langbase .'</div>'."<br />\n";
 374              }
 375          }
 376          if (!$uselocal && !file_exists($langdir)) {
 377              if (!lang_make_directory($langdir)) {
 378                  error('ERROR: Could not create directory '.$langdir);
 379              } else {
 380                  echo '<div class="notifysuccess">Created directory '.
 381                                                       $langdir .'</div>'."<br />\n";
 382              }
 383          }
 384          if ($uselocal && !file_exists($locallangdir)) {
 385              if (!lang_make_directory($locallangdir)) {
 386                  echo '<div class="notifyproblem">ERROR: Could not create directory '.
 387                                       $locallangdir .'</div>'."<br />\n";
 388                  $uselocal = 0;
 389              } else {
 390                  echo '<div class="notifysuccess">Created directory '.
 391                                                       $locallangdir .'</div>'."<br />\n";
 392              }
 393          }
 394  
 395          if ($currentfile <> '') {
 396              if (!$fileinfo = lang_get_file_info($currentfile, $stringfiles)) {
 397                  error('Unable to find info for: '.$currentfile);
 398              }
 399              // check the filename is set up correctly, prevents bugs similar to MDL-10920
 400              $location = $fileinfo['location'];
 401              $plugin = $fileinfo['plugin'];
 402              $prefix = $fileinfo['prefix'];
 403              $filename = $fileinfo['filename'];
 404              if ($location || $plugin) {
 405                  // file in an extra location
 406                  if ($currentfile != "{$prefix}{$plugin}.php") {
 407                      error("Non-core filename mismatch. The file $currentfile should be {$prefix}{$plugin}.php");
 408                  }
 409                  if (!$uselocal) {
 410                      notify($streditingnoncorelangfile);
 411                      $editable = false;
 412                  }
 413              } else {
 414                  // file in standard location
 415                  if ($currentfile != $filename) {
 416                      error("Core filename mismatch. The file $currentfile should be $filename");
 417                  }
 418              }
 419  
 420              // Get some information about file locations:
 421              //  $enfilepath = the path to the English file distributed either in the core space or in plugin space
 422              //  $trfilepath = the path to the translated file distributed either in the lang pack or in plugin space
 423              //  $lcfilepath = the path to the _local customization
 424              //  $trfilename = the filename of the translated version of the file (including prefix for non-core files)
 425              if ($location || $plugin) {
 426                  // non-core file in an extra location
 427                  $enfilepath = "$CFG->dirroot/$location/$plugin/lang/en_utf8/$filename";
 428                  $trfilepath = "$CFG->dirroot/$location/$plugin/lang/$currentlang/$filename";
 429                  $lcfilepath = "$locallangdir/$filename";
 430                  $trfilename = $filename;
 431              } else {
 432                  // core file in standard location
 433                  $enfilepath = "$CFG->dirroot/lang/en_utf8/$filename";
 434                  $trfilepath = "$langdir/$filename";
 435                  $lcfilepath = "$locallangdir/$filename";
 436                  $trfilename = $filename;
 437              }
 438          }
 439  
 440          if (isset($_POST['currentfile'])){   // Save a file
 441              if (!confirm_sesskey()) {
 442                  print_error('confirmsesskeybad', 'error');
 443              }
 444  
 445              $newstrings = array();
 446  
 447              foreach ($_POST as $postkey => $postval) {
 448                  $stringkey = lang_file_string_key($postkey);
 449                  $newstrings[$stringkey] = $postval;
 450              }
 451  
 452              unset($newstrings['currentfile']);
 453  
 454              $packstring = array();
 455              $saveinto = $langdir;
 456              if ($uselocal) {
 457                  if(file_exists($trfilepath)) {
 458                      include($trfilepath);
 459                      if (isset($string)) {
 460                          $packstring = $string;
 461                      }
 462                      unset($string);
 463                  }
 464                  $saveinto = $locallangdir;
 465              }
 466               
 467              if (lang_save_file($saveinto, $currentfile, $newstrings, $uselocal, $packstring)) {
 468                  notify(get_string("changessaved")." ($saveinto/$currentfile)", "notifysuccess");
 469              } else {
 470                  error("Could not save the file '$saveinto/$currentfile'!", "lang.php?mode=compare&amp;currentfile=$currentfile");
 471              }
 472              unset($packstring);
 473          }
 474  
 475          print_box_start('generalbox editstrings');
 476          $menufiles = array();
 477          $menufiles_coregrp = 1;
 478          foreach ($stringfiles as $stringfile) {
 479              $item_key = $stringfile['filename'];
 480              $item_label = $stringfile['filename'];
 481              if ($stringfile['location'] != '' && $stringfile['plugin'] != '') {
 482                  $item_label .= ' ('.$stringfile['location'].'/'.$stringfile['plugin'].')';
 483                  if ($menufiles_coregrp == 1) {
 484                      $menufiles['extra'] = '------------';
 485                      $menufiles_coregrp = 0;
 486                  }
 487              }
 488              $menufiles[$item_key] = $item_label;
 489          }
 490          $selectionlabel = '<code class="path">';
 491          //$selectionlabel .= $strfilestoredin;
 492          $selectionlabel .= $uselocal ? "{$currentlang}_local" : $currentlang;
 493          $selectionlabel .= '/</code>';
 494          popup_form("$CFG->wwwroot/$CFG->admin/lang.php?mode=compare&amp;currentfile=", $menufiles, "choosefile",
 495              $currentfile, $strchoosefiletoedit, '', '', false, 'self', $selectionlabel);
 496          helpbutton('langswitchstorage', $strfilestoredinhelp, 'moodle');
 497          print_box_end();
 498          
 499          if ($currentfile <> '') {
 500              error_reporting(0);
 501              if (!isset($editable) || $editable) {
 502                  if (!file_exists("$saveto/$currentfile")) {
 503                      if (!@touch("$saveto/$currentfile")) {
 504                          print_heading(get_string("filemissing", "", "$saveto/$currentfile"), '', 4, 'error');
 505                      } else {
 506                          print_heading($strfilecreated, '', 4, 'notifysuccess');
 507                      }
 508                  }
 509                  if ($currentlang == "en_utf8" && !$uselocal) {
 510                      $editable = false;
 511                      print_heading($streditennotallowed, '', 4);
 512                  } elseif ($f = fopen("$saveto/$currentfile","r+")) {
 513                      $editable = true;
 514                      fclose($f);
 515                  } else {
 516                      $editable = false;
 517                      notify(get_string("makeeditable", "", "$saveto/$currentfile"), 'notifyproblem');
 518                  }
 519              }
 520              error_reporting($CFG->debug);
 521  
 522              $o = '';    // stores the HTML output to be echo-ed
 523              
 524              unset($string);
 525              include($enfilepath);
 526              $enstring = isset($string) ? $string : array();
 527              //
 528              // Following strings have moved into langconfig.php, but keep the here for backward compatibility
 529              //
 530              if ($currentlang != 'en' and $currentfile == 'moodle.php') {
 531                  $enstring['thislanguage'] = "<< TRANSLATORS: Specify the name of your language here.  If possible use Unicode Numeric Character References >>";
 532                  $enstring['thischarset'] = "<< TRANSLATORS:  Charset encoding - always use utf-8 >>";
 533                  $enstring['thisdirection'] = "<< TRANSLATORS: This string specifies the direction of your text, either left-to-right or right-to-left.  Insert either 'ltr' or 'rtl' here. >>";
 534                  $enstring['parentlanguage'] = "<< TRANSLATORS: If your language has a Parent Language that Moodle should use when strings are missing from your language pack, then specify the code for it here.  If you leave this blank then English will be used.  Example: nl >>";
 535              }
 536              unset($string);
 537              ksort($enstring);
 538  
 539              @include($lcfilepath);
 540              $localstring = isset($string) ? $string : array();
 541              unset($string);
 542              ksort($localstring);
 543  
 544              @include($trfilepath);
 545              $string = isset($string) ? $string : array();
 546              ksort($string);
 547  
 548              if ($editable) {
 549                  $o .= "<form id=\"$currentfile\" action=\"lang.php\" method=\"post\">";
 550                  $o .= '<div>';
 551              }
 552              $o .= "<table summary=\"\" width=\"100%\" class=\"translator\">";
 553              $linescounter = 0;
 554              $missingcounter = 0;
 555              foreach ($enstring as $key => $envalue) {
 556                  $linescounter++ ;
 557                  if (LANG_SUBMIT_REPEAT &&  $editable && $linescounter % LANG_SUBMIT_REPEAT_EVERY == 0) {
 558                      $o .= '<tr><td>&nbsp;</td><td><br />';
 559                      $o .= '<input type="submit" tabindex="'.$missingcounter.'" name="update" value="'.get_string('savechanges').': '.$currentfile.'" />';
 560                      $o .= '<br />&nbsp;</td></tr>';
 561                  }
 562                  $envalue = nl2br(htmlspecialchars($envalue));
 563                  $envalue = preg_replace('/(\$a\-\&gt;[a-zA-Z0-9]*|\$a)/', '<b>$0</b>', $envalue);  // Make variables bold.
 564                  $envalue = str_replace("%%","%",$envalue);
 565                  $envalue = str_replace("\\","",$envalue);              // Delete all slashes
 566  
 567                  $o .= "\n\n".'<tr class="';
 568                  if ($linescounter % 2 == 0) {
 569                      $o .= 'r0';
 570                  } else {
 571                      $o .= 'r1';
 572                  }
 573                  $o .= '">';
 574                  $o .= '<td dir="ltr" lang="en">';
 575                  $o .= '<span id="'.$key.'" class="stren">'.$envalue.'</span>';
 576                  $o .= '<br />'."\n";
 577                  $o .= '<span class="strkey">'.$key.'</span>';
 578                  $o .= '</td>'."\n";
 579  
 580                  // Missing array keys are not bugs here but missing strings
 581                  error_reporting(E_ALL ^ E_NOTICE);
 582                  if ($uselocal) {
 583                      $value = lang_fix_value_from_file($localstring[$key]);
 584                      $value2 = lang_fix_value_from_file($string[$key]);
 585                      if ($value == '') {
 586                          $value = $value2;
 587                      }
 588                  } else {
 589                      $value = lang_fix_value_from_file($string[$key]);
 590                      $value2 = lang_fix_value_from_file($localstring[$key]);
 591                  }
 592                  error_reporting($CFG->debug);
 593                  $missingtarget = '';
 594                  $missingnext = '';
 595                  $missingprev = '';
 596                  $cellcolour = '';
 597                  $usetabindex = false;
 598                  if (!$value) {
 599                      // the string is not present in the pack being processed
 600                      if (!$value2) {
 601                          $cellcolour = 'class="bothmissing"';
 602                          $usetabindex = true;
 603                      } else {
 604                          $cellcolour = 'class="mastermissing"';
 605                          $usetabindex = true;
 606                      }
 607                      $missingcounter++;
 608                      if (LANG_DISPLAY_MISSING_LINKS) {
 609                          $missingtarget = '<a name="missing'.$missingcounter.'"></a>';
 610                          $missingnext = '<a href="#missing'.($missingcounter+1).'">'.
 611                          '<img src="' . $CFG->pixpath . '/t/down.gif" class="iconsmall" alt="'.$strnext.'" /></a>';
 612                          $missingprev = '<a href="#missing'.($missingcounter-1).'">'.
 613                          '<img src="' . $CFG->pixpath . '/t/up.gif" class="iconsmall" alt="'.$strprev.'" /></a>';
 614                      }
 615                  } else {
 616                      // the string is translated in the pack being processed
 617                      if ($value <> $value2 && ($value2 <> '')) {
 618                          $cellcolour = 'class="localdifferent"';
 619                          $usetabindex = true;
 620                          $missingcounter++;
 621                          if (LANG_DISPLAY_MISSING_LINKS) {
 622                              $missingtarget = '<a name="missing'.$missingcounter.'"></a>';
 623                              $missingnext = '<a href="#missing'.($missingcounter+1).'">'.
 624                              '<img src="' . $CFG->pixpath . '/t/down.gif" class="iconsmall" alt="'.$strnext.'" /></a>';
 625                              $missingprev = '<a href="#missing'.($missingcounter-1).'">'.
 626                              '<img src="' . $CFG->pixpath . '/t/up.gif" class="iconsmall" alt="'.$strprev.'" /></a>';
 627                          }
 628                      }
 629                  }
 630  
 631                  if ($editable) {
 632                      $o .= '<td '.$cellcolour.' valign="top">';
 633                      if ($missingcounter > 1) {
 634                          $o .= $missingprev;
 635                      }
 636                      $o .= $missingtarget."\n";
 637                      if (isset($string[$key])) {
 638                          $valuelen = strlen($value);
 639                      } else {
 640                          $valuelen = strlen($envalue);
 641                      }
 642                      $cols=40;
 643                      if ($usetabindex) {
 644                          $tabindex = 'tabindex="'.$missingcounter.'"';
 645                      } else {
 646                          $tabindex = '';
 647                      }
 648                      if (strstr($value, "\r") or strstr($value, "\n") or $valuelen > $cols) {
 649                          $rows = ceil($valuelen / $cols);
 650                          $o .= '<textarea name="stringXXX'.lang_form_string_key($key).'" cols="'.$cols.'" rows="'.$rows.'" '.$tabindex.'>'.$value.'</textarea>'."\n";
 651                      } else {
 652                          if ($valuelen) {
 653                              $cols = $valuelen + 5;
 654                          }
 655                          if (LANG_ALWAYS_TEXTAREA) {
 656                              $o .= '<textarea name="stringXXX'.lang_form_string_key($key).'" cols="'.$cols.'" rows="1" '.$tabindex.'>'.$value.'</textarea>'."\n";
 657                          } else {
 658                              $o .= '<input type="text" name="stringXXX'.lang_form_string_key($key).'" value="'.$value.'" size="'.$cols.'" '.$tabindex.' />';
 659                          }
 660                      }
 661                      if ($value2 <> '' && $value <> $value2) {
 662                          $o .= '<br /><span style="font-size:small">'.$value2.'</span>';
 663                      }
 664                      $o .= $missingnext . '</td>';
 665  
 666                  } else {
 667                      $o .= '<td '.$cellcolour.' valign="top">'.$value.'<br />'.$value2.'</td>';
 668                  }
 669                  $o .= '</tr>'."\n";
 670              }
 671              if ($editable) {
 672                  $o .= '<tr><td>&nbsp;</td><td><br />';
 673                  $o .= '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
 674                  $o .= '<input type="hidden" name="currentfile" value="'.$currentfile.'" />';
 675                  $o .= '<input type="hidden" name="mode" value="compare" />';
 676                  $o .= '<input type="submit" name="update" tabindex="'.$missingcounter.'" value="'.get_string('savechanges').': '.$currentfile.'" />';
 677                  $o .= '</td></tr>';
 678              }
 679              $o .= '</table>';
 680              if ($editable) {
 681                  $o .= '</div>';
 682                  $o .= '</form>';
 683              }
 684  
 685              if (LANG_DISPLAY_MISSING_LINKS) {
 686                  if ($missingcounter > 0) {
 687                      print_heading(get_string('numberofmissingstrings', 'admin', $missingcounter), '', 4);
 688                      if ($editable) {
 689                          print_heading('<a href="#missing1">'.$strgotofirst.'</a>', "", 4);
 690                      }
 691                  } else {
 692                      print_heading($strnomissingstrings, '', 4, 'notifysuccess');
 693                  }
 694              }
 695              echo $o;
 696  
 697          } else {
 698              // no $currentfile specified
 699              // no useful information to display - maybe some help? instructions?
 700          }
 701  
 702      } elseif ($mode == 'helpfiles') {
 703  
 704          $saveto = $saveto.'/help';                      // the edited content will be saved to
 705          $enlangdir = $enlangdir.'/help';                // English master help files localtion
 706          $langdir = $langdir.'/help';                    // current language master help files location
 707          $locallangdir = $locallangdir.'/help';          // local modifications of help files location
 708          $altdir = $uselocal ? $langdir : $locallangdir; // alternative to $saveto
 709  
 710          $fileeditorrows = 10;           // number of textareas' rows
 711          $fileeditorcols = 100;          // dtto cols
 712          $filemissingmark = ' (***)';    // mark to add to non-existing or zero-length files
 713          $fileoldmark = ' (old?)';       // mark to add to filenames in selection form if the English version is newer
 714          $filetemplate = '';             // template for new files, e.g. CVS identification
 715  
 716          if (isset($_POST['currentfile'])) {  // Save a file
 717              if (!confirm_sesskey()) {
 718                  print_error('confirmsesskeybad', 'error');
 719              }
 720              if (lang_help_save_file($saveto, $currentfile, $_POST['filedata'])) {
 721                  notify(get_string("changessaved")." ($saveto/$currentfile)", "notifysuccess");
 722              } else {
 723                  error("Could not save the file '$currentfile'!", "lang.php?mode=helpfiles&amp;currentfile=$currentfile&amp;sesskey=$USER->sesskey");
 724              }
 725          }
 726  
 727          print_box_start('generalbox editstrings');
 728          $menufiles = array();
 729          $menufiles_coregrp = 1;
 730          $origlocation = ''; // the location of the currentfile's English source will be stored here
 731          $origplugin = '';   // dtto plugin
 732          foreach ($helpfiles as $helppath => $helpfile) {
 733              $item_key = $helpfile['filename'];
 734              $item_label = $helpfile['filename'];
 735              if ((!file_exists($saveto.'/'.$helpfile['filename'])) || (filesize($saveto.'/'.$helpfile['filename']) == 0)) {
 736                  $item_label .= $filemissingmark;
 737              } else {
 738                  if (filemtime($saveto.'/'.$helpfile['filename']) < filemtime($helppath)) {
 739                      $item_label .= $fileoldmark;
 740                  }
 741                  if ($helpfile['location'] != '' && $helpfile['plugin'] != '') {
 742                      $item_label .= ' ('.$helpfile['location'].'/'.$helpfile['plugin'].')';
 743                      if ($menufiles_coregrp == 1) {
 744                          $menufiles['extra'] = '------------';
 745                          $menufiles_coregrp = 0;
 746                      }
 747                  }
 748              }
 749              $menufiles[$item_key] = $item_label;
 750              if ($currentfile == $helpfile['filename']) {
 751                  $origlocation = $helpfile['location'];
 752                  $origplugin = $helpfile['plugin'];
 753              }
 754          }
 755          $selectionlabel = '<code class="path">';
 756          //$selectionlabel .= $strfilestoredin;
 757          $selectionlabel .= $uselocal ? "{$currentlang}_local" : $currentlang;
 758          $selectionlabel .= '/help/</code>';
 759          popup_form("$CFG->wwwroot/$CFG->admin/lang.php?mode=helpfiles&amp;currentfile=", $menufiles, "choosefile",
 760              $currentfile, $strchoosefiletoedit, '', '', false, 'self', $selectionlabel);
 761          helpbutton('langswitchstorage', $strfilestoredinhelp, 'moodle');
 762          print_box_end();
 763  
 764          if (!empty($currentfile)) {
 765  
 766              if (!file_exists("$saveto/$currentfile")) {
 767                  $dbg .= "File does not exist: $saveto/$currentfile\n";
 768                  //check if directory exist
 769                  if (!file_exists(dirname("$saveto/$currentfile"))) {
 770                       if(!lang_make_directory(dirname("$saveto/$currentfile"))) {
 771                           echo ('Cannot create directory: '.dirname("$saveto/$currentfile"));
 772                       }
 773                  }
 774                  //
 775                  // file doesn't exist - let's check webserver's permission to create it
 776                  //
 777                  if (!@touch("$saveto/$currentfile")) {
 778                      //
 779                      // webserver is unable to create new file
 780                      //
 781                      notify(get_string('filemissing', '', "$saveto/$currentfile" ));
 782                      notify(get_string('makeeditable', '', "$saveto/$currentfile"));
 783                      $editable = false;
 784                  } else {
 785                      //
 786                      // webserver can create new file - we can delete it now and let
 787                      // it create again if its filesize() > 0
 788                      //
 789                      $editable = true;
 790                      unlink("$saveto/$currentfile");
 791                  }
 792              } elseif (is_writable("$saveto/$currentfile")) {
 793                  $editable = true;
 794              } else {
 795                  //
 796                  // file exists but it is not writeable by web server process :-(
 797                  //
 798                  $editable = false;
 799                  notify(get_string('makeeditable', '', "$saveto/$currentfile"));
 800              }
 801  
 802              // master en_utf8 in dataroot is not editable
 803              if ((!$uselocal) && ($currentlang == 'en_utf8')) {
 804                  $editable = false;
 805              }
 806  
 807              echo '<div>';
 808  
 809              if ($uselocal) {
 810                  $strsavetotitle = $strlanglocalpackage . helpbutton('langpackages', $strlanglocalpackage, 'moodle', true, false, '', true);
 811                  $straltdirtitle = $strlangmasterpackage . helpbutton('langpackages', $strlangmasterpackage, 'moodle', true, false, '', true);
 812              } else {
 813                  $straltdirtitle = $strlanglocalpackage . helpbutton('langpackages', $strlanglocalpackage, 'moodle', true, false, '', true);
 814                  $strsavetotitle = $strlangmasterpackage . helpbutton('langpackages', $strlangmasterpackage, 'moodle', true, false, '', true);
 815  
 816              }
 817  
 818              if ($editable) {
 819                  // generate an editor for the current help file in $saveto
 820                  echo '<fieldset><legend>'.$strsavetotitle.'</legend>';
 821                  echo "<form id=\"helpfileeditor\" action=\"lang.php\" method=\"post\">";
 822                  echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
 823                  echo '<input type="hidden" name="currentfile" value="'.$currentfile.'" />';
 824                  echo '<input type="hidden" name="mode" value="helpfiles" />';
 825                  echo "<div align=\"center\">\n";
 826                  echo "<textarea rows=\"$fileeditorrows\" cols=\"$fileeditorcols\" name=\"filedata\">";
 827                  if (file_exists("$saveto/$currentfile")) {
 828                      echo htmlspecialchars(file_get_contents("$saveto/$currentfile"));
 829                  } else {
 830                      echo ($filetemplate);
 831                  }
 832                  echo "</textarea>\n</div>\n";
 833                  echo '<div align="center"><input type="submit" value="'.get_string('savechanges').'" /></div>';
 834                  echo '</form>';
 835                  $preview_url = lang_help_preview_url($currentfile, !$uselocal);
 836                  if ($preview_url) {
 837                      link_to_popup_window($preview_url, 'popup', get_string('preview'));
 838                  }
 839                  echo '</fieldset>';
 840              }
 841  
 842              if (is_readable("$altdir/$currentfile")) {
 843                  // show the content of the same help file in alternative location
 844                  echo '<fieldset><legend>'.$straltdirtitle.'</legend>';
 845                  echo "<div align=\"center\">\n";
 846                  echo "<textarea rows=\"$fileeditorrows\" cols=\"$fileeditorcols\" name=\"\">";
 847                  if (file_exists("$altdir/$currentfile")) {
 848                      echo htmlspecialchars(file_get_contents("$altdir/$currentfile"));
 849                  } else {
 850                      echo ($filetemplate);
 851                  }
 852                  echo "</textarea>\n</div>\n";
 853                  $preview_url = lang_help_preview_url($currentfile, $uselocal);
 854                  if ($preview_url) {
 855                      link_to_popup_window($preview_url, 'popup', get_string('preview'));
 856                  }
 857                  echo '</fieldset>';
 858              }
 859  
 860              // show the content of the original English file either in core space or plugin space
 861              if ($origlocation != '' && $origplugin != '') {
 862                  // non-core help file
 863                  $ensrc = "$CFG->dirroot/$origlocation/$origplugin/lang/en_utf8/help/$currentfile";
 864              } else {
 865                  // core help file
 866                  $ensrc = "$enlangdir/$currentfile";
 867              }
 868              if (is_readable($ensrc)) {
 869                  echo '<fieldset><legend>'.$strlangmasterenglish;
 870                  helpbutton('langpackages', $strlangmasterenglish);
 871                  echo '</legend>';
 872                  echo "<div align=\"center\">\n<textarea rows=\"$fileeditorrows\" cols=\"$fileeditorcols\" name=\"\">";
 873                  echo htmlspecialchars(file_get_contents($ensrc));
 874                  echo "</textarea>\n</div>\n";
 875                  $preview_url = lang_help_preview_url($currentfile, true, 'en_utf8');   // do not display en_utf8_local
 876                  if ($preview_url) {
 877                      link_to_popup_window($preview_url, 'popup', get_string('preview'));
 878                  }
 879                  echo '</fieldset>';
 880              }
 881  
 882              echo '</div>'; // translator box
 883              error_reporting($CFG->debug);
 884          }
 885  
 886          if (false && $CFG->debugdisplay && debugging('', DEBUG_DEVELOPER) ) {
 887              echo '<hr />';
 888              print_heading('Debugging info');
 889              echo '<pre class="notifytiny">';
 890              print_r($dbg);
 891              print_r("\n\$currentfile = $currentfile");
 892              print_r("\n\$enlangdir = $enlangdir");
 893              print_r("\n\$langdir = $langdir");
 894              print_r("\n\$locallangdir = $locallangdir");
 895              print_r("\n\$saveto = $saveto");
 896              print_r("\n\$altdir = $altdir");
 897              print_r("\n\$origlocation = $origlocation");
 898              print_r("\n\$origplugin = $origplugin");
 899              print_r("\n\$ensrc = $ensrc");
 900              print_r("\n\$helpfiles = ");
 901              print_r($helpfiles);
 902              echo '</pre>';
 903          }
 904  
 905      } // fi $mode == 'helpfiles'
 906  
 907  
 908      admin_externalpage_print_footer();
 909  
 910  //////////////////////////////////////////////////////////////////////
 911  
 912  /**
 913   * Save language translation file.
 914   *
 915   * Thanks to Petri Asikainen for the original version of code
 916   * used to save language files.
 917   *
 918   * @uses $CFG
 919   * @uses $USER
 920   * @param string $path Full pathname to the directory to use
 921   * @param string $file File to overwrite
 922   * @param array $strings Array of strings to write
 923   * @param bool $local Should *_local version be saved?
 924   * @param array $packstrings Array of default langpack strings (needed if $local)
 925   * @return bool Created successfully?
 926   */
 927  function lang_save_file($path, $file, $strings, $local, $packstrings) {
 928      global $CFG, $USER;
 929      if (LANG_KEEP_ORPHANS) {
 930          // let us load the current content of the file
 931          unset($string);
 932          @include("$path/$file");
 933          if (isset($string)) {
 934              $orphans = $string;
 935              unset($string);
 936          } else {
 937              $orphans = array();
 938          }
 939      }
 940      // let us rewrite the file
 941      if (!$f = @fopen("$path/$file","w")) {
 942          return false;
 943      }
 944  
 945      fwrite($f, "<?PHP // \$Id\$ \n");
 946      fwrite($f, "      // $file - created with Moodle $CFG->release ($CFG->version)\n");
 947      if ($local) {
 948          fwrite($f, "      // local modifications from $CFG->wwwroot\n");
 949      }
 950      fwrite($f, "\n\n");
 951      ksort($strings);
 952      foreach ($strings as $key => $value) {
 953          @list($id, $stringname) = explode('XXX',$key);
 954          $value = lang_fix_value_before_save($value);
 955          if ($id == "string" and $value != ""){
 956              if ((!$local) || (!isset($packstrings[$stringname])) || (lang_fix_value_from_file($packstrings[$stringname]) <> lang_fix_value_from_file($value))) {
 957                  // Either we are saving the master language pack
 958                  // or the string is not saved in packstring - fixes PHP notices about missing key
 959                  // or we are saving local language pack and the strings differ.
 960                  fwrite($f,"\$string['$stringname'] = '$value';\n");
 961              }
 962              if (LANG_KEEP_ORPHANS && isset($orphans[$stringname])) {
 963                  unset($orphans[$stringname]);
 964              }
 965          }
 966      }
 967      if (LANG_KEEP_ORPHANS) {
 968          // let us add orphaned strings, i.e. already translated strings without the English referential source
 969          foreach ($orphans as $key => $value) {
 970              fwrite($f,"\$string['$key'] = '".lang_fix_value_before_save($value)."'; // ORPHANED\n");
 971          }
 972      }
 973      fwrite($f,"\n?>\n");
 974      fclose($f);
 975      return true;
 976  }
 977  
 978  /**
 979   * Fix value of the translated string after it is load from the file.
 980   *
 981   * These modifications are typically necessary to work with the same string coming from two sources.
 982   * We need to compare the content of these sources and we want to have e.g. "This string\r\n"
 983   * to be the same as " This string\n".
 984   *
 985   * @param string $value Original string from the file
 986   * @return string Fixed value
 987   */
 988  function lang_fix_value_from_file($value='') {
 989      $value = str_replace("\r","",$value);              // Bad character caused by Windows
 990      $value = preg_replace("/\n{3,}/", "\n\n", $value); // Collapse runs of blank lines
 991      $value = trim($value);                             // Delete leading/trailing white space
 992      $value = str_replace("\\","",$value);              // Delete all slashes
 993      $value = str_replace("%%","%",$value);
 994      $value = str_replace("&","&amp;",$value);          // Fixes MDL-9248
 995      $value = str_replace("<","&lt;",$value);
 996      $value = str_replace(">","&gt;",$value);
 997      $value = str_replace('"',"&quot;",$value);
 998      return $value;
 999  }
1000  
1001  /**
1002   * Fix value of the translated string before it is saved into the file
1003   *
1004   * @uses $CFG
1005   * @param string $value Raw string to be saved into the lang pack
1006   * @return string Fixed value
1007   */
1008  function lang_fix_value_before_save($value='') {
1009      global $CFG;
1010      if ($CFG->lang != "zh_hk" and $CFG->lang != "zh_tw") {  // Some MB languages include backslash bytes
1011          $value = str_replace("\\","",$value);           // Delete all slashes
1012      }
1013      if (ini_get_bool('magic_quotes_sybase')) {          // Unescape escaped sybase quotes
1014          $value = str_replace("''", "'", $value);
1015      }
1016      $value = str_replace("'", "\\'", $value);           // Add slashes for '
1017      $value = str_replace('"', "\\\"", $value);          // Add slashes for "
1018      $value = str_replace("%","%%",$value);              // Escape % characters
1019      $value = str_replace("\r", "",$value);              // Remove linefeed characters
1020      $value = trim($value);                              // Delete leading/trailing white space
1021      return $value;
1022  }
1023  
1024  /**
1025   * Try and create a new language directory.
1026   *
1027   * Uses PHP>=5.0 syntax of mkdir and tries to create directories recursively.
1028   *
1029   * @uses $CFG
1030   * @param string $directory full path to the directory under $langbase
1031   * @return string|false Returns full path to directory if successful, false if not
1032   */
1033  function lang_make_directory($dir, $shownotices=true) {
1034      global $CFG;
1035      umask(0000);
1036      if (! file_exists($dir)) {
1037          if (! @mkdir($dir, $CFG->directorypermissions, true)) { // recursive=true; PHP>=5.0 needed
1038              return false;
1039          }
1040          //@chmod($dir, $CFG->directorypermissions);  // Just in case mkdir didn't do it
1041      }
1042      return $dir;
1043  }
1044  
1045  /**
1046   * Return the string key name for use in HTML form.
1047   *
1048   * Required because '.' in form input names get replaced by '_' by PHP.
1049   *
1050   * @param string $keyfromfile The key name containing '.'
1051   * @return string The key name without '.'
1052   */
1053  function lang_form_string_key($keyfromfile) {
1054      return str_replace('.', '##46#', $keyfromfile);  /// Derived from &#46, the ascii value for a period.
1055  }
1056  
1057  /**
1058   * Return the string key name for use in file.
1059   *
1060   * Required because '.' in form input names get replaced by '_' by PHP.
1061   *
1062   * @param string $keyfromfile The key name without '.'
1063   * @return string The key name containing '.'
1064   */
1065  function lang_file_string_key($keyfromform) {
1066      return str_replace('##46#', '.', $keyfromform);
1067  }
1068  
1069  /**
1070   * Return the substring of the string and take care of XHTML compliance.
1071   *
1072   * There was a problem with pure substr() which could possibly produce XHTML parsing error:
1073   *  substr('Marks &amp; Spencer', 0, 9) -> 'Marks &am' ... is not XHTML compliance
1074   * This function takes care of these cases. Fixes MDL-8852.
1075   *
1076   * Thanks to kovacsendre, the author of the function at http://php.net/substr
1077   *
1078   * @param string $str The original string
1079   * @param int $start Start position in the $value string
1080   * @param int $length Optional length of the returned substring
1081   * @return string The substring as returned by substr() with XHTML compliance
1082   * @todo Seems the function does not work with negative $start together with $length being set
1083   */
1084  function lang_xhtml_save_substr($str, $start, $length = NULL) {
1085      if ($length === 0) {
1086          //stop wasting our time ;)
1087          return "";
1088      }
1089  
1090      //check if we can simply use the built-in functions
1091      if (strpos($str, '&') === false) {
1092          // No entities. Use built-in functions
1093          if ($length === NULL) {
1094              return substr($str, $start);
1095          } else {
1096              return substr($str, $start, $length);
1097          }
1098      }
1099  
1100      // create our array of characters and html entities
1101      $chars = preg_split('/(&[^;\s]+;)|/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE);
1102      $html_length = count($chars);
1103  
1104      // check if we can predict the return value and save some processing time, i.e.:
1105      // input string was empty OR
1106      // $start is longer than the input string OR
1107      // all characters would be omitted
1108      if (($html_length === 0) or ($start >= $html_length) or (isset($length) and ($length <= -$html_length))) {
1109          return '';
1110      }
1111  
1112      //calculate start position
1113      if ($start >= 0) {
1114          $real_start = $chars[$start][1];
1115      } else {
1116          //start'th character from the end of string
1117          $start = max($start,-$html_length);
1118          $real_start = $chars[$html_length+$start][1];
1119      }
1120  
1121      if (!isset($length)) {
1122          // no $length argument passed, return all remaining characters
1123          return substr($str, $real_start);
1124      } elseif ($length > 0) {
1125          // copy $length chars
1126          if ($start+$length >= $html_length) {
1127              // return all remaining characters
1128              return substr($str, $real_start);
1129          } else {
1130              //return $length characters
1131              return substr($str, $real_start, $chars[max($start,0)+$length][1] - $real_start);
1132          }
1133      } else {
1134          //negative $length. Omit $length characters from end
1135          return substr($str, $real_start, $chars[$html_length+$length][1] - $real_start);
1136      }
1137  }
1138  
1139  /**
1140  * Finds all English string files in the standard lang/en_utf8 location.
1141  *
1142  * Core lang files should always be stored here and not in the module space (MDL-10920).
1143  * The English version of the file may be found in
1144  *  $CFG->dirroot/lang/en_utf8/filename
1145  * The localised version of the found file should be saved into
1146  *  $CFG->dataroot/lang/currentlang[_local]/filename
1147  * where "filename" is returned as a part of the file record.
1148  *
1149  * @return array Array of a file information. Compatible format with {@link lang_extra_locations()}
1150  */
1151  function lang_standard_locations() {
1152      global $CFG;
1153      $files = array();
1154      // Standard location of master English string files.
1155      $places = array($CFG->dirroot.'/lang/en_utf8');
1156          foreach ($places as $place) {
1157              foreach (get_directory_list($place, '', false) as $file) {
1158                  if ((substr($file, -4) == ".php") && ($file != "langconfig.php")) {
1159                      $fullpath = $place.'/'.$file;
1160                      $files[$fullpath] = array(
1161                          'filename' => $file,
1162                          'location' => '',
1163                          'plugin' => '',
1164                          'prefix' => '',
1165                      );
1166                  }
1167              }
1168          }
1169      return $files;
1170  }
1171  
1172  /**
1173  * Finds all English string files in non-standard location.
1174  *
1175  * Searches for lang/en_utf8/*.php in various types of plugins (blocks, database presets, question types,
1176  * 3rd party modules etc.) and returns an array of found files details.
1177  *
1178  * The English version of the file may be found in
1179  *  $CFG->dirroot/location/plugin/lang/en_utf8/filename
1180  * The localised version of the found file should be saved into
1181  *  $CFG->dataroot/lang/currentlang[_local]/prefix_plugin.php
1182  * where "location", "plugin", "prefix" and "filename" are returned as a part of the file record.
1183  *
1184  * @return array Array of a file information. Compatible format with {@link lang_standard_locations()}
1185  */
1186  function lang_extra_locations() {
1187      global $CFG;
1188      $files = array();
1189      $places = places_to_search_for_lang_strings();
1190      foreach ($places as $prefix => $directories) {
1191          if ($prefix != '__exceptions') {
1192              foreach ($directories as $directory) {
1193                  foreach (get_list_of_plugins($directory) as $plugin) {
1194                      $enlangdirlocation = $CFG->dirroot.'/'.$directory.'/'.$plugin.'/lang/en_utf8';
1195                      foreach (get_directory_list($enlangdirlocation, '', false) as $file) {
1196                          if ((substr($file, -4) == ".php") && ($file != "langconfig.php")) {
1197                              $fullpath = $enlangdirlocation.'/'.$file;
1198                              $files[$fullpath] = array(
1199                                  'filename' => $file,
1200                                  'location' => $directory,
1201                                  'plugin' => $plugin,
1202                                  'prefix' => $prefix,
1203                              );
1204                          }
1205                      }
1206                  }
1207              }
1208          }
1209      }
1210      return $files;
1211  }
1212  
1213  /**
1214   * Lookup for a stringfile details.
1215   *
1216   * English files can be stored in several places (core space or module/plugin space). Their translations
1217   * go into the one directory - the current language pack. Therefore, the name of the stringfile may be
1218   * considered as a key of the list of all stringfiles.
1219   *
1220   * @param string $currentfile the filename
1221   * @param array $stringfiles the array of file info returned by {@link lang_extra_locations()}
1222   * @return array Array of a file information (filename, location, plugin, prefix) or null.
1223   */
1224  function lang_get_file_info($currentfile, $stringfiles) {
1225      $found = false;
1226      foreach ($stringfiles as $path=>$stringfile) {
1227          if ($stringfile['filename'] == $currentfile) {
1228              $found = true;
1229              $ret = $stringfile;
1230              $ret['fullpath'] = $path;
1231              break;
1232          }
1233      }
1234      if ($found) {
1235          return $ret;
1236      } else {
1237          return null;
1238      }
1239  }
1240  
1241  /**
1242   * Returns all English help files in the standard lang/en_utf8/help location.
1243   *
1244   * Core help files should always be stored here and not in the module space (MDL-10920).
1245   * The English version of the file may be found in
1246   *  $CFG->dirroot/lang/en_utf8/help/filename
1247   * The localised version of the found file should be saved into
1248   *  $CFG->dataroot/lang/currentlang[_local]/help/filename
1249   * where "filename" is returned as a part of the file record.
1250   *
1251   * @return array Array of a file information. Compatible format with {@link lang_extra_locations()}
1252   */
1253  function lang_help_standard_locations() {
1254      global $CFG;
1255      $files = array();
1256      // Standard location of master English help files.
1257      $places = array($CFG->dirroot.'/lang/en_utf8/help');
1258          foreach ($places as $place) {
1259              foreach (get_directory_list($place, 'CVS') as $file) {
1260                  if ((substr($file, -5) == '.html') || (substr($file, -4) == '.txt' )) {
1261                      $fullpath = $place.'/'.$file;
1262                      $files[$fullpath] = array(
1263                          'filename' => $file,
1264                          'location' => '',
1265                          'plugin' => '',
1266                          'prefix' => '',
1267                      );
1268                  }
1269              }
1270          }
1271      return $files;
1272  }
1273  
1274  /**
1275   * Returns all English help files in non-standard location.
1276   *
1277   * Searches for lang/en_utf8/help/* files in various types of plugins (blocks, database presets, question types,
1278   * 3rd party modules etc.) and returns an array of found files details.
1279   *
1280   * The English version of the file may be found in
1281   *  $CFG->dirroot/location/plugin/lang/en_utf8/help/filename
1282   * The localised version of the found file should be saved into
1283   *  $CFG->dataroot/lang/currentlang[_local]/help/prefix_plugin/filename (XXX is "prefix" here right?)
1284   * where "location", "plugin", "prefix" and "filename" are returned as a part of the file record.
1285   *
1286   * @return array Array of a file information. Compatible format with {@link lang_standard_locations()}
1287   */
1288  function lang_help_extra_locations() {
1289      global $CFG;
1290      $files = array();
1291      $places = places_to_search_for_lang_strings();
1292      foreach ($places as $prefix => $directories) {
1293          if ($prefix != '__exceptions') {
1294              foreach ($directories as $directory) {
1295                  foreach (get_list_of_plugins($directory) as $plugin) {
1296                      $enlangdirlocation = $CFG->dirroot.'/'.$directory.'/'.$plugin.'/lang/en_utf8/help';
1297                      foreach (get_directory_list($enlangdirlocation, 'CVS') as $file) {
1298                          if ((substr($file, -5) == '.html') || (substr($file, -4) == '.txt' )) {
1299                              $fullpath = $enlangdirlocation.'/'.$file;
1300                              $files[$fullpath] = array(
1301                                  'filename' => $file,
1302                                  'location' => $directory,
1303                                  'plugin' => $plugin,
1304                                  'prefix' => $prefix,
1305                              );
1306                          }
1307                      }
1308                  }
1309              }
1310          }
1311      }
1312      return $files;
1313  }
1314  
1315  /**
1316   * Return a preview URL for help file, if available.
1317   *
1318   * @param string $currentfile The relative path to the help file, e.g. "assignment/types.html" - MDL-12291
1319   * @param bool $skiplocal Force displaying the helpfile from a master lang pack
1320   * @param string $forcelang Force language of the help, e.g. "en_utf8"
1321   * @return string $url
1322   */
1323  function lang_help_preview_url($currentfile, $skiplocal=false, $forcelang = '') {
1324      $currentpathexp = explode('/', $currentfile);
1325      if (count($currentpathexp) > 1) {
1326          $url = '/help.php?module='.implode('/',array_slice($currentpathexp,0,count($currentpathexp)-1)).'&amp;file='.end($currentpathexp);
1327      } else {
1328          $url = '/help.php?module=moodle&amp;file='.$currentfile;
1329      }
1330      if ($skiplocal) {
1331          $url .= '&amp;skiplocal=1';
1332      }
1333      if ($forcelang) {
1334          $url .= '&amp;forcelang='.$forcelang;
1335      }
1336      return $url;
1337  }
1338  
1339  
1340  /**
1341   * Saves (overwrites) translated help file.
1342   *
1343   * @param string $helproot The path to the "help" folder
1344   * @param string $file The relative path to the html help file
1345   * @param string $content HTML data to be saved
1346   * @return bool False if save failed, true otherwise
1347   */
1348  function lang_help_save_file($helproot, $file, $content) {
1349      global $CFG, $USER;
1350  
1351      $content = str_replace("\r", "",$content);              // Remove linefeed characters
1352      $content = preg_replace("/\n{3,}/", "\n\n", $content);  // Collapse runs of blank lines
1353      $content = trim($content);                              // Delete leading/trailing whitespace
1354      if (is_readable("$helproot/$file") && filesize("$helproot/$file") > 0 && $content == '') {
1355          notify(get_string('langrmyourself', 'admin'));
1356          return true;
1357      }
1358  
1359      error_reporting(0);
1360      if (!$f = fopen("$helproot/$file","w")) {
1361          error_reporting($CFG->debug);
1362          return false;
1363      }
1364      error_reporting($CFG->debug);
1365  
1366      fwrite($f, stripslashes($content));
1367      fclose($f);
1368  
1369      // Remove file if its empty
1370      if (filesize("$helproot/$file") == 0) {
1371          unlink("$helproot/$file");
1372      }
1373  
1374      return true;
1375  }
1376  
1377  
1378  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7