libdir . '/moodlelib.php'); define('NUM_CALLS', 20000); define('NUM_REPITITIONS', 3); $TEST_LANGUAGES = array('en_utf8', 'fr_utf8', 'fr_ca_utf8', 'nonexistant'); require_login(); require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)); $title = 'get_string performance test'; print_header($title, $title, build_navigation($title)); $installedlangs = get_list_of_languages(); $requiredlangs = $TEST_LANGUAGES; array_pop($requiredlangs); foreach ($requiredlangs as $lang) { if (!isset($installedlangs[$lang])) { notify('You must install the following language packs to run these test: ' . implode(', ', $requiredlangs)); print_footer(); die; } } time_for_loop(); print_heading('Timing calling functions'); time_function_call('dummy_function'); time_function_call('simple_eval'); time_function_call('simple_eval_with_interp'); time_function_call('sprintf_eval'); time_function_call('sprintf_eval_with_interp'); time_function_call('strtr_eval'); time_function_call('strtr_eval_with_interp'); time_function_call('proposed'); time_function_call('proposed_with_interp'); time_log_file('empty.log.php'); unset($COURSE->lang); if (isset($SESSION->lang)) { $originalsessionlang = $SESSION->lang; } else { $originalsessionlang = null; } try { foreach ($TEST_LANGUAGES as $lang) { print_heading("Language '$lang'"); $SESSION->lang = $lang; time_log_file('admin_index.php_get_string.log.php'); time_log_file('course_view.php_get_string.log.php'); time_log_file('admin_index.php_old_get_string.log.php'); time_log_file('course_view.php_old_get_string.log.php'); // test_one_case('info', '', null); // test_one_case('attemptquiznow', 'quiz', null); // $a = new stdClass; // $a->firstname = 'Martin'; // $a->lastname = 'Dougiamas'; // test_one_case('fullnamedisplay', '', $a); // test_one_case('stringthatdoesnotexistinanyfile', 'qtype_shortanswer', null); } } catch(Exception $e) { // Did they really leave finally out of PHP? if (is_null($originalsessionlang)) { unset($SESSION->lang); } else { $SESSION->lang = $originalsessionlang; } } print_footer(); /** * plays back one of the files recored by turning on the logging option in string_manager. * @param $filename * @return unknown_type */ function time_log_file($filename) { global $CFG; print_heading("Playing back calls from $filename", '', 3); $fullpath = $CFG->libdir . '/simpletest/get_string_fixtures/pagelogs/' . $filename; for ($i = 0; $i < NUM_REPITITIONS; ++$i) { set_time_limit(60); $startime = microtime(true); include($fullpath); $duration = microtime(true) - $startime; echo '
Time for ' . $filename . ': ' . format_float($duration, 3) . "s.
\n"; flush(); } } /** * Repeat one call to get_string NUM_CALLS times. * @param $string * @param $module * @param $a */ function test_one_case($string, $module, $a) { print_heading("get_string('$string', '$module', " . print_r($a, true) . ")", '', 3); echo 'Resulting string: ' . get_string($string, $module, $a) . "
\n"; for ($i = 0; $i < NUM_REPITITIONS; ++$i) { set_time_limit(60); $startime = microtime(true); for ($j = 0; $j < NUM_CALLS; $j++) { get_string($string, $module, $a); } $duration = microtime(true) - $startime; print_result_line($duration, 'calls to get_string'); } } function time_for_loop() { print_heading('Timing an empty for loop'); $startime = microtime(true); for ($i = 0; $i < NUM_CALLS; $i++) { } $duration = microtime(true) - $startime; print_result_line($duration, 'trips through an empty for loop', 'iterations per second'); } function simple_eval($string, $module, $a) { $result = ''; $code = '$result = "Language string";'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } return $result; } function simple_eval_with_interp($string, $module, $a) { $result = ''; $code = '$result = "Language string $a->field.";'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } return $result; } function sprintf_eval($string, $module, $a) { $result = ''; $code = '$result = sprintf("Language string");'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } return $result; } function sprintf_eval_with_interp($string, $module, $a) { $result = ''; $code = '$result = sprintf("Language string $a->field.");'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } return $result; } function strtr_eval($string, $module, $a) { $result = ''; $code = '$result = strtr("Language string", "", "");'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } return $result; } function strtr_eval_with_interp($string, $module, $a) { $result = ''; $code = '$result = strtr("Language string $a->field.", "", "");'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } return $result; } function proposed($string, $module, $a) { $result = 'Language string'; if (strpos($result, '$') !== false) { $code = '$result = strtr("' . $result . '", "", "");'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } } return $result; } function proposed_with_interp($string, $module, $a) { $result = 'Language string $a->field.'; if (strpos($result, '$') !== false) { $code = '$result = strtr("' . $result . '", "", "");'; if (eval($code) === FALSE) { // Means parse error. debugging('Parse error while trying to load string "'.$identifier.'" from file "' . $langfile . '".', DEBUG_DEVELOPER); } } return $result; } function dummy_function($string, $module, $a) { } function time_function_call($functionname) { $string = 'string'; $module = 'module'; $a = new stdClass; $a->field = 'value'; $startime = microtime(true); for ($i = 0; $i < NUM_CALLS; $i++) { $functionname($string, $module, $a); } $duration = microtime(true) - $startime; print_result_line($duration, 'calls to ' . $functionname); } function print_result_line($duration, $action1, $action2 = 'calls per second') { echo 'Time for ' . format_float(NUM_CALLS, 0) . ' ' . $action1 . ': ' . format_float($duration, 3) . 's which is ' . format_float((NUM_CALLS / $duration), 0) . ' ' . $action2 . ".
\n"; flush(); } // ============================================================================= // The rest of this file is the old implementation of get_string, with get_string // renamed to old_get_string, so we can do comparative timings. /** * fix up the optional data in get_string()/print_string() etc * ensure possible sprintf() format characters are escaped correctly * needs to handle arbitrary strings and objects * @param mixed $a An object, string or number that can be used * @return mixed the supplied parameter 'cleaned' */ function clean_getstring_data( $a ) { if (is_string($a)) { return str_replace( '%','%%',$a ); } elseif (is_object($a)) { $a_vars = get_object_vars( $a ); $new_a_vars = array(); foreach ($a_vars as $fname => $a_var) { $new_a_vars[$fname] = clean_getstring_data( $a_var ); } return (object)$new_a_vars; } else { return $a; } } /** * @return array places to look for lang strings based on the prefix to the * module name. For example qtype_ in question/type. Used by get_string and * help.php. */ function places_to_search_for_lang_strings() { global $CFG; return array( '__exceptions' => array('moodle', 'langconfig'), 'assignment_' => array('mod/assignment/type'), 'auth_' => array('auth'), 'block_' => array('blocks'), 'datafield_' => array('mod/data/field'), 'datapreset_' => array('mod/data/preset'), 'enrol_' => array('enrol'), 'filter_' => array('filter'), 'format_' => array('course/format'), 'quiz_' => array('mod/quiz/report'), 'qtype_' => array('question/type'), 'qformat_' => array('question/format'), 'report_' => array($CFG->admin.'/report', 'course/report'), 'repository_'=>array('repository'), 'resource_' => array('mod/resource/type'), 'gradereport_' => array('grade/report'), 'gradeimport_' => array('grade/import'), 'gradeexport_' => array('grade/export'), 'profilefield_' => array('user/profile/field'), 'portfolio_' => array('portfolio/type'), '' => array('mod') ); } /** * Returns a localized string. * * Returns the translated string specified by $identifier as * for $module. Uses the same format files as STphp. * $a is an object, string or number that can be used * within translation strings * * eg "hello \$a->firstname \$a->lastname" * or "hello \$a" * * If you would like to directly echo the localized string use * the function {@link print_string()} * * Example usage of this function involves finding the string you would * like a local equivalent of and using its identifier and module information * to retrive it.
* $string['wordforstudent'] = 'Your word for Student';
*
* So if you want to display the string 'Your word for student'
* in any language that supports it on your site
* you just need to use the identifier 'wordforstudent'
*
* $mystring = ''. get_string('wordforstudent') .'';
or
*
* If the string you want is in another file you'd take a slightly
* different approach. Looking in moodle/lang/en/calendar.php you find
* around line 75:
*
* $string['typecourse'] = 'Course event';
*
* If you want to display the string "Course event" in any language
* supported you would use the identifier 'typecourse' and the module 'calendar'
* (because it is in the file calendar.php):
*
* $mystring = ''. get_string('typecourse', 'calendar') .'
';
*
*
* As a last resort, should the identifier fail to map to a string
* the returned string will be [[ $identifier ]]
*
* @uses $CFG
* @param string $identifier The key identifier for the localized string
* @param string $module The module where the key identifier is stored,
* usually expressed as the filename in the language pack without the
* .php on the end but can also be written as mod/forum or grade/export/xls.
* If none is specified then moodle.php is used.
* @param mixed $a An object, string or number that can be used
* within translation strings
* @param array $extralocations DEPRICATED. An array of strings with other
* locations to look for string files. This used to be used by plugins so
* they could package their language strings in the plugin folder, however,
* There is now a better way to achieve this. See
* http://docs.moodle.org/en/Development:Places_to_search_for_lang_strings.
* @return string The localized string.
*/
function old_get_string($identifier, $module='', $a=NULL, $extralocations=NULL) {
global $CFG;
/// originally these special strings were stored in moodle.php now we are only in langconfig.php
$langconfigstrs = array('alphabet', 'backupnameformat', 'decsep', 'firstdayofweek', 'listsep', 'locale',
'localewin', 'localewincharset', 'oldcharset', 'parentlanguage',
'strftimedate', 'strftimedateshort', 'strftimedatefullshort', 'strftimedatetime',
'strftimedaydate', 'strftimedaydatetime', 'strftimedayshort', 'strftimedaytime',
'strftimemonthyear', 'strftimerecent', 'strftimerecentfull', 'strftimetime',
'thischarset', 'thisdirection', 'thislanguage', 'strftimedatetimeshort', 'thousandssep');
$filetocheck = 'langconfig.php';
$defaultlang = 'en_utf8';
if (in_array($identifier, $langconfigstrs)) {
$module = 'langconfig'; //This strings are under langconfig.php for 1.6 lang packs
}
$lang = current_language();
if ($module == '') {
$module = 'moodle';
}
/// If the "module" is actually a pathname, then automatically derive the proper module name
if (strpos($module, '/') !== false) {
$modulepath = split('/', $module);
switch ($modulepath[0]) {
case 'mod':
$module = $modulepath[1];
break;
case 'blocks':
case 'block':
$module = 'block_'.$modulepath[1];
break;
case 'enrol':
$module = 'enrol_'.$modulepath[1];
break;
case 'format':
$module = 'format_'.$modulepath[1];
break;
case 'grade':
$module = 'grade'.$modulepath[1].'_'.$modulepath[2];
break;
}
}
/// if $a happens to have % in it, double it so sprintf() doesn't break
if ($a) {
$a = clean_getstring_data( $a );
}
/// Define the two or three major locations of language strings for this module
$locations = array();
if (!empty($extralocations)) {
// This is an old, deprecated mechanism that predates the
// places_to_search_for_lang_strings mechanism that comes later in
// this function. So tell people who use it to change.
debugging('The fourth, $extralocations parameter to get_string is deprecated. ' .
'See http://docs.moodle.org/en/Development:Places_to_search_for_lang_strings ' .
'for a better way to package language strings with your plugin.', DEBUG_DEVELOPER);
if (is_array($extralocations)) {
$locations += $extralocations;
} else if (is_string($extralocations)) {
$locations[] = $extralocations;
} else {
debugging('Bad lang path provided');
}
}
if (!empty($CFG->running_installer) and $lang !== 'en_utf8') {
static $stringnames = null;
if (!$stringnames) {
$stringnames = file($CFG->dirroot.'/install/stringnames.txt');
$stringnames = array_map('trim', $stringnames);
}
if (array_search($identifier, $stringnames) !== false) {
$module = 'installer';
$filetocheck = 'installer.php';
$defaultlang = 'en_utf8';
$locations[] = $CFG->dirroot.'/install/lang/';
}
}
$locations[] = $CFG->dataroot.'/lang/';
$locations[] = $CFG->dirroot.'/lang/';
$locations[] = $CFG->dirroot.'/local/lang/';
/// Add extra places to look for strings for particular plugin types.
$rules = places_to_search_for_lang_strings();
$exceptions = $rules['__exceptions'];
unset($rules['__exceptions']);
if (!in_array($module, $exceptions)) {
$dividerpos = strpos($module, '_');
if ($dividerpos === false) {
$type = '';
$plugin = $module;
} else {
$type = substr($module, 0, $dividerpos + 1);
$plugin = substr($module, $dividerpos + 1);
}
if (!empty($rules[$type])) {
foreach ($rules[$type] as $location) {
$locations[] = $CFG->dirroot . "/$location/$plugin/lang/";
}
}
}
/// First check all the normal locations for the string in the current language
$resultstring = '';
foreach ($locations as $location) {
$locallangfile = $location.$lang.'_local'.'/'.$module.'.php'; //first, see if there's a local file
if (file_exists($locallangfile)) {
if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) {
if (eval($result) === FALSE) {
trigger_error('Lang error: '.$identifier.':'.$locallangfile, E_USER_NOTICE);
}
return $resultstring;
}
}
//if local directory not found, or particular string does not exist in local direcotry
$langfile = $location.$lang.'/'.$module.'.php';
if (file_exists($langfile)) {
if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
if (eval($result) === FALSE) {
trigger_error('Lang error: '.$identifier.':'.$langfile, E_USER_NOTICE);
}
return $resultstring;
}
}
}
/// If the preferred language was English (utf8) we can abort now
/// saving some checks beacuse it's the only "root" lang
if ($lang == 'en_utf8') {
return '[['. $identifier .']]';
}
/// Is a parent language defined? If so, try to find this string in a parent language file
foreach ($locations as $location) {
$langfile = $location.$lang.'/'.$filetocheck;
if (file_exists($langfile)) {
if ($result = get_string_from_file('parentlanguage', $langfile, "\$parentlang")) {
if (eval($result) === FALSE) {
trigger_error('Lang error: '.$identifier.':'.$langfile, E_USER_NOTICE);
}
if (!empty($parentlang) and strpos($parentlang, '<') === false) { // found it!
//first, see if there's a local file for parent
$locallangfile = $location.$parentlang.'_local'.'/'.$module.'.php';
if (file_exists($locallangfile)) {
if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) {
if (eval($result) === FALSE) {
trigger_error('Lang error: '.$identifier.':'.$locallangfile, E_USER_NOTICE);
}
return $resultstring;
}
}
//if local directory not found, or particular string does not exist in local direcotry
$langfile = $location.$parentlang.'/'.$module.'.php';
if (file_exists($langfile)) {
if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
eval($result);
return $resultstring;
}
}
}
}
}
}
/// Our only remaining option is to try English
foreach ($locations as $location) {
$locallangfile = $location.$defaultlang.'_local/'.$module.'.php'; //first, see if there's a local file
if (file_exists($locallangfile)) {
if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) {
eval($result);
return $resultstring;
}
}
//if local_en not found, or string not found in local_en
$langfile = $location.$defaultlang.'/'.$module.'.php';
if (file_exists($langfile)) {
if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
eval($result);
return $resultstring;
}
}
}
/// And, because under 1.6 en is defined as en_utf8 child, me must try
/// if it hasn't been queried before.
if ($defaultlang == 'en') {
$defaultlang = 'en_utf8';
foreach ($locations as $location) {
$locallangfile = $location.$defaultlang.'_local/'.$module.'.php'; //first, see if there's a local file
if (file_exists($locallangfile)) {
if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) {
eval($result);
return $resultstring;
}
}
//if local_en not found, or string not found in local_en
$langfile = $location.$defaultlang.'/'.$module.'.php';
if (file_exists($langfile)) {
if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
eval($result);
return $resultstring;
}
}
}
}
return '[['.$identifier.']]'; // Last resort
}
/**
* This function is only used from {@link get_string()}.
*
* @internal Only used from get_string, not meant to be public API
* @param string $identifier ?
* @param string $langfile ?
* @param string $destination ?
* @return string|false ?
* @staticvar array $strings Localized strings
* @access private
* @todo Finish documenting this function.
*/
function get_string_from_file($identifier, $langfile, $destination) {
static $strings; // Keep the strings cached in memory.
if (empty($strings[$langfile])) {
$string = array();
include ($langfile);
$strings[$langfile] = $string;
} else {
$string = &$strings[$langfile];
}
if (!isset ($string[$identifier])) {
return false;
}
return $destination .'= sprintf("'. $string[$identifier] .'");';
}
?>