diff -ur moodle-original/admin/lang.php moodle/admin/lang.php
--- moodle-original/admin/lang.php	2009-11-27 02:02:50.000000000 +0200
+++ moodle/admin/lang.php	2010-03-21 09:04:24.347796904 +0200
@@ -34,6 +34,9 @@
         $currentfile = optional_param('currentfile', LANG_DEFAULT_HELPFILE, PARAM_PATH);
     } else {
         $currentfile = optional_param('currentfile', LANG_DEFAULT_FILE, PARAM_FILE);
+        // some language files are really big (ie. moodle.php) and take long to load
+        // we use this parameter to allow quick single string editing
+        $currentstr = optional_param('currentstr', '', PARAM_TEXT);
     }
     $uselocal = optional_param('uselocal', -1, PARAM_INT);
 
@@ -533,6 +536,11 @@
                 $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. >>";
                 $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 >>";
             }
+            // if a particular string was requested, then we will show/edit only
+            // that string to make working with large files (like moodle.php) faster 
+            if ($currentstr) {
+                $enstring = array($currentstr => $enstring[$currentstr]);
+            }
             unset($string);
             ksort($enstring);
 
@@ -672,6 +680,7 @@
                 $o .= '<tr><td>&nbsp;</td><td><br />';
                 $o .= '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
                 $o .= '<input type="hidden" name="currentfile" value="'.$currentfile.'" />';
+                $o .= '<input type="hidden" name="currentstr" value="'.$currentstr.'" />';
                 $o .= '<input type="hidden" name="mode" value="compare" />';
                 $o .= '<input type="submit" name="update" tabindex="'.$missingcounter.'" value="'.get_string('savechanges').': '.$currentfile.'" />';
                 $o .= '</td></tr>';
