libdir.'/adminlib.php'); admin_externalpage_setup('langedit'); $context = get_context_instance(CONTEXT_SYSTEM); define('LANG_SUBMIT_REPEAT', 1); // repeat displaying submit button? define('LANG_SUBMIT_REPEAT_EVERY', 20); // if so, after how many lines? define('LANG_DISPLAY_MISSING_LINKS', 1); // display "go to first/next missing string" links? define('LANG_DEFAULT_FILE', ''); // default file to translate. Empty allowed define('LANG_DEFAULT_HELPFILE', ''); // default helpfile to translate. Empty allowed define('LANG_LINK_MISSING_STRINGS', 1); // create links from "missing" page to "compare" page? define('LANG_DEFAULT_USELOCAL', 0); // should *_utf8_local be used by default? define('LANG_MISSING_TEXT_MAX_LEN', 60); // maximum length of the missing text to display define('LANG_KEEP_ORPHANS', 1); // keep orphaned strings (i.e. strings w/o English reference) define('LANG_SEARCH_EXTRA', 1); // search lang files in extra locations define('LANG_ALWAYS_TEXTAREA', 1); // always use '."\n"; } else { if ($valuelen) { $cols = $valuelen + 5; } if (LANG_ALWAYS_TEXTAREA) { $o .= ''."\n"; } else { $o .= ''; } } if ($value2 <> '' && $value <> $value2) { $o .= '
'.$value2.''; } $o .= $missingnext . ''; } else { $o .= ''.$value.'
'.$value2.''; } $o .= ''."\n"; } if ($editable) { $o .= ' 
'; $o .= ''; $o .= ''; $o .= ''; $o .= ''; $o .= ''; } $o .= ''; if ($editable) { $o .= ''; $o .= ''; } if (LANG_DISPLAY_MISSING_LINKS) { if ($missingcounter > 0) { print_heading(get_string('numberofmissingstrings', 'admin', $missingcounter), '', 4); if ($editable) { print_heading(''.$strgotofirst.'', "", 4); } } else { print_heading($strnomissingstrings, '', 4, 'notifysuccess'); } } echo $o; } else { // no $currentfile specified // no useful information to display - maybe some help? instructions? } } elseif ($mode == 'helpfiles') { $saveto = $saveto.'/help'; // the edited content will be saved to $enlangdir = $enlangdir.'/help'; // English master help files localtion $langdir = $langdir.'/help'; // current language master help files location $locallangdir = $locallangdir.'/help'; // local modifications of help files location $altdir = $uselocal ? $langdir : $locallangdir; // alternative to $saveto $fileeditorrows = 10; // number of textareas' rows $fileeditorcols = 100; // dtto cols $filemissingmark = ' (***)'; // mark to add to non-existing or zero-length files $fileoldmark = ' (old?)'; // mark to add to filenames in selection form if the English version is newer $filetemplate = ''; // template for new files, e.g. CVS identification if (isset($_POST['currentfile'])) { // Save a file if (!confirm_sesskey()) { print_error('confirmsesskeybad', 'error'); } if (lang_help_save_file($saveto, $currentfile, $_POST['filedata'])) { notify(get_string("changessaved")." ($saveto/$currentfile)", "notifysuccess"); } else { error("Could not save the file '$currentfile'!", "lang.php?mode=helpfiles&currentfile=$currentfile&sesskey=$USER->sesskey"); } } print_box_start('generalbox editstrings'); $menufiles = array(); $menufiles_coregrp = 1; $origlocation = ''; // the location of the currentfile's English source will be stored here $origplugin = ''; // dtto plugin foreach ($helpfiles as $helppath => $helpfile) { $item_key = $helpfile['filename']; $item_label = $helpfile['filename']; if ((!file_exists($saveto.'/'.$helpfile['filename'])) || (filesize($saveto.'/'.$helpfile['filename']) == 0)) { $item_label .= $filemissingmark; } else { if (filemtime($saveto.'/'.$helpfile['filename']) < filemtime($helppath)) { $item_label .= $fileoldmark; } if ($helpfile['location'] != '' && $helpfile['plugin'] != '') { $item_label .= ' ('.$helpfile['location'].'/'.$helpfile['plugin'].')'; if ($menufiles_coregrp == 1) { $menufiles['extra'] = '------------'; $menufiles_coregrp = 0; } } } $menufiles[$item_key] = $item_label; if ($currentfile == $helpfile['filename']) { $origlocation = $helpfile['location']; $origplugin = $helpfile['plugin']; } } $selectionlabel = ''; //$selectionlabel .= $strfilestoredin; $selectionlabel .= $uselocal ? "{$currentlang}_local" : $currentlang; $selectionlabel .= '/help/'; popup_form("$CFG->wwwroot/$CFG->admin/lang.php?mode=helpfiles&currentfile=", $menufiles, "choosefile", $currentfile, $strchoosefiletoedit, '', '', false, 'self', $selectionlabel); helpbutton('langswitchstorage', $strfilestoredinhelp, 'moodle'); print_box_end(); if (!empty($currentfile)) { if (!file_exists("$saveto/$currentfile")) { $dbg .= "File does not exist: $saveto/$currentfile\n"; //check if directory exist if (!file_exists(dirname("$saveto/$currentfile"))) { if(!lang_make_directory(dirname("$saveto/$currentfile"))) { echo ('Cannot create directory: '.dirname("$saveto/$currentfile")); } } // // file doesn't exist - let's check webserver's permission to create it // if (!@touch("$saveto/$currentfile")) { // // webserver is unable to create new file // notify(get_string('filemissing', '', "$saveto/$currentfile" )); notify(get_string('makeeditable', '', "$saveto/$currentfile")); $editable = false; } else { // // webserver can create new file - we can delete it now and let // it create again if its filesize() > 0 // $editable = true; unlink("$saveto/$currentfile"); } } elseif (is_writable("$saveto/$currentfile")) { $editable = true; } else { // // file exists but it is not writeable by web server process :-( // $editable = false; notify(get_string('makeeditable', '', "$saveto/$currentfile")); } // master en_utf8 in dataroot is not editable if ((!$uselocal) && ($currentlang == 'en_utf8')) { $editable = false; } echo '
'; if ($uselocal) { $strsavetotitle = $strlanglocalpackage . helpbutton('langpackages', $strlanglocalpackage, 'moodle', true, false, '', true); $straltdirtitle = $strlangmasterpackage . helpbutton('langpackages', $strlangmasterpackage, 'moodle', true, false, '', true); } else { $straltdirtitle = $strlanglocalpackage . helpbutton('langpackages', $strlanglocalpackage, 'moodle', true, false, '', true); $strsavetotitle = $strlangmasterpackage . helpbutton('langpackages', $strlangmasterpackage, 'moodle', true, false, '', true); } if ($editable) { // generate an editor for the current help file in $saveto echo '
'.$strsavetotitle.''; echo "
"; echo ''; echo ''; echo ''; echo "
\n"; echo "\n
\n"; echo '
'; echo '
'; $preview_url = lang_help_preview_url($currentfile, !$uselocal); if ($preview_url) { link_to_popup_window($preview_url, 'popup', get_string('preview')); } echo '
'; } if (is_readable("$altdir/$currentfile")) { // show the content of the same help file in alternative location echo '
'.$straltdirtitle.''; echo "
\n"; echo "\n
\n"; $preview_url = lang_help_preview_url($currentfile, $uselocal); if ($preview_url) { link_to_popup_window($preview_url, 'popup', get_string('preview')); } echo '
'; } // show the content of the original English file either in core space or plugin space if ($origlocation != '' && $origplugin != '') { // non-core help file $ensrc = "$CFG->dirroot/$origlocation/$origplugin/lang/en_utf8/help/$currentfile"; } else { // core help file $ensrc = "$enlangdir/$currentfile"; } if (is_readable($ensrc)) { echo '
'.$strlangmasterenglish; helpbutton('langpackages', $strlangmasterenglish); echo ''; echo "
\n\n
\n"; $preview_url = lang_help_preview_url($currentfile, true, 'en_utf8'); // do not display en_utf8_local if ($preview_url) { link_to_popup_window($preview_url, 'popup', get_string('preview')); } echo '
'; } echo '
'; // translator box error_reporting($CFG->debug); } if (false && $CFG->debugdisplay && debugging('', DEBUG_DEVELOPER) ) { echo '
'; print_heading('Debugging info'); echo '
';
            print_r($dbg);
            print_r("\n\$currentfile = $currentfile");
            print_r("\n\$enlangdir = $enlangdir");
            print_r("\n\$langdir = $langdir");
            print_r("\n\$locallangdir = $locallangdir");
            print_r("\n\$saveto = $saveto");
            print_r("\n\$altdir = $altdir");
            print_r("\n\$origlocation = $origlocation");
            print_r("\n\$origplugin = $origplugin");
            print_r("\n\$ensrc = $ensrc");
            print_r("\n\$helpfiles = ");
            print_r($helpfiles);
            echo '