diff -ur moodle-original/lib/moodlelib.php moodle/lib/moodlelib.php
--- moodle-original/lib/moodlelib.php	2010-02-25 02:03:05.000000000 +0200
+++ moodle/lib/moodlelib.php	2010-03-20 23:13:33.604544639 +0200
@@ -5297,6 +5297,36 @@
 }
 
 /**
+ * Caches results of get_string for click-to-translate actions.
+ * 
+ * If the current user has moodle/site:langeditlocal or moodle/site:langeditmaster 
+ * capabilities then the function caches the parameters and result of get_string 
+ * in order to be used for click-to-translate actions.
+ *
+ * @param string $identifier The key identifier for the localized string
+ * @param string $langfile The language file (including .php) where the key 
+ * identifier is stored.
+ * @param string $result The output of get_string call (including $a variable 
+ * substitutions)
+ * @return null on normal call (stores data); or the cached data (sorted string 
+ * length) if $identifier or $langfile are null
+ */
+function store_get_string_result($identifier, $langfile, $result) {
+    static $strings;
+    $context = get_system_context();
+    if (!has_capability('moodle/site:langeditlocal', $context, 0, false) &&
+		    !has_capability('moodle/site:langeditmaster', $context, 0, false)) {
+       return;
+	  }
+	
+    if(is_null($identifier) && is_null($langfile)) {
+        uasort($strings, create_function('$a,$b', 'return strlen($b) - strlen($a)'));
+        return $strings;
+    }
+    $strings["$langfile#$identifier"] = $result;
+}
+
+/**
  * Returns a localized string.
  *
  * Returns the translated string specified by $identifier as
@@ -5464,6 +5494,7 @@
                 if (eval($result) === FALSE) {
                     trigger_error('Lang error: '.$identifier.':'.$locallangfile, E_USER_NOTICE);
                 }
+                store_get_string_result($identifier, $module . '.php', $resultstring);
                 return $resultstring;
             }
         }
@@ -5474,6 +5505,7 @@
                 if (eval($result) === FALSE) {
                     trigger_error('Lang error: '.$identifier.':'.$langfile, E_USER_NOTICE);
                 }
+                store_get_string_result($identifier, $module . '.php', $resultstring);
                 return $resultstring;
             }
        }
@@ -5503,6 +5535,7 @@
                             if (eval($result) === FALSE) {
                                 trigger_error('Lang error: '.$identifier.':'.$locallangfile, E_USER_NOTICE);
                             }
+                            store_get_string_result($identifier, $module . '.php', $resultstring);
                             return $resultstring;
                         }
                     }
@@ -5512,6 +5545,7 @@
                     if (file_exists($langfile)) {
                         if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
                             eval($result);
+                            store_get_string_result($identifier, $module . '.php', $resultstring);
                             return $resultstring;
                         }
                     }
@@ -5527,6 +5561,7 @@
         if (file_exists($locallangfile)) {
             if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) {
                 eval($result);
+                store_get_string_result($identifier, $module . '.php', $resultstring);
                 return $resultstring;
             }
         }
@@ -5537,6 +5572,7 @@
         if (file_exists($langfile)) {
             if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
                 eval($result);
+                store_get_string_result($identifier, $module . '.php', $resultstring);
                 return $resultstring;
             }
         }
@@ -5551,6 +5587,7 @@
             if (file_exists($locallangfile)) {
                 if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) {
                     eval($result);
+                    store_get_string_result($identifier, $module . '.php', $resultstring);
                     return $resultstring;
                 }
             }
@@ -5561,6 +5598,7 @@
             if (file_exists($langfile)) {
                 if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) {
                     eval($result);
+                    store_get_string_result($identifier, $module . '.php', $resultstring);
                     return $resultstring;
                 }
             }
diff -ur moodle-original/lib/weblib.php moodle/lib/weblib.php
--- moodle-original/lib/weblib.php	2010-03-11 02:03:24.000000000 +0200
+++ moodle/lib/weblib.php	2010-03-20 23:47:55.792543396 +0200
@@ -3066,6 +3066,89 @@
 /// Include the actual footer file
 
     ob_start();
+    // if we cached the results of get_string, then it means we can edit the 
+    // language files; therefore, we enable the click-to-translate feature
+    if($strings = store_get_string_result(NULL, NULL, NULL)) {
+        // FOR PHP 4:
+        // PHP 4 does not have json_encode. A add-on function can be found 
+        // here: http://www.php.net/manual/en/function.json-encode.php#82904
+        // save it into the json_encode.php file in the moodle lib directory
+        // and uncomment the following line
+        // include_once(dirname(__FILE__) . '/json_encode.php');
+        echo '
+<script type="text/javascript" src="http://www.google.com/jsapi"></script>
+<script type="text/javascript">
+  google.load("jquery", "1.4.1")
+  // this array contains translatable strings an their source (language file 
+  // and key identifier used)
+  var langdict = ', json_encode($strings) , '
+  var wwwroot = "', $CFG->wwwroot , '"
+</script>';
+        echo <<<JS
+<script type="text/javascript">
+$(function() {
+  // create a place to display translatable strings options
+  $('<div id="translation_console">')
+    .hide()
+    .css({
+      position: 'absolute',
+      zIndex: 1000,
+      background: 'white',
+      color: 'black',
+      width: '300px',
+      height: '300px',
+      overflow: 'scroll'
+    })
+    .mouseleave(function() { $(this).fadeOut(1000) })
+    .appendTo('body')
+})
+
+// when the user right-click on a element while pressing the control key
+// we will display the translateable texts from that element's HTML instead of 
+// the element contextual menu
+$(document).mousedown(function(e){
+  if(e.ctrlKey && e.which == 3) {
+    // take control over the next display of the contextual menu
+    $(e.target).one('contextmenu',function(event){
+      // clear the translation console
+      var console = $('#translation_console').html('')
+      // read the full HTML of the target element
+      var targetHtml = $('<div>').append($(event.target).clone()).html()
+      // find translatable string withing the target element's HTML
+      for(var key in langdict) {
+        if (targetHtml.indexOf(langdict[key]) != -1) {
+          // parse the file and string identifier
+          var data = key.split('#', 2)
+          // find the editing form URL (including current string and page fragment)
+          var formurl = wwwroot + '/admin/lang.php?mode=compare&currentfile=' + data[0] + '&currentstr=' + data[1] + '#' + data[1]
+          // add a link into the translation console that opens the editing form
+          // in a new frame with a name based on the string key and file
+          $('<a>')
+            .css('display', 'block')
+            .attr('href', formurl)
+            .attr('target', key)
+            .text(langdict[key])
+            .appendTo(console)
+        }
+      }
+      
+      // try to center the translation console around the mouse position, 
+      // but without puting it outside the window boundaries
+      var left = event.pageX - console.width() / 2
+      var top = event.pageY - console.height() / 2
+      left = Math.max(0, Math.min(left, $(document).width() - console.width() / 2))
+      top = Math.max(0, Math.min(top, $(document).height() - console.height() / 2))
+      // display the console
+      console.css({left: left, top: top}).show()
+      // prevent the real contextual menu to show up
+      return false;
+    });
+  }
+})
+</script>
+JS
+;
+	}
     include($CFG->footer);
     $output = ob_get_contents();
     ob_end_clean();