'; } } // fi $mode == 'helpfiles' admin_externalpage_print_footer(); ////////////////////////////////////////////////////////////////////// /** * Save language translation file. * * Thanks to Petri Asikainen for the original version of code * used to save language files. * * @uses $CFG * @uses $USER * @param string $path Full pathname to the directory to use * @param string $file File to overwrite * @param array $strings Array of strings to write * @param bool $local Should *_local version be saved? * @param array $packstrings Array of default langpack strings (needed if $local) * @return bool Created successfully? */ function lang_save_file($path, $file, $strings, $local, $packstrings) { global $CFG, $USER; if (LANG_KEEP_ORPHANS) { // let us load the current content of the file unset($string); @include("$path/$file"); if (isset($string)) { $orphans = $string; unset($string); } else { $orphans = array(); } } // let us rewrite the file if (!$f = @fopen("$path/$file","w")) { return false; } fwrite($f, "release ($CFG->version)\n"); if ($local) { fwrite($f, " // local modifications from $CFG->wwwroot\n"); } fwrite($f, "\n\n"); ksort($strings); foreach ($strings as $key => $value) { @list($id, $stringname) = explode('XXX',$key); $value = lang_fix_value_before_save($value); if ($id == "string" and $value != ""){ if ((!$local) || (!isset($packstrings[$stringname])) || (lang_fix_value_from_file($packstrings[$stringname]) <> lang_fix_value_from_file($value))) { // Either we are saving the master language pack // or the string is not saved in packstring - fixes PHP notices about missing key // or we are saving local language pack and the strings differ. fwrite($f,"\$string['$stringname'] = '$value';\n"); } if (LANG_KEEP_ORPHANS && isset($orphans[$stringname])) { unset($orphans[$stringname]); } } } if (LANG_KEEP_ORPHANS) { // let us add orphaned strings, i.e. already translated strings without the English referential source foreach ($orphans as $key => $value) { fwrite($f,"\$string['$key'] = '".lang_fix_value_before_save($value)."'; // ORPHANED\n"); } } fwrite($f,"\n?>\n"); fclose($f); return true; } /** * Fix value of the translated string after it is load from the file. * * These modifications are typically necessary to work with the same string coming from two sources. * We need to compare the content of these sources and we want to have e.g. "This string\r\n" * to be the same as " This string\n". * * @param string $value Original string from the file * @return string Fixed value */ function lang_fix_value_from_file($value='') { $value = str_replace("\r","",$value); // Bad character caused by Windows $value = preg_replace("/\n{3,}/", "\n\n", $value); // Collapse runs of blank lines $value = trim($value); // Delete leading/trailing white space $value = str_replace("\\","",$value); // Delete all slashes $value = str_replace("%%","%",$value); $value = str_replace("&","&",$value); // Fixes MDL-9248 $value = str_replace("<","<",$value); $value = str_replace(">",">",$value); $value = str_replace('"',""",$value); return $value; } /** * Fix value of the translated string before it is saved into the file * * @uses $CFG * @param string $value Raw string to be saved into the lang pack * @return string Fixed value */ function lang_fix_value_before_save($value='') { global $CFG; if ($CFG->lang != "zh_hk" and $CFG->lang != "zh_tw") { // Some MB languages include backslash bytes $value = str_replace("\\","",$value); // Delete all slashes } if (ini_get_bool('magic_quotes_sybase')) { // Unescape escaped sybase quotes $value = str_replace("''", "'", $value); } // escape all embedded variables $value = str_replace('$', '\$', $value); // Add slashes for $ // unescape placeholders: only $a and $a->something are allowed. All other $variables are left escaped $value = preg_replace('/\\\\\$a($|[^_a-zA-Z0-9\-]|\->[a-zA-Z0-9_]+)/', '$a\\1', $value); $value = str_replace("'", "\\'", $value); // Add slashes for ' $value = str_replace('"', "\\\"", $value); // Add slashes for " $value = str_replace("%","%%",$value); // Escape % characters $value = str_replace("\r", "",$value); // Remove linefeed characters $value = trim($value); // Delete leading/trailing white space return $value; } /** * Try and create a new language directory. * * Uses PHP>=5.0 syntax of mkdir and tries to create directories recursively. * * @uses $CFG * @param string $directory full path to the directory under $langbase * @return string|false Returns full path to directory if successful, false if not */ function lang_make_directory($dir, $shownotices=true) { global $CFG; umask(0000); if (! file_exists($dir)) { if (! @mkdir($dir, $CFG->directorypermissions, true)) { // recursive=true; PHP>=5.0 needed return false; } //@chmod($dir, $CFG->directorypermissions); // Just in case mkdir didn't do it } return $dir; } /** * Return the string key name for use in HTML form. * * Required because '.' in form input names get replaced by '_' by PHP. * * @param string $keyfromfile The key name containing '.' * @return string The key name without '.' */ function lang_form_string_key($keyfromfile) { return str_replace('.', '##46#', $keyfromfile); /// Derived from ., the ascii value for a period. } /** * Return the string key name for use in file. * * Required because '.' in form input names get replaced by '_' by PHP. * * @param string $keyfromfile The key name without '.' * @return string The key name containing '.' */ function lang_file_string_key($keyfromform) { return str_replace('##46#', '.', $keyfromform); } /** * Return the substring of the string and take care of XHTML compliance. * * There was a problem with pure substr() which could possibly produce XHTML parsing error: * substr('Marks & Spencer', 0, 9) -> 'Marks &am' ... is not XHTML compliance * This function takes care of these cases. Fixes MDL-8852. * * Thanks to kovacsendre, the author of the function at http://php.net/substr * * @param string $str The original string * @param int $start Start position in the $value string * @param int $length Optional length of the returned substring * @return string The substring as returned by substr() with XHTML compliance * @todo Seems the function does not work with negative $start together with $length being set */ function lang_xhtml_save_substr($str, $start, $length = NULL) { if ($length === 0) { //stop wasting our time ;) return ""; } //check if we can simply use the built-in functions if (strpos($str, '&') === false) { // No entities. Use built-in functions if ($length === NULL) { return substr($str, $start); } else { return substr($str, $start, $length); } } // create our array of characters and html entities $chars = preg_split('/(&[^;\s]+;)|/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE); $html_length = count($chars); // check if we can predict the return value and save some processing time, i.e.: // input string was empty OR // $start is longer than the input string OR // all characters would be omitted if (($html_length === 0) or ($start >= $html_length) or (isset($length) and ($length <= -$html_length))) { return ''; } //calculate start position if ($start >= 0) { $real_start = $chars[$start][1]; } else { //start'th character from the end of string $start = max($start,-$html_length); $real_start = $chars[$html_length+$start][1]; } if (!isset($length)) { // no $length argument passed, return all remaining characters return substr($str, $real_start); } elseif ($length > 0) { // copy $length chars if ($start+$length >= $html_length) { // return all remaining characters return substr($str, $real_start); } else { //return $length characters return substr($str, $real_start, $chars[max($start,0)+$length][1] - $real_start); } } else { //negative $length. Omit $length characters from end return substr($str, $real_start, $chars[$html_length+$length][1] - $real_start); } } /** * Finds all English string files in the standard lang/en_utf8 location. * * Core lang files should always be stored here and not in the module space (MDL-10920). * The English version of the file may be found in * $CFG->dirroot/lang/en_utf8/filename * The localised version of the found file should be saved into * $CFG->dataroot/lang/currentlang[_local]/filename * where "filename" is returned as a part of the file record. * * @return array Array of a file information. Compatible format with {@link lang_extra_locations()} */ function lang_standard_locations() { global $CFG; $files = array(); // Standard location of master English string files. $places = array($CFG->dirroot.'/lang/en_utf8'); foreach ($places as $place) { foreach (get_directory_list($place, '', false) as $file) { if ((substr($file, -4) == ".php") && ($file != "langconfig.php")) { $fullpath = $place.'/'.$file; $files[$fullpath] = array( 'filename' => $file, 'location' => '', 'plugin' => '', 'prefix' => '', ); } } } return $files; } /** * Finds all English string files in non-standard location. * * Searches for lang/en_utf8/*.php in various types of plugins (blocks, database presets, question types, * 3rd party modules etc.) and returns an array of found files details. * * The English version of the file may be found in * $CFG->dirroot/location/plugin/lang/en_utf8/filename * The localised version of the found file should be saved into * $CFG->dataroot/lang/currentlang[_local]/prefix_plugin.php * where "location", "plugin", "prefix" and "filename" are returned as a part of the file record. * * @return array Array of a file information. Compatible format with {@link lang_standard_locations()} */ function lang_extra_locations() { global $CFG; $files = array(); $places = places_to_search_for_lang_strings(); foreach ($places as $prefix => $directories) { if ($prefix != '__exceptions') { foreach ($directories as $directory) { foreach (get_list_of_plugins($directory) as $plugin) { $enlangdirlocation = $CFG->dirroot.'/'.$directory.'/'.$plugin.'/lang/en_utf8'; foreach (get_directory_list($enlangdirlocation, '', false) as $file) { if ((substr($file, -4) == ".php") && ($file != "langconfig.php")) { $fullpath = $enlangdirlocation.'/'.$file; $files[$fullpath] = array( 'filename' => $file, 'location' => $directory, 'plugin' => $plugin, 'prefix' => $prefix, ); } } } } } } return $files; } /** * Lookup for a stringfile details. * * English files can be stored in several places (core space or module/plugin space). Their translations * go into the one directory - the current language pack. Therefore, the name of the stringfile may be * considered as a key of the list of all stringfiles. * * @param string $currentfile the filename * @param array $stringfiles the array of file info returned by {@link lang_extra_locations()} * @return array Array of a file information (filename, location, plugin, prefix) or null. */ function lang_get_file_info($currentfile, $stringfiles) { $found = false; foreach ($stringfiles as $path=>$stringfile) { if ($stringfile['filename'] == $currentfile) { $found = true; $ret = $stringfile; $ret['fullpath'] = $path; break; } } if ($found) { return $ret; } else { return null; } } /** * Returns all English help files in the standard lang/en_utf8/help location. * * Core help files should always be stored here and not in the module space (MDL-10920). * The English version of the file may be found in * $CFG->dirroot/lang/en_utf8/help/filename * The localised version of the found file should be saved into * $CFG->dataroot/lang/currentlang[_local]/help/filename * where "filename" is returned as a part of the file record. * * @return array Array of a file information. Compatible format with {@link lang_extra_locations()} */ function lang_help_standard_locations() { global $CFG; $files = array(); // Standard location of master English help files. $places = array($CFG->dirroot.'/lang/en_utf8/help'); foreach ($places as $place) { foreach (get_directory_list($place, 'CVS') as $file) { if ((substr($file, -5) == '.html') || (substr($file, -4) == '.txt' )) { $fullpath = $place.'/'.$file; $files[$fullpath] = array( 'filename' => $file, 'location' => '', 'plugin' => '', 'prefix' => '', ); } } } return $files; } /** * Returns all English help files in non-standard location. * * Searches for lang/en_utf8/help/* files in various types of plugins (blocks, database presets, question types, * 3rd party modules etc.) and returns an array of found files details. * * The English version of the file may be found in * $CFG->dirroot/location/plugin/lang/en_utf8/help/filename * The localised version of the found file should be saved into * $CFG->dataroot/lang/currentlang[_local]/help/prefix_plugin/filename (XXX is "prefix" here right?) * where "location", "plugin", "prefix" and "filename" are returned as a part of the file record. * * @return array Array of a file information. Compatible format with {@link lang_standard_locations()} */ function lang_help_extra_locations() { global $CFG; $files = array(); $places = places_to_search_for_lang_strings(); foreach ($places as $prefix => $directories) { if ($prefix != '__exceptions') { foreach ($directories as $directory) { foreach (get_list_of_plugins($directory) as $plugin) { $enlangdirlocation = $CFG->dirroot.'/'.$directory.'/'.$plugin.'/lang/en_utf8/help'; foreach (get_directory_list($enlangdirlocation, 'CVS') as $file) { if ((substr($file, -5) == '.html') || (substr($file, -4) == '.txt' )) { $fullpath = $enlangdirlocation.'/'.$file; $files[$fullpath] = array( 'filename' => $file, 'location' => $directory, 'plugin' => $plugin, 'prefix' => $prefix, ); } } } } } } return $files; } /** * Return a preview URL for help file, if available. * * @param string $currentfile The relative path to the help file, e.g. "assignment/types.html" - MDL-12291 * @param bool $skiplocal Force displaying the helpfile from a master lang pack * @param string $forcelang Force language of the help, e.g. "en_utf8" * @return string $url */ function lang_help_preview_url($currentfile, $skiplocal=false, $forcelang = '') { $currentpathexp = explode('/', $currentfile); if (count($currentpathexp) > 1) { $url = '/help.php?module='.implode('/',array_slice($currentpathexp,0,count($currentpathexp)-1)).'&file='.end($currentpathexp); } else { $url = '/help.php?module=moodle&file='.$currentfile; } if ($skiplocal) { $url .= '&skiplocal=1'; } if ($forcelang) { $url .= '&forcelang='.$forcelang; } return $url; } /** * Saves (overwrites) translated help file. * * @param string $helproot The path to the "help" folder * @param string $file The relative path to the html help file * @param string $content HTML data to be saved * @return bool False if save failed, true otherwise */ function lang_help_save_file($helproot, $file, $content) { global $CFG, $USER; $content = str_replace("\r", "",$content); // Remove linefeed characters $content = preg_replace("/\n{3,}/", "\n\n", $content); // Collapse runs of blank lines $content = trim($content); // Delete leading/trailing whitespace if (is_readable("$helproot/$file") && filesize("$helproot/$file") > 0 && $content == '') { notify(get_string('langrmyourself', 'admin')); return true; } error_reporting(0); if (!$f = fopen("$helproot/$file","w")) { error_reporting($CFG->debug); return false; } error_reporting($CFG->debug); fwrite($f, stripslashes($content)); fclose($f); // Remove file if its empty if (filesize("$helproot/$file") == 0) { unlink("$helproot/$file"); } return true; } ?>