includes/pageutils.php
changeset 229 97ae8e9d5e29
parent 227 0eca1498a77b
child 238 a78537db2850
--- a/includes/pageutils.php	Thu Sep 27 15:55:37 2007 -0400
+++ b/includes/pageutils.php	Sat Nov 03 07:43:35 2007 -0400
@@ -1,7 +1,8 @@
 <?php
+
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0.2 (Coblynau)
+ * Version 1.1.1
  * Copyright (C) 2006-2007 Dan Fuhry
  * pageutils.php - a class that handles raw page manipulations, used mostly by AJAX requests or their old-fashioned form-based counterparts
  *
@@ -15,18 +16,27 @@
 class PageUtils {
   
   /**
-   * List possible username completions
+   * Tell if a username is used or not.
    * @param $name the name to check for
-   * @return array
+   * @return string
    */
   
   function checkusername($name)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE username=\''.$db->escape(rawurldecode($name)).'\'');
-    if(!$q) die(mysql_error());
-    if($db->numrows() < 1) { $db->free_result(); return('good'); }
-    else { $db->free_result(); return('bad'); }
+    $q = $db->sql_query('SELECT username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape(rawurldecode($name)) . '\'');
+    if ( !$q )
+    {
+      die(mysql_error());
+    }
+    if ( $db->numrows() < 1)
+    {
+      $db->free_result(); return('good');
+    }
+    else
+    {
+      $db->free_result(); return('bad');
+    }
   }
   
   /**
@@ -57,10 +67,10 @@
     $pid = RenderMan::strToPageID($page);
     if($pid[1] == 'Special' || $pid[1] == 'Admin')
     {
-      die('This type of page ('.$paths->nslist[$pid[1]].') cannot be edited because the page source code is not stored in the database.');
+      die('This type of page (' . $paths->nslist[$pid[1]] . ') cannot be edited because the page source code is not stored in the database.');
     }
     
-    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$pid[0].'\' AND namespace=\''.$pid[1].'\'');
+    $e = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix.'page_text WHERE page_id=\'' . $pid[0] . '\' AND namespace=\'' . $pid[1] . '\'');
     if ( !$e )
     {
       $db->_die('The page text could not be selected.');
@@ -123,7 +133,7 @@
         return $r;
       }
       
-      $fname = 'page_'.$pid[1].'_'.$paths->pages[$page]['urlname_nons'];
+      $fname = 'page_' . $pid[1] . '_' . $paths->pages[$page]['urlname_nons'];
       @call_user_func($fname);
       
     }
@@ -147,7 +157,7 @@
         return $r;
       }
       
-      $fname = 'page_'.$pid[1].'_'.$pid[0];
+      $fname = 'page_' . $pid[1] . '_' . $pid[0];
       if ( !function_exists($fname) )
       {
         $title = 'Page backend not found';
@@ -190,12 +200,17 @@
                <p>You have requested a page that doesn\'t exist yet.';
         if($session->get_permissions('create_page')) echo ' You can <a href="'.makeUrl($paths->page, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
         else echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
-        if($session->get_permissions('history_rollback')) {
-          $e = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE action=\'delete\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' ORDER BY time_id DESC;');
-          if(!$e) $db->_die('The deletion log could not be selected.');
-          if($db->numrows() > 0) {
+        if ( $session->get_permissions('history_rollback') )
+        {
+          $e = $db->sql_query('SELECT * FROM ' . table_prefix.'logs WHERE action=\'delete\' AND page_id=\'' . $paths->cpage['urlname_nons'] . '\' AND namespace=\'' . $pid[1] . '\' ORDER BY time_id DESC;');
+          if ( !$e )
+          {
+            $db->_die('The deletion log could not be selected.');
+          }
+          if ($db->numrows() > 0 )
+          {
             $r = $db->fetchrow();
-            echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on '.$r['date_string'].'. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
+            echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on ' . $r['date_string'] . '. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id=' . $r['time_id']) . '" onclick="ajaxRollback(\'' . $r['time_id'] . '\'); return false;">roll back</a> the deletion.</p>';
           }
           $db->free_result();
         }
@@ -233,15 +248,16 @@
         return $text;
       }
       
-      if($hist_id) {
-        $e = $db->sql_query('SELECT page_text,date_string,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$paths->pages[$page]['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' AND log_type=\'page\' AND action=\'edit\' AND time_id='.$db->escape($hist_id).'');
+      if ( $hist_id )
+      {
+        $e = $db->sql_query('SELECT page_text,date_string,char_tag FROM ' . table_prefix.'logs WHERE page_id=\'' . $paths->pages[$page]['urlname_nons'] . '\' AND namespace=\'' . $pid[1] . '\' AND log_type=\'page\' AND action=\'edit\' AND time_id=' . $db->escape($hist_id) . '');
         if($db->numrows() < 1)
         {
           $db->_die('There were no rows in the text table that matched the page text query.');
         }
         $r = $db->fetchrow();
         $db->free_result();
-        $message = '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.$r['date_string'].'.<br /><a href="'.makeUrl($page).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrl($page, 'do=rollback&amp;id='.$hist_id).'" onclick="ajaxRollback(\''.$hist_id.'\')">Restore this version</a></div><br />'.RenderMan::render($r['page_text']);
+        $message = '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on ' . $r['date_string'] . '.<br /><a href="'.makeUrl($page).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrl($page, 'do=rollback&amp;id=' . $hist_id) . '" onclick="ajaxRollback(\'' . $hist_id . '\')">Restore this version</a></div><br />'.RenderMan::render($r['page_text']);
         
         if( !$paths->pages[$page]['special'] )
         {
@@ -252,7 +268,7 @@
           display_page_headers();
         }
         
-        eval('?>'.$message);
+        eval('?>' . $message);
         
         if( !$paths->pages[$page]['special'] )
         {
@@ -286,7 +302,7 @@
 
         // This is it, this is what all of Enano has been working up to...
         
-        eval('?>'.$message);
+        eval('?>' . $message);
         
         if( !$paths->pages[$page]['special'] )
         {
@@ -322,8 +338,9 @@
     
     if(!isset($paths->pages[$pname]))
     {
-      if(!PageUtils::createPage($page_id, $namespace))
-        return 'The page did not exist, and I was not able to create it. Permissions problem?';
+      $create = PageUtils::createPage($page_id, $namespace);
+      if ( $create != 'good' )
+        return 'The page did not exist, and I was not able to create it. The reported error was: ' . $create;
       $paths->page_exists = true;
     }
     
@@ -337,10 +354,10 @@
     $msg = $db->escape($message);
     
     $minor = $minor ? 'true' : 'false';
-    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$msg.'\', \''.$uid.'\', \''.$session->username.'\', \''.$db->escape(htmlspecialchars($summary)).'\', '.$minor.');';
+    $q='INSERT INTO ' . table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \'' . $paths->cpage['urlname_nons'] . '\', \'' . $paths->namespace . '\', \'' . $msg . '\', \'' . $uid . '\', \'' . $session->username . '\', \'' . $db->escape(htmlspecialchars($summary)) . '\', ' . $minor . ');';
     if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
     
-    $q = 'UPDATE '.table_prefix.'page_text SET page_text=\''.$msg.'\',char_tag=\''.$uid.'\' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';';
+    $q = 'UPDATE ' . table_prefix.'page_text SET page_text=\'' . $msg . '\',char_tag=\'' . $uid . '\' WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';';
     $e = $db->sql_query($q);
     if(!$e) $db->_die('Enano was unable to save the page contents. Your changes have been lost <tt>:\'(</tt>.');
       
@@ -362,32 +379,38 @@
     if(in_array($namespace, Array('Special', 'Admin')))
     {
       // echo '<b>Notice:</b> PageUtils::createPage: You can\'t create a special page in the database<br />';
-      return false; // Can't create a special page
+      return 'You can\'t create a special page in the database';
     }
     
     if(!isset($paths->nslist[$namespace]))
     {
       // echo '<b>Notice:</b> PageUtils::createPage: Couldn\'t look up the namespace<br />';
-      return false; // Couldn't look up namespace
+      return 'Couldn\'t look up the namespace';
     }
     
     $pname = $paths->nslist[$namespace] . $page_id;
     if(isset($paths->pages[$pname]))
     {
       // echo '<b>Notice:</b> PageUtils::createPage: Page already exists<br />';
-      return false; // Page already exists
+      return 'Page already exists';
     }
     
     if(!$session->get_permissions('create_page'))
     {
       // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create pages<br />';
-      return false; // Access denied
+      return 'Not authorized to create pages';
     }
     
     if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System')
     {
       // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create system messages<br />';
-      return false; // Not authorized to create system messages
+      return 'Not authorized to create system messages';
+    }
+    
+    if ( substr($page_id, 0, 8) == 'Project:' )
+    {
+      // echo '<b>Notice:</b> PageUtils::createPage: Prefix "Project:" is reserved<br />';
+      return 'The prefix "Project:" is reserved for a parser shortcut; if a page was created using this prefix, it would not be possible to link to it.';
     }
     
     $page_id = dirtify_page_id($page_id);
@@ -398,7 +421,7 @@
     if(!preg_match($regex, $page))
     {
       //echo '<b>Notice:</b> PageUtils::createPage: Name contains invalid characters<br />';
-      return false; // Name contains invalid characters
+      return 'Name contains invalid characters';
     }
     
     $page_id = sanitize_page_id( $page_id );
@@ -421,16 +444,15 @@
     
     $paths->add_page($page_data);
     
-    $qa = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace,visible,protected,delvote_ips) VALUES(\''.$db->escape($name).'\', \''.$db->escape($page_id).'\', \''.$namespace.'\', '. ( $visible ? '1' : '0' ) .', '.$prot.', \'' . $db->escape(serialize($ips)) . '\');');
-    $qb = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace) VALUES(\''.$db->escape($page_id).'\', \''.$namespace.'\');');
-    $qc = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$db->escape($page_id).'\', \''.$namespace.'\');');
+    $qa = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace,visible,protected,delvote_ips) VALUES(\'' . $db->escape($name) . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\', '. ( $visible ? '1' : '0' ) .', ' . $prot . ', \'' . $db->escape(serialize($ips)) . '\');');
+    $qb = $db->sql_query('INSERT INTO ' . table_prefix.'page_text(page_id,namespace) VALUES(\'' . $db->escape($page_id) . '\', \'' . $namespace . '\');');
+    $qc = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'create\', \'' . $session->username . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\');');
     
     if($qa && $qb && $qc)
-      return true;
+      return 'good';
     else
     {
-      echo $db->get_error();
-      return false;
+      return $db->get_error();
     }
   }
   
@@ -450,31 +472,41 @@
     $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
     $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
     
-    if(!$session->get_permissions('protect')) return('Insufficient access rights');
-    if(!$wiki) return('Page protection only has an effect when Wiki Mode is enabled.');
-    if(!preg_match('#^([0-9]+){1}$#', (string)$level)) return('Invalid $level parameter.');
-    
-    if($reason!='NO_REASON') {
-      switch($level)
-      {
-        case 0:
-          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'unprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
-          break;
-        case 1:
-          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'prot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
-          break;
-        case 2:
-          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'semiprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
-          break;
-        default:
-          return 'PageUtils::protect(): Invalid value for $level';
-          break;
-      }
-      if(!$db->sql_query($q)) $db->_die('The log entry for the page protection could not be inserted.');
+    if ( !$session->get_permissions('protect') )
+    {
+      return('Insufficient access rights');
+    }
+    if ( !$wiki )
+    {
+      return('Page protection only has an effect when Wiki Mode is enabled.');
+    }
+    if ( !preg_match('#^([0-9]+){1}$#', (string)$level) )
+    {
+      return('Invalid $level parameter.');
     }
     
-    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET protected='.$_POST['level'].' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$q) $db->_die('The pages table was not updated.');
+    switch($level)
+    {
+      case 0:
+        $q = 'INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'unprot\', \'' . $session->username . '\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $db->escape(htmlspecialchars($reason)) . '\');';
+        break;
+      case 1:
+        $q = 'INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'prot\', \'' . $session->username . '\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $db->escape(htmlspecialchars($reason)) . '\');';
+        break;
+      case 2:
+        $q = 'INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'semiprot\', \'' . $session->username . '\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $db->escape(htmlspecialchars($reason)) . '\');';
+        break;
+      default:
+        return 'PageUtils::protect(): Invalid value for $level';
+        break;
+    }
+    if(!$db->sql_query($q)) $db->_die('The log entry for the page protection could not be inserted.');
+    
+    $q = $db->sql_query('UPDATE ' . table_prefix.'pages SET protected=' . $level . ' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
+    if ( !$q )
+    {
+      $db->_die('The pages table was not updated.');
+    }
     
     return('good');
   }
@@ -489,6 +521,7 @@
   function histlist($page_id, $namespace)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     
     if(!$session->get_permissions('history_view'))
       return 'Access denied';
@@ -499,16 +532,19 @@
     $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
     $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
     
-    $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' ORDER BY time_id DESC;';
-    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
-    echo 'History of edits and actions<h3>Edits:</h3>';
+    $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit FROM ' . table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' ORDER BY time_id DESC;';
+    if(!$db->sql_query($q)) $db->_die('The history data for the page "' . $paths->cpage['name'] . '" could not be selected.');
+    echo $lang->get('history_page_subtitle') . '
+          <h3>' . $lang->get('history_heading_edits') . '</h3>';
     $numrows = $db->numrows();
-    if($numrows < 1) echo 'No history entries in this category.';
+    if ( $numrows < 1 )
+    {
+      echo $lang->get('history_no_entries');
+    }
     else
     {
-      
       echo '<form action="'.makeUrlNS($namespace, $page_id, 'do=diff').'" onsubmit="ajaxHistDiff(); return false;" method="get">
-            <input type="submit" value="Compare selected revisions" />
+            <input type="submit" value="' . $lang->get('history_btn_compare') . '" />
             ' . ( urlSeparator == '&' ? '<input type="hidden" name="title" value="' . htmlspecialchars($paths->nslist[$namespace] . $page_id) . '" />' : '' ) . '
             ' . ( $session->sid_super ? '<input type="hidden" name="auth"  value="' . $session->sid_super . '" />' : '') . '
             <input type="hidden" name="do" value="diff" />
@@ -516,17 +552,18 @@
             <div class="tblholder">
             <table border="0" width="100%" cellspacing="1" cellpadding="4">
             <tr>
-              <th colspan="2">Diff</th>
-              <th>Date/time</th>
-              <th>User</th>
-              <th>Edit summary</th>
-              <th>Minor</th>
-              <th colspan="3">Actions</th>
+              <th colspan="2">' . $lang->get('history_col_diff') . '</th>
+              <th>' . $lang->get('history_col_datetime') . '</th>
+              <th>' . $lang->get('history_col_user') . '</th>
+              <th>' . $lang->get('history_col_summary') . '</th>
+              <th>' . $lang->get('history_col_minor') . '</th>
+              <th colspan="3">' . $lang->get('history_col_actions') . '</th>
             </tr>'."\n"."\n";
       $cls = 'row2';
       $ticker = 0;
       
-      while($r = $db->fetchrow()) {
+      while ( $r = $db->fetchrow() )
+      {
         
         $ticker++;
         
@@ -551,29 +588,42 @@
           $s1 = '';
           $s2 = '';
         }
-        if($ticker > 1)        echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s1.'name="diff1" type="radio" value="'.$r['time_id'].'" id="diff1_'.$r['time_id'].'" class="clsDiff1Radio" onclick="selectDiff1Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
-        if($ticker < $numrows) echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s2.'name="diff2" type="radio" value="'.$r['time_id'].'" id="diff2_'.$r['time_id'].'" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
+        if($ticker > 1)        echo '<td class="' . $cls . '" style="padding: 0;"><input ' . $s1 . 'name="diff1" type="radio" value="' . $r['time_id'] . '" id="diff1_' . $r['time_id'] . '" class="clsDiff1Radio" onclick="selectDiff1Button(this);" /></td>'."\n"; else echo '<td class="' . $cls . '"></td>';
+        if($ticker < $numrows) echo '<td class="' . $cls . '" style="padding: 0;"><input ' . $s2 . 'name="diff2" type="radio" value="' . $r['time_id'] . '" id="diff2_' . $r['time_id'] . '" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="' . $cls . '"></td>';
         
         // Date and time
-        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">'."\n";
+        echo '<td class="' . $cls . '">' . $r['date_string'] . '</td class="' . $cls . '">'."\n";
         
         // User
-        if($session->get_permissions('mod_misc') && preg_match('#^([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}$#', $r['author'])) $rc = ' style="cursor: pointer;" title="Click cell background for reverse DNS info" onclick="ajaxReverseDNS(this, \''.$r['author'].'\');"';
-        else $rc = '';
-        echo '<td class="'.$cls.'"'.$rc.'><a href="'.makeUrlNS('User', $r['author']).'" ';
-        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
-        echo '>'.$r['author'].'</a></td class="'.$cls.'">'."\n";
+        if ( $session->get_permissions('mod_misc') && is_valid_ip($r['author']) )
+        {
+          $rc = ' style="cursor: pointer;" title="' . $lang->get('history_tip_rdns') . '" onclick="ajaxReverseDNS(this, \'' . $r['author'] . '\');"';
+        }
+        else
+        {
+          $rc = '';
+        }
+        echo '<td class="' . $cls . '"' . $rc . '><a href="'.makeUrlNS('User', $r['author']).'" ';
+        if ( !isPage($paths->nslist['User'] . $r['author']) )
+        {
+          echo 'class="wikilink-nonexistent"';
+        }
+        echo '>' . $r['author'] . '</a></td class="' . $cls . '">'."\n";
         
         // Edit summary
-        echo '<td class="'.$cls.'">'.$r['edit_summary'].'</td>'."\n";
+        if ( $r['edit_summary'] == 'Automatic backup created when logs were purged' )
+        {
+          $r['edit_summary'] = $lang->get('history_summary_clearlogs');
+        }
+        echo '<td class="' . $cls . '">' . $r['edit_summary'] . '</td>'."\n";
         
         // Minor edit
-        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>'."\n";
+        echo '<td class="' . $cls . '" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>'."\n";
         
         // Actions!
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'oldid='.$r['time_id']).'" onclick="ajaxHistView(\''.$r['time_id'].'\'); return false;">View revision</a></td>'."\n";
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>'."\n";
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert to this revision</a></td>'."\n";
+        echo '<td class="' . $cls . '" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'oldid=' . $r['time_id']) . '" onclick="ajaxHistView(\'' . $r['time_id'] . '\'); return false;">' . $lang->get('history_action_view') . '</a></td>'."\n";
+        echo '<td class="' . $cls . '" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/' . $r['author']) . '">' . $lang->get('history_action_contrib') . '</a></td>'."\n";
+        echo '<td class="' . $cls . '" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id=' . $r['time_id']) . '" onclick="ajaxRollback(\'' . $r['time_id'] . '\'); return false;">' . $lang->get('history_action_restore') . '</a></td>'."\n";
         
         echo '</tr>'."\n"."\n";
         
@@ -582,18 +632,33 @@
             </div>
             <br />
             <input type="hidden" name="do" value="diff" />
-            <input type="submit" value="Compare selected revisions" />
+            <input type="submit" value="' . $lang->get('history_btn_compare') . '" />
             </form>
             <script type="text/javascript">if ( !KILL_SWITCH ) { buildDiffList(); }</script>';
     }
     $db->free_result();
-    echo '<h3>Other changes:</h3>';
-    $q = 'SELECT time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action!=\'edit\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\' ORDER BY time_id DESC;';
-    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
-    if($db->numrows() < 1) echo 'No history entries in this category.';
-    else {
+    echo '<h3>' . $lang->get('history_heading_other') . '</h3>';
+    $q = 'SELECT time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit FROM ' . table_prefix.'logs WHERE log_type=\'page\' AND action!=\'edit\' AND page_id=\'' . $paths->cpage['urlname_nons'] . '\' AND namespace=\'' . $paths->namespace . '\' ORDER BY time_id DESC;';
+    if ( !$db->sql_query($q) )
+    {
+      $db->_die('The history data for the page "' . htmlspecialchars($paths->cpage['name']) . '" could not be selected.');
+    }
+    if ( $db->numrows() < 1 )
+    {
+      echo $lang->get('history_no_entries');
+    }
+    else
+    {
       
-      echo '<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4"><tr><th>Date/time</th><th>User</th><th>Minor</th><th>Action taken</th><th>Extra info</th><th colspan="2"></th></tr>';
+      echo '<div class="tblholder">
+              <table border="0" width="100%" cellspacing="1" cellpadding="4"><tr>
+                <th>' . $lang->get('history_col_datetime') . '</th>
+                <th>' . $lang->get('history_col_user') . '</th>
+                <th>' . $lang->get('history_col_minor') . '</th>
+                <th>' . $lang->get('history_col_action_taken') . '</th>
+                <th>' . $lang->get('history_col_extra') . '</th>
+                <th colspan="2"></th>
+              </tr>';
       $cls = 'row2';
       while($r = $db->fetchrow()) {
         
@@ -603,37 +668,32 @@
         echo '<tr>';
         
         // Date and time
-        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">';
+        echo '<td class="' . $cls . '">' . $r['date_string'] . '</td class="' . $cls . '">';
         
         // User
-        echo '<td class="'.$cls.'"><a href="'.makeUrlNS('User', $r['author']).'" ';
+        echo '<td class="' . $cls . '"><a href="'.makeUrlNS('User', $r['author']).'" ';
         if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
-        echo '>'.$r['author'].'</a></td class="'.$cls.'">';
+        echo '>' . $r['author'] . '</a></td class="' . $cls . '">';
         
         
         // Minor edit
-        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>';
+        echo '<td class="' . $cls . '" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>';
         
         // Action taken
-        echo '<td class="'.$cls.'">';
+        echo '<td class="' . $cls . '">';
         // Some of these are sanitized at insert-time. Others follow the newer Enano policy of stripping HTML at runtime.
-        if    ($r['action']=='prot')     echo 'Protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='unprot')   echo 'Unprotected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='semiprot') echo 'Semi-protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='rename')   echo 'Renamed page</td><td class="'.$cls.'">Old title: '.htmlspecialchars($r['edit_summary']);
-        elseif($r['action']=='create')   echo 'Created page</td><td class="'.$cls.'">';
-        elseif($r['action']=='delete')   echo 'Deleted page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='reupload') echo 'Uploaded new file version</td><td class="'.$cls.'">Reason: '.htmlspecialchars($r['edit_summary']);
+        if    ($r['action']=='prot')     echo $lang->get('history_log_protect') . '</td><td class="' . $cls . '">' . $lang->get('history_extra_reason') . ' ' . $r['edit_summary'];
+        elseif($r['action']=='unprot')   echo $lang->get('history_log_unprotect') . '</td><td class="' . $cls . '">' . $lang->get('history_extra_reason') . ' ' . $r['edit_summary'];
+        elseif($r['action']=='semiprot') echo $lang->get('history_log_semiprotect') . '</td><td class="' . $cls . '">' . $lang->get('history_extra_reason') . ' ' . $r['edit_summary'];
+        elseif($r['action']=='rename')   echo $lang->get('history_log_rename') . '</td><td class="' . $cls . '">' . $lang->get('history_extra_oldtitle') . ' '.htmlspecialchars($r['edit_summary']);
+        elseif($r['action']=='create')   echo $lang->get('history_log_create') . '</td><td class="' . $cls . '">';
+        elseif($r['action']=='delete')   echo $lang->get('history_log_delete') . '</td><td class="' . $cls . '">' . $lang->get('history_extra_reason') . ' ' . $r['edit_summary'];
+        elseif($r['action']=='reupload') echo $lang->get('history_log_uploadnew') . '</td><td class="' . $cls . '">' . $lang->get('history_extra_reason') . ' '.htmlspecialchars($r['edit_summary']);
         echo '</td>';
         
         // Actions!
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>';
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert action</a></td>';
-        
-        //echo '(<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">rollback</a>) <i>'.$r['date_string'].'</i> '.$r['author'].' (<a href="'.makeUrl($paths->nslist['User'].$r['author']).'">Userpage</a>, <a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">Contrib</a>): ';
-        
-        if($r['minor_edit']) echo '<b> - minor edit</b>';
-        echo '<br />';
+        echo '<td class="' . $cls . '" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/' . $r['author']) . '">' . $lang->get('history_action_contrib') . '</a></td>';
+        echo '<td class="' . $cls . '" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id=' . $r['time_id']) . '" onclick="ajaxRollback(\'' . $r['time_id'] . '\'); return false;">' . $lang->get('history_action_revert') . '</a></td>';
         
         echo '</tr>';
       }
@@ -654,71 +714,157 @@
   function rollback($id)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('history_rollback')) return('You are not authorized to perform rollbacks.');
-    if(!preg_match('#^([0-9]+)$#', (string)$id)) return('The value "id" on the query string must be an integer.');
-    $e = $db->sql_query('SELECT log_type,action,date_string,page_id,namespace,page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id.';');
-    if(!$e) $db->_die('The rollback data could not be selected.');
+    if ( !$session->get_permissions('history_rollback') )
+    {
+      return('You are not authorized to perform rollbacks.');
+    }
+    if ( !preg_match('#^([0-9]+)$#', (string)$id) )
+    {
+      return('The value "id" on the query string must be an integer.');
+    }
+    $e = $db->sql_query('SELECT log_type,action,date_string,page_id,namespace,page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id=' . $id . ';');
+    if ( !$e )
+    {
+      $db->_die('The rollback data could not be selected.');
+    }
     $rb = $db->fetchrow();
     $db->free_result();
-    switch($rb['log_type']) {
+    
+    if ( $rb['log_type'] == 'page' && $rb['action'] != 'delete' )
+    {
+      $pagekey = $paths->nslist[$rb['namespace']] . $rb['page_id'];
+      if ( !isset($paths->pages[$pagekey]) )
+      {
+        return "Page doesn't exist";
+      }
+      $pagedata =& $paths->pages[$pagekey];
+      $protected = false;
+      // Special case: is the page protected? if so, check for even_when_protected permissions
+      if($pagedata['protected'] == 2)
+      {
+        // The page is semi-protected, determine permissions
+        if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
+        {
+          $protected = false;
+        }
+        else
+        {
+          $protected = true;
+        }
+      }
+      else
+      {
+        $protected = ( $pagedata['protected'] == 1 );
+      }
+      
+      $perms = $session->fetch_page_acl($rb['page_id'], $rb['namespace']);
+      
+      if ( $protected && !$perms->get_permissions('even_when_protected') )
+      {
+        return "Because this page is protected, you need moderator rights to roll back changes.";
+      }
+    }
+    else
+    {
+      $perms =& $session;
+    }
+    
+    switch($rb['log_type'])
+    {
       case "page":
-        switch($rb['action']) {
+        switch($rb['action'])
+        {
           case "edit":
+            if ( !$perms->get_permissions('edit_page') )
+              return "You don't have permission to edit pages, so rolling back edits can't be allowed either.";
             $t = $db->escape($rb['page_text']);
-            $e = $db->sql_query('UPDATE '.table_prefix.'page_text SET page_text=\''.$t.'\',char_tag=\''.$rb['char_tag'].'\' WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the state it was in on '.$rb['date_string'].'.');
+            $e = $db->sql_query('UPDATE ' . table_prefix.'page_text SET page_text=\'' . $t . '\',char_tag=\'' . $rb['char_tag'] . '\' WHERE page_id=\'' . $rb['page_id'] . '\' AND namespace=\'' . $rb['namespace'] . '\'');
+            if ( !$e )
+            {
+              return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            }
+            else
+            {
+              return 'The page "' . $paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the state it was in on ' . $rb['date_string'] . '.';
+            }
             break;
           case "rename":
+            if ( !$perms->get_permissions('rename') )
+              return "You don't have permission to rename pages, so rolling back renames can't be allowed either.";
             $t = $db->escape($rb['edit_summary']);
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$t.'\' WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the name it had ("'.$rb['edit_summary'].'") before '.$rb['date_string'].'.');
+            $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET name=\'' . $t . '\' WHERE urlname=\'' . $rb['page_id'] . '\' AND namespace=\'' . $rb['namespace'] . '\'');
+            if ( !$e )
+            {
+              return "An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace();
+            }
+            else
+            {
+              return 'The page "' . $paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the name it had ("' . $rb['edit_summary'] . '") before ' . $rb['date_string'] . '.';
+            }
             break;
           case "prot":
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
+            if ( !$perms->get_permissions('protect') )
+              return "You don't have permission to protect pages, so rolling back protection can't be allowed either.";
+            $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET protected=0 WHERE urlname=\'' . $rb['page_id'] . '\' AND namespace=\'' . $rb['namespace'] . '\'');
+            if ( !$e )
+              return "An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace();
+            else
+              return 'The page "' . $paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at ' . $rb['date_string'] . '.';
             break;
           case "semiprot":
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
+            if ( !$perms->get_permissions('protect') )
+              return "You don't have permission to protect pages, so rolling back protection can't be allowed either.";
+            $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET protected=0 WHERE urlname=\'' . $rb['page_id'] . '\' AND namespace=\'' . $rb['namespace'] . '\'');
+            if ( !$e )
+              return "An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace();
+            else
+              return 'The page "' . $paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at ' . $rb['date_string'] . '.';
             break;
           case "unprot":
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=1 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been protected according to the log created at '.$rb['date_string'].'.');
+            if ( !$perms->get_permissions('protect') )
+              return "You don't have permission to protect pages, so rolling back protection can't be allowed either.";
+            $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET protected=1 WHERE urlname=\'' . $rb['page_id'] . '\' AND namespace=\'' . $rb['namespace'] . '\'');
+            if ( !$e )
+              return "An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace();
+            else
+              return 'The page "' . $paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been protected according to the log created at ' . $rb['date_string'] . '.';
             break;
           case "delete":
-            if(!$session->get_permissions('history_rollback_extra')) return('Administrative privileges are required for page undeletion.');
-            if(isset($paths->pages[$paths->cpage['urlname']])) return('You cannot raise a dead page that is alive.');
+            if ( !$perms->get_permissions('history_rollback_extra') )
+              return 'Administrative privileges are required for page undeletion.';
+            if ( isset($paths->pages[$paths->cpage['urlname']]) )
+              return 'You cannot raise a dead page that is alive.';
             $name = str_replace('_', ' ', $rb['page_id']);
-            $e = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace) VALUES( \''.$name.'\', \''.$rb['page_id'].'\',\''.$rb['namespace'].'\' )');if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\' AND log_type=\'page\' AND action=\'edit\' ORDER BY time_id DESC;'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            $e = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace) VALUES( \'' . $name . '\', \'' . $rb['page_id'] . '\',\'' . $rb['namespace'] . '\' )');if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            $e = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix.'logs WHERE page_id=\'' . $rb['page_id'] . '\' AND namespace=\'' . $rb['namespace'] . '\' AND log_type=\'page\' AND action=\'edit\' ORDER BY time_id DESC;'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
             $r = $db->fetchrow();
-            $e = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\''.$rb['page_id'].'\',\''.$rb['namespace'].'\',\''.$db->escape($r['page_text']).'\',\''.$r['char_tag'].'\')'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            return('The page "'.$name.'" has been undeleted according to the log created at '.$rb['date_string'].'.');
+            $e = $db->sql_query('INSERT INTO ' . table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\'' . $rb['page_id'] . '\',\'' . $rb['namespace'] . '\',\'' . $db->escape($r['page_text']) . '\',\'' . $r['char_tag'] . '\')'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
+            return 'The page "' . $name . '" has been undeleted according to the log created at ' . $rb['date_string'] . '.';
             break;
           case "reupload":
-            if(!$session->get_permissions('history_rollbacks_extra')) return('Administrative privileges are required for file rollbacks.');
+            if ( !$session->get_permissions('history_rollbacks_extra') )
+            {
+              return 'Administrative privileges are required for file rollbacks.';
+            }
             $newtime = time();
             $newdate = date('d M Y h:i a');
-            if(!$db->sql_query('UPDATE '.table_prefix.'logs SET time_id='.$newtime.',date_string=\''.$newdate.'\' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
-            if(!$db->sql_query('UPDATE '.table_prefix.'files SET time_id='.$newtime.' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
-            return('The file has been rolled back to the version uploaded on '.date('d M Y h:i a', (int)$id).'.');
+            if(!$db->sql_query('UPDATE ' . table_prefix.'logs SET time_id=' . $newtime . ',date_string=\'' . $newdate . '\' WHERE time_id=' . $id))
+              return 'Error during query: '.mysql_error();
+            if(!$db->sql_query('UPDATE ' . table_prefix.'files SET time_id=' . $newtime . ' WHERE time_id=' . $id))
+              return 'Error during query: '.mysql_error();
+            return 'The file has been rolled back to the version uploaded on '.date('d M Y h:i a', (int)$id).'.';
             break;
           default:
-            return('Rollback of the action "'.$rb['action'].'" is not yet supported.');
+            return('Rollback of the action "' . $rb['action'] . '" is not yet supported.');
             break;
         }
         break;
       case "security":
       case "login":
-        return('A '.$rb['log_type'].'-related log entry cannot be rolled back.');
+        return('A ' . $rb['log_type'] . '-related log entry cannot be rolled back.');
         break;
       default:
-        return('Unknown log entry type: "'.$rb['log_type'].'"');
+        return('Unknown log entry type: "' . $rb['log_type'] . '"');
     }
   }
   
@@ -749,9 +895,9 @@
     $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name);
     $subj = RenderMan::preprocess_text($subject);
     if(getConfig('approve_comments')=='1') $appr = '0'; else $appr = '1';
-    $q = 'INSERT INTO '.table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\''.$page_id.'\',\''.$namespace.'\',\''.$subj.'\',\''.$text.'\',\''.$name.'\','.$session->user_id.','.$appr.','.time().')';
+    $q = 'INSERT INTO ' . table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\'' . $page_id . '\',\'' . $namespace . '\',\'' . $subj . '\',\'' . $text . '\',\'' . $name . '\',' . $session->user_id . ',' . $appr . ','.time().')';
     $e = $db->sql_query($q);
-    if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.mysql_error().'\n\nQuery:\n'.$q).'\'))');
+    if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.mysql_error().'\n\nQuery:\n' . $q) . '\'))');
     else $_ob .= '<div class="info-box">Your comment has been posted.</div>';
     return PageUtils::comments($page_id, $namespace, false, Array(), $_ob);
   }
@@ -770,6 +916,7 @@
   function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '')
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     
     $pname = $paths->nslist[$namespace] . $page_id;
     
@@ -781,15 +928,15 @@
       case "delete":
         if(isset($flags['id']))
         {
-          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.intval($flags['id']).' LIMIT 1;';
+          $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND comment_id='.intval($flags['id']).' LIMIT 1;';
         } else {
           $n = $db->escape($flags['name']);
           $s = $db->escape($flags['subj']);
           $t = $db->escape($flags['text']);
-          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
+          $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\' LIMIT 1;';
         }
         $e=$db->sql_query($q);
-        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n' . $q) . '\'));');
         break;
       case "approve":
         if(isset($flags['id']))
@@ -799,20 +946,20 @@
           $n = $db->escape($flags['name']);
           $s = $db->escape($flags['subj']);
           $t = $db->escape($flags['text']);
-          $where = 'name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\'';
+          $where = 'name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\'';
         }
-        $q = 'SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.' LIMIT 1;';
+        $q = 'SELECT approved FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND ' . $where . ' LIMIT 1;';
         $e = $db->sql_query($q);
-        if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n' . $q) . '\'));');
         $r = $db->fetchrow();
         $db->free_result();
         $a = ( $r['approved'] ) ? '0' : '1';
-        $q = 'UPDATE '.table_prefix.'comments SET approved='.$a.' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.';';
+        $q = 'UPDATE ' . table_prefix.'comments SET approved=' . $a . ' WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND ' . $where . ';';
         $e=$db->sql_query($q);
-        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
-        if($a=='1') $v = 'Unapprove';
-        else $v = 'Approve';
-        echo 'document.getElementById("mdgApproveLink'.$_GET['id'].'").innerHTML="'.$v.'";';
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n' . $q) . '\'));');
+        if($a=='1') $v = $lang->get('comment_btn_mod_unapprove');
+        else $v = $lang->get('comment_btn_mod_approve');
+        echo 'document.getElementById("mdgApproveLink'.intval($_GET['id']).'").innerHTML="' . $v . '";';
         break;
       }
     }
@@ -824,42 +971,53 @@
     
     $tpl = $template->makeParser('comment.tpl');
     
-    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=0;');
+    $e = $db->sql_query('SELECT * FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND approved=0;');
     if(!$e) $db->_die('The comment text data could not be selected.');
     $num_unapp = $db->numrows();
     $db->free_result();
-    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=1;');
+    $e = $db->sql_query('SELECT * FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND approved=1;');
     if(!$e) $db->_die('The comment text data could not be selected.');
     $num_app = $db->numrows();
     $db->free_result();
     $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,u.user_level,u.signature
-                  FROM '.table_prefix.'comments AS c
-                  LEFT JOIN '.table_prefix.'users AS u
+                  FROM ' . table_prefix.'comments AS c
+                  LEFT JOIN ' . table_prefix.'users AS u
                     ON c.user_id=u.user_id
-                  WHERE page_id=\''.$page_id.'\'
-                  AND namespace=\''.$namespace.'\' ORDER BY c.time ASC;');
+                  WHERE page_id=\'' . $page_id . '\'
+                  AND namespace=\'' . $namespace . '\' ORDER BY c.time ASC;');
     if(!$lq) _die('The comment text data could not be selected. '.mysql_error());
-    $_ob .= '<h3>Article Comments</h3>';
+    $_ob .= '<h3>' . $lang->get('comment_heading') . '</h3>';
+    
     $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app;
-    if($n==1) $s = 'is '.$n.' comment'; else $s = 'are '.$n.' comments';
-    if($n < 1)
+    
+    $subst = array(
+        'num_comments' => $n,
+        'page_type' => $template->namespace_string
+      );
+    
+    $_ob .= '<p>';
+    $_ob .= ( $n == 0 ) ? $lang->get('comment_msg_count_zero', $subst) : ( $n == 1 ? $lang->get('comment_msg_count_one', $subst) : $lang->get('comment_msg_count_plural', $subst) );
+    
+    if ( $session->get_permissions('mod_comments') && $num_unapp > 0 )
     {
-      $_ob .= '<p>There are currently no comments on this '.strtolower($namespace).'';
-      if($namespace != 'Article') $_ob .= ' page';
-      $_ob .= '.</p>';
-    } else $_ob .= '<p>There '.$s.' on this article.';
-    if($session->get_permissions('mod_comments') && $num_unapp > 0) $_ob .= ' <span style="color: #D84308">'.$num_unapp.' of those are unapproved.</span>';
-    elseif(!$session->get_permissions('mod_comments') && $num_unapp > 0) { $u = ($num_unapp == 1) ? "is $num_unapp comment" : "are $num_unapp comments"; $_ob .= ' However, there ' . $u . ' awating approval.'; }
+      $_ob .= ' <span style="color: #D84308">' . $lang->get('comment_msg_count_unapp_mod', array( 'num_unapp' => $num_unapp )) . '</span>';
+    }
+    else if ( !$session->get_permissions('mod_comments') && $num_unapp > 0 )
+    {
+      $ls = ( $num_unapp == 1 ) ? 'comment_msg_count_unapp_one' : 'comment_msg_count_unapp_plural';
+      $_ob .= ' <span>' . $lang->get($ls, array( 'num_unapp' => $num_unapp )) . '</span>';
+    }
     $_ob .= '</p>';
     $list = 'list = { ';
     // _die(htmlspecialchars($ttext));
     $i = -1;
-    while($row = $db->fetchrow($lq))
+    while ( $row = $db->fetchrow($lq) )
     {
       $i++;
       $strings = Array();
       $bool = Array();
-      if($session->get_permissions('mod_comments') || $row['approved']) {
+      if ( $session->get_permissions('mod_comments') || $row['approved'] )
+      {
         $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
         
         // Comment ID (used in the Javascript apps)
@@ -867,14 +1025,14 @@
         
         // Determine the name, and whether to link to the user page or not
         $name = '';
-        if($row['user_id'] > 0) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $row['name'])).'">';
+        if($row['user_id'] > 1) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $row['name'])).'">';
         $name .= $row['name'];
-        if($row['user_id'] > 0) $name .= '</a>';
+        if($row['user_id'] > 1) $name .= '</a>';
         $strings['NAME'] = $name; unset($name);
         
         // Subject
         $s = $row['subject'];
-        if(!$row['approved']) $s .= ' <span style="color: #D84308">(Unapproved)</span>';
+        if(!$row['approved']) $s .= ' <span style="color: #D84308">' . $lang->get('comment_msg_note_unapp') . '</span>';
         $strings['SUBJECT'] = $s;
         
         // Date and time
@@ -885,16 +1043,17 @@
         {
           default:
           case USER_LEVEL_GUEST:
-            $l = 'Guest';
+            $l = $lang->get('user_type_guest');
             break;
           case USER_LEVEL_MEMBER:
-            $l = 'Member';
+          case USER_LEVEL_CHPREF:
+            $l = $lang->get('user_type_member');
             break;
           case USER_LEVEL_MOD:
-            $l = 'Moderator';
+            $l = $lang->get('user_type_mod');
             break;
           case USER_LEVEL_ADMIN:
-            $l = 'Administrator';
+            $l = $lang->get('user_type_admin');
             break;
         }
         $strings['USER_LEVEL'] = $l; unset($l);
@@ -905,10 +1064,10 @@
         if($session->get_permissions('edit_comments'))
         {
           // Edit link
-          $strings['EDIT_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=editcomment&amp;id='.$row['comment_id']).'" id="editbtn_'.$i.'">edit</a>';
+          $strings['EDIT_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=editcomment&amp;id=' . $row['comment_id']) . '" id="editbtn_' . $i . '">' . $lang->get('comment_btn_edit') . '</a>';
         
           // Delete link
-          $strings['DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=deletecomment&amp;id='.$row['comment_id']).'">delete</a>';
+          $strings['DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=deletecomment&amp;id=' . $row['comment_id']) . '">' . $lang->get('comment_btn_delete') . '</a>';
         }
         else
         {
@@ -920,19 +1079,19 @@
         }
         
         // Send PM link
-        $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/'.$row['name']).'">Send private message</a><br />' : '';
+        $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 1 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/' . $row['name']) . '">' . $lang->get('comment_btn_send_privmsg') . '</a><br />' : '';
         
         // Add Buddy link
-        $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/'.$row['name']).'">Add to buddy list</a>' : '';
+        $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 1 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/' . $row['name']) . '">' . $lang->get('comment_btn_add_buddy') . '</a>' : '';
         
         // Mod links
         $applink = '';
-        $applink .= '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=approve&amp;id='.$row['comment_id']).'" id="mdgApproveLink'.$i.'">';
-        if($row['approved']) $applink .= 'Unapprove';
-        else $applink .= 'Approve';
+        $applink .= '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=approve&amp;id=' . $row['comment_id']) . '" id="mdgApproveLink' . $i . '">';
+        if($row['approved']) $applink .= $lang->get('comment_btn_mod_unapprove');
+        else $applink .= $lang->get('comment_btn_mod_approve');
         $applink .= '</a>';
         $strings['MOD_APPROVE_LINK'] = $applink; unset($applink);
-        $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=delete&amp;id='.$row['comment_id']).'">Delete</a>';
+        $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=delete&amp;id=' . $row['comment_id']) . '">' . $lang->get('comment_btn_mod_delete') . '</a>';
         
         // Signature
         $strings['SIGNATURE'] = '';
@@ -950,38 +1109,37 @@
     }
     if(getConfig('comments_need_login') != '2' || $session->user_logged_in)
     {
-      if(!$session->get_permissions('post_comments'))
-      {
-        $_ob .= '<h3>Got something to say?</h3><p>Access to post comments on this page is denied.</p>';
-      }
-      else
+      if($session->get_permissions('post_comments'))
       {
-        $_ob .= '<h3>Got something to say?</h3>If you have comments or suggestions on this article, you can shout it out here.';
-        if(getConfig('approve_comments')=='1') $_ob .= '  Before your comment will be visible to the public, a moderator will have to approve it.';
-        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) $_ob .= ' Because you are not logged in, you will need to enter a visual confirmation before your comment will be posted.';
-        $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="'.$session->username.'" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />';
-        $_ob .= '  <a href="#" id="mdgCommentFormLink" style="display: none;" onclick="document.getElementById(\'mdgCommentForm\').style.display=\'block\';this.style.display=\'none\';return false;">Leave a comment...</a>
+        $_ob .= '<h3>' . $lang->get('comment_postform_title') . '</h3>';
+        $_ob .= $lang->get('comment_postform_blurb');
+        if(getConfig('approve_comments')=='1') $_ob .= ' ' . $lang->get('comment_postform_blurb_unapp');
+        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
+        {
+          $_ob .= ' ' . $lang->get('comment_postform_blurb_captcha');
+        }
+        $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="' . $session->username . '" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />';
+        $_ob .= '  <a href="#" id="mdgCommentFormLink" style="display: none;" onclick="document.getElementById(\'mdgCommentForm\').style.display=\'block\';this.style.display=\'none\';return false;">' . $lang->get('comment_postform_blurb_link') . '</a>
         <div id="mdgCommentForm">
-        <h3>Comment form</h3>
         <form action="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=postcomment').'" method="post" style="margin-left: 1em">
         <table border="0">
-        <tr><td>Your name or screen name:</td><td>'.$sn.'</td></tr>
-        <tr><td>Comment subject:</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr>';
+        <tr><td>' . $lang->get('comment_postform_field_name') . '</td><td>' . $sn . '</td></tr>
+        <tr><td>' . $lang->get('comment_postform_field_subject') . '</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr>';
         if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
         {
           $session->kill_captcha();
           $captcha = $session->make_captcha();
-          $_ob .= '<tr><td>Visual confirmation:<br /><small>Please enter the code you see on the right.</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/'.$captcha).'" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="'.$captcha.'" /><br />Code: <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("If you can\'t read the code, click on the image to generate a new one.");</script><noscript>If you can\'t read the code, please refresh this page to generate a new one.</noscript></small></td></tr>';
+          $_ob .= '<tr><td>' . $lang->get('comment_postform_field_captcha_title') . '<br /><small>' . $lang->get('comment_postform_field_captcha_blurb') . '</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/' . $captcha) . '" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="' . $captcha . '" /><br />' . $lang->get('comment_postform_field_captcha_label') . ' <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("' . $lang->get('comment_postform_field_captcha_cantread_js') . '");</script><noscript>' . $lang->get('comment_postform_field_captcha_cantread_nojs') . '</noscript></small></td></tr>';
         }
         $_ob .= '
-        <tr><td valign="top">Comment text:<br />(most HTML will be stripped)</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr>
-        <tr><td colspan="2" style="text-align: center;"><input type="submit" value="Submit Comment" /></td></tr>
+        <tr><td valign="top">' . $lang->get('comment_postform_field_comment') . '</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr>
+        <tr><td colspan="2" style="text-align: center;"><input type="submit" value="' . $lang->get('comment_postform_btn_submit') . '" /></td></tr>
         </table>
         </form>
         </div>';
       }
     } else {
-      $_ob .= '<h3>Got something to say?</h3><p>You need to be logged in to post comments. <a href="'.makeUrlNS('Special', 'Login/'.$pname.'%2523comments').'">Log in</a></p>';
+      $_ob .= '<h3>Got something to say?</h3><p>You need to be logged in to post comments. <a href="'.makeUrlNS('Special', 'Login/' . $pname . '%2523comments').'">Log in</a></p>';
     }
     $list .= '};';
     echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\');
@@ -1052,7 +1210,7 @@
     if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
     {
       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_data=\'' . $old_text . '\' AND subject=\'' . $old_subject . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;';
       $s = $db->sql_query($q);
       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       $r = $db->fetchrow($s);
@@ -1061,13 +1219,13 @@
     }
     $s = RenderMan::preprocess_text($subject);
     $t = RenderMan::preprocess_text($text);
-    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $sql  = 'UPDATE ' . table_prefix.'comments SET subject=\'' . $s . '\',comment_data=\'' . $t . '\' WHERE comment_data=\'' . $old_text . '\' AND subject=\'' . $old_subject . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'';
     $result = $db->sql_query($sql);
     if($result)
     {
       return 'result="GOOD";
-                      list['.$id.'][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\');
-                      list['.$id.'][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = '.$id.';
+                      list[' . $id . '][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\');
+                      list[' . $id . '][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = ' . $id . ';
       s = unescape(\''.rawurlencode($s).'\');
       t = unescape(\''.str_replace('%5Cn', '<br \\/>', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');';
     }
@@ -1075,7 +1233,7 @@
     {
       return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment.
       Performed SQL:
-      '.$sql.'
+      ' . $sql . '
     
       Error returned by MySQL: '.mysql_error()).'");';
     }
@@ -1101,7 +1259,7 @@
     if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
     {
       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;';
       $s = $db->sql_query($q);
       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       $r = $db->fetchrow($s);
@@ -1110,13 +1268,13 @@
     }
     $s = RenderMan::preprocess_text($subject);
     $t = RenderMan::preprocess_text($text);
-    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $sql  = 'UPDATE ' . table_prefix.'comments SET subject=\'' . $s . '\',comment_data=\'' . $t . '\' WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'';
     $result = $db->sql_query($sql);
     if($result)
     return 'good';
     else return 'Enano encountered a problem whilst saving the comment.
     Performed SQL:
-    '.$sql.'
+    ' . $sql . '
     
     Error returned by MySQL: '.mysql_error();
   }
@@ -1148,16 +1306,16 @@
     if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
     {
       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$t.'\' AND subject=\''.$s.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_data=\'' . $t . '\' AND subject=\'' . $s . '\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;';
       $s = $db->sql_query($q);
       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       $r = $db->fetchrow($s);
       if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
       $db->free_result();
     }
-    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
+    $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND name=\'' . $n . '\' AND subject=\'' . $s . '\' AND comment_data=\'' . $t . '\' LIMIT 1;';
     $e=$db->sql_query($q);
-    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n' . $q) . '\'));');
     return('good');
   }
   
@@ -1182,16 +1340,16 @@
     if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
     {
       if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
+      $q = 'SELECT c.name FROM ' . table_prefix.'comments c, ' . table_prefix.'users u WHERE comment_id=' . $id . ' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND u.user_id=c.user_id;';
       $s = $db->sql_query($q);
       if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
       $r = $db->fetchrow($s);
       if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
       $db->free_result();
     }
-    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.$id.' LIMIT 1;';
+    $q = 'DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\' AND comment_id=' . $id . ' LIMIT 1;';
     $e=$db->sql_query($q);
-    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n' . $q) . '\'));');
     return('good');
   }
   
@@ -1206,6 +1364,7 @@
   function rename($page_id, $namespace, $name)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     
     $pname = $paths->nslist[$namespace] . $page_id;
     
@@ -1214,28 +1373,32 @@
     
     if( empty($name)) 
     {
-      die('Name is too short');
+      return($lang->get('ajax_rename_too_short'));
     }
     if( ( $session->get_permissions('rename') && ( ( $prot && $session->get_permissions('even_when_protected') ) || !$prot ) ) && ( $paths->namespace != 'Special' && $paths->namespace != 'Admin' ))
     {
-      $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'rename\', \''.$db->escape($paths->cpage['urlname_nons']).'\', \''.$paths->namespace.'\', \''.$db->escape($session->username).'\', \''.$db->escape($paths->cpage['name']).'\')');
+      $e = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'rename\', \'' . $db->escape($paths->cpage['urlname_nons']) . '\', \'' . $paths->namespace . '\', \'' . $db->escape($session->username) . '\', \'' . $db->escape($paths->cpage['name']) . '\')');
       if ( !$e )
       {
         $db->_die('The page title could not be updated.');
       }
-      $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$db->escape($name).'\' WHERE urlname=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';');
+      $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET name=\'' . $db->escape($name) . '\' WHERE urlname=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\';');
       if ( !$e )
       {
         $db->_die('The page title could not be updated.');
       }
       else
       {
-        return('The page "'.$paths->pages[$pname]['name'].'" has been renamed to "'.$name.'". You are encouraged to leave a comment explaining your action.' . "\n\n" . 'You will see the change take effect the next time you reload this page.');
+        $subst = array(
+          'page_name_old' => $paths->pages[$pname]['name'],
+          'page_name_new' => $name
+          );
+        return $lang->get('ajax_rename_success', $subst);
       }
     }
     else
     {
-      return('Access is denied.');
+      return($lang->get('etc_access_denied'));
     }
   }
   
@@ -1249,22 +1412,26 @@
   function flushlogs($page_id, $namespace)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('clear_logs')) die('Administrative privileges are required to flush logs, you loser.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';');
+    global $lang;
+    if(!$session->get_permissions('clear_logs'))
+    {
+      return $lang->get('etc_access_denied');
+    }
+    $e = $db->sql_query('DELETE FROM ' . table_prefix.'logs WHERE page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\';');
     if(!$e) $db->_die('The log entries could not be deleted.');
     
     // If the page exists, make a backup of it in case it gets spammed/vandalized
     // If not, the admin's probably deleting a trash page
     if ( isset($paths->pages[ $paths->nslist[$namespace] . $page_id ]) )
     {
-      $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      $e = $db->sql_query('SELECT page_text,char_tag FROM ' . table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
       if(!$e) $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.');
       $row = $db->fetchrow();
       $db->free_result();
-      $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape($row['page_text']).'\', \''.$row['char_tag'].'\', \''.$session->username.'\', \''."Automatic backup created when logs were purged".'\', '.'false'.');';
+      $q='INSERT INTO ' . table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $db->escape($row['page_text']) . '\', \'' . $row['char_tag'] . '\', \'' . $session->username . '\', \''."Automatic backup created when logs were purged".'\', '.'false'.');';
       if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
     }
-    return('The logs for this page have been cleared. A backup of this page has been added to the logs table so that this page can be restored in case of vandalism or spam later.');
+    return $lang->get('ajax_clearlogs_success');
   }
   
   /**
@@ -1278,26 +1445,27 @@
   function deletepage($page_id, $namespace, $reason)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     $perms = $session->fetch_page_acl($page_id, $namespace);
     $x = trim($reason);
     if ( empty($x) )
     {
-      return 'Invalid reason for deletion passed';
+      return $lang->get('ajax_delete_need_reason');
     }
     if(!$perms->get_permissions('delete_page')) return('Administrative privileges are required to delete pages, you loser.');
-    $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \''.$page_id.'\', \''.$namespace.'\', \''.$session->username.'\', \'' . $db->escape(htmlspecialchars($reason)) . '\')');
+    $e = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $session->username . '\', \'' . $db->escape(htmlspecialchars($reason)) . '\')');
     if(!$e) $db->_die('The page log entry could not be inserted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'');
     if(!$e) $db->_die('The page categorization entries could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    $e = $db->sql_query('DELETE FROM ' . table_prefix.'comments WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'');
     if(!$e) $db->_die('The page comments could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    $e = $db->sql_query('DELETE FROM ' . table_prefix.'page_text WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'');
     if(!$e) $db->_die('The page text entry could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'pages WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
+    $e = $db->sql_query('DELETE FROM ' . table_prefix.'pages WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'');
     if(!$e) $db->_die('The page entry could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'files WHERE page_id=\''.$page_id.'\'');
+    $e = $db->sql_query('DELETE FROM ' . table_prefix.'files WHERE page_id=\'' . $page_id . '\'');
     if(!$e) $db->_die('The file entry could not be deleted.');
-    return('This page has been deleted. Note that there is still a log of edits and actions in the database, and anyone with admin rights can raise this page from the dead unless the log is cleared. If the deleted file is an image, there may still be cached thumbnails of it in the cache/ directory, which is inaccessible to users.');
+    return $lang->get('ajax_delete_success');
   }
   
   /**
@@ -1310,9 +1478,10 @@
   function delvote($page_id, $namespace)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     if ( !$session->get_permissions('vote_delete') )
     {
-      return 'Access denied';
+      return $lang->get('etc_access_denied');
     }
     
     if ( $namespace == 'Admin' || $namespace == 'Special' || $namespace == 'System' )
@@ -1351,7 +1520,7 @@
     
     if ( in_array($session->username, $ips['u']) || in_array($_SERVER['REMOTE_ADDR'], $ips['ip']) )
     {
-      return 'It appears that you have already voted to have this page deleted.';
+      return $lang->get('ajax_delvote_already_voted');
     }
     
     $ips['u'][] = $session->username;
@@ -1360,10 +1529,10 @@
     
     $cv++;
     
-    $q = 'UPDATE '.table_prefix.'pages SET delvotes='.$cv.',delvote_ips=\''.$ips.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    $q = 'UPDATE ' . table_prefix.'pages SET delvotes=' . $cv . ',delvote_ips=\'' . $ips . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'';
     $w = $db->sql_query($q);
     
-    return 'Your vote to have this page deleted has been cast.'."\nYou are encouraged to leave a comment explaining the reason for your vote.";
+    return $lang->get('ajax_delvote_success');
   }
   
   /**
@@ -1376,11 +1545,18 @@
   function resetdelvotes($page_id, $namespace)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('vote_reset')) die('You need moderator rights in order to do this, stinkin\' hacker.');
-    $q = 'UPDATE '.table_prefix.'pages SET delvotes=0,delvote_ips=\'' . $db->escape(serialize(array('ip'=>array(),'u'=>array()))) . '\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
+    global $lang;
+    if(!$session->get_permissions('vote_reset'))
+    {
+      return $lang->get('etc_access_denied');
+    }
+    $q = 'UPDATE ' . table_prefix.'pages SET delvotes=0,delvote_ips=\'' . $db->escape(serialize(array('ip'=>array(),'u'=>array()))) . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\'';
     $e = $db->sql_query($q);
     if(!$e) $db->_die('The number of delete votes was not reset.');
-    else return('The number of votes for having this page deleted has been reset to zero.');
+    else
+    {
+      return $lang->get('ajax_delvote_reset_success');
+    }
   }
   
   /**
@@ -1393,14 +1569,17 @@
   {
     $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
     
-    $dir = './themes/'.$_GET['id'].'/css/';
+    if ( !preg_match('/^([a-z0-9_-]+)$/', $_GET['id']) )
+      return $json->encode(false);
+    
+    $dir = './themes/' . $_GET['id'] . '/css/';
     $list = Array();
     // Open a known directory, and proceed to read its contents
     if (is_dir($dir)) {
       if ($dh = opendir($dir)) {
         while (($file = readdir($dh)) !== false) {
-          if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') { // _printable.css should be included with every theme
-                                                                                    // it should be a copy of the original style, but
+          if ( preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css' ) // _printable.css should be included with every theme
+          {                                                                         // it should be a copy of the original style, but
                                                                                     // mostly black and white
                                                                                     // Note to self: document this
             $list[] = substr($file, 0, strlen($file)-4);
@@ -1438,9 +1617,11 @@
   function catedit_raw($page_id, $namespace)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
+    
     ob_start();
     $_ob = '';
-    $e = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
+    $e = $db->sql_query('SELECT category_id FROM ' . table_prefix.'categories WHERE page_id=\'' . $paths->cpage['urlname_nons'] . '\' AND namespace=\'' . $paths->namespace . '\'');
     if(!$e) jsdie('Error selecting category information for current page: '.mysql_error());
     $cat_current = Array();
     while($r = $db->fetchrow())
@@ -1475,11 +1656,11 @@
     }
     
     echo 'catlist = new Array();'; // Initialize the client-side category list
-    $_ob .= '<h3>Select which categories this page should be included in.</h3>
+    $_ob .= '<h3>' . $lang->get('catedit_title') . '</h3>
              <form name="mdgCatForm" action="'.makeUrlNS($namespace, $page_id, 'do=catedit').'" method="post">';
     if ( sizeof($cat_info) < 1 )
     {
-      $_ob .= '<p>There are no categories on this site yet.</p>';
+      $_ob .= '<p>' . $lang->get('catedit_no_categories') . '</p>';
     }
     for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ )
     {
@@ -1492,15 +1673,15 @@
          $is_prot = true;
       $prot = ( $is_prot ) ? ' disabled="disabled" ' : '';
       $prottext = ( $is_prot ) ? ' <img alt="(protected)" width="16" height="16" src="'.scriptPath.'/images/lock16.png" />' : '';
-      echo 'catlist['.$i.'] = \''.$cat_info[$i]['urlname_nons'].'\';';
-      $_ob .= '<span class="catCheck"><input '.$prot.' name="'.$cat_info[$i]['urlname_nons'].'" id="mdgCat_'.$cat_info[$i]['urlname_nons'].'" type="checkbox"';
+      echo 'catlist[' . $i . '] = \'' . $cat_info[$i]['urlname_nons'] . '\';';
+      $_ob .= '<span class="catCheck"><input ' . $prot . ' name="' . $cat_info[$i]['urlname_nons'] . '" id="mdgCat_' . $cat_info[$i]['urlname_nons'] . '" type="checkbox"';
       if(isset($cat_info[$i]['member'])) $_ob .= ' checked="checked"';
-      $_ob .= '/>  <label for="mdgCat_'.$cat_info[$i]['urlname_nons'].'">'.$cat_info[$i]['name'].$prottext.'</label></span><br />';
+      $_ob .= '/>  <label for="mdgCat_' . $cat_info[$i]['urlname_nons'] . '">' . $cat_info[$i]['name'].$prottext.'</label></span><br />';
     }
     
     $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : '';
       
-    $_ob .= '<div style="border-top: 1px solid #CCC; padding-top: 5px; margin-top: 10px;"><input name="__enanoSaveButton" ' . $disabled . ' style="font-weight: bold;" type="submit" onclick="ajaxCatSave(); return false;" value="Save changes" /> <input name="__enanoCatCancel" type="submit" onclick="ajaxReset(); return false;" value="Cancel" /></div></form>';
+    $_ob .= '<div style="border-top: 1px solid #CCC; padding-top: 5px; margin-top: 10px;"><input name="__enanoSaveButton" ' . $disabled . ' style="font-weight: bold;" type="submit" onclick="ajaxCatSave(); return false;" value="' . $lang->get('etc_save_changes') . '" /> <input name="__enanoCatCancel" type="submit" onclick="ajaxReset(); return false;" value="' . $lang->get('etc_cancel') . '" /></div></form>';
     
     $cont = ob_get_contents();
     ob_end_clean();
@@ -1550,9 +1731,9 @@
       if(!$auth)
       {
         // Find out if the page is currently in the category
-        $q = $db->sql_query('SELECT * FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+        $q = $db->sql_query('SELECT * FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
         if(!$q)
-          return 'MySQL error: '.$db->get_error();
+          return 'MySQL error: ' . $db->get_error();
         if($db->numrows() > 0)
         {
           $auth = true;
@@ -1560,13 +1741,13 @@
         }
         $db->free_result();
       }
-      if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\''.$page_id.'\', \''.$namespace.'\', \''.$cat_all[$i]['urlname_nons'].'\')';
+      if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\'' . $page_id . '\', \'' . $namespace . '\', \'' . $cat_all[$i]['urlname_nons'] . '\')';
     }
     if(sizeof($rowlist) > 0)
     {
       $val = implode(',', $rowlist);
-      $q = 'INSERT INTO '.table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';';
-      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      $q = 'INSERT INTO ' . table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';';
+      $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
       if(!$e) $db->_die('The old category data could not be deleted.');
       $e = $db->sql_query($q);
       if(!$e) $db->_die('The new category data could not be inserted.');
@@ -1574,7 +1755,7 @@
     }
     else
     {
-      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
+      $e = $db->sql_query('DELETE FROM ' . table_prefix.'categories WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
       if(!$e) $db->_die('The old category data could not be deleted.');
       return('GOOD');
     }
@@ -1592,9 +1773,15 @@
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
     if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights');
-    if(!isset($level) || (isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level))) return('Invalid mode string');
-    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode='.$level.' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$q) return('Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    if ( !isset($level) || ( isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level) ) )
+    {
+      return('Invalid mode string');
+    }
+    $q = $db->sql_query('UPDATE ' . table_prefix.'pages SET wiki_mode=' . $level . ' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
+    if ( !$q )
+    {
+      return('Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    }
     return('GOOD');
   }
   
@@ -1609,21 +1796,37 @@
   function setpass($page_id, $namespace, $pass)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     // Determine permissions
     if($paths->pages[$paths->nslist[$namespace].$page_id]['password'] != '')
       $a = $session->get_permissions('password_reset');
     else
       $a = $session->get_permissions('password_set');
     if(!$a)
-      return 'Access is denied';
+      return $lang->get('etc_access_denied');
     if(!isset($pass)) return('Password was not set on URL');
     $p = $pass;
-    if(!preg_match('#([0-9a-f]){40,40}#', $p)) $p = sha1($p);
-    if($p=='da39a3ee5e6b4b0d3255bfef95601890afd80709') $p = '';
-    $e = $db->sql_query('UPDATE '.table_prefix.'pages SET password=\''.$p.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$e) die('PageUtils::setpass(): Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
-    if($p=='') return('The password for this page has been disabled.');
-    else return('The password for this page has been set.');
+    if ( !preg_match('#([0-9a-f]){40,40}#', $p) )
+    {
+      $p = sha1($p);
+    }
+    if ( $p == 'da39a3ee5e6b4b0d3255bfef95601890afd80709' )
+      // sha1('') = da39a3ee5e6b4b0d3255bfef95601890afd80709
+      $p = '';
+    $e = $db->sql_query('UPDATE ' . table_prefix.'pages SET password=\'' . $p . '\' WHERE urlname=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';');
+    if ( !$e )
+    {
+      die('PageUtils::setpass(): Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
+    }
+    // Is the new password blank?
+    if ( $p == '' )
+    {
+      return $lang->get('ajax_password_disable_success');
+    }
+    else
+    {
+      return $lang->get('ajax_password_success');
+    }
   }
   
   /**
@@ -1634,7 +1837,8 @@
    
   function genPreview($text)
   {
-    $ret = '<div class="info-box"><b>Reminder:</b> This is only a preview - your changes to this page have not yet been saved.</div><div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: 250px; overflow: auto; margin: 1em 0 1em 1em;">';
+    global $lang;
+    $ret = '<div class="info-box">' . $lang->get('editor_preview_blurb') . '</div><div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: 250px; overflow: auto; margin: 1em 0 1em 1em;">';
     $text = RenderMan::render(RenderMan::preprocess_text($text, false, false));
     ob_start();
     eval('?>' . $text);
@@ -1654,7 +1858,7 @@
    
   function scrollBox($text, $height = 250)
   {
-    return '<div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: '.(string)intval($height).'px; overflow: auto; margin: 1em 0 1em 1em;">'.$text.'</div>';
+    return '<div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: '.(string)intval($height).'px; overflow: auto; margin: 1em 0 1em 1em;">' . $text . '</div>';
   }
   
   /**
@@ -1669,14 +1873,15 @@
   function pagediff($page_id, $namespace, $id1, $id2)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     if(!$session->get_permissions('history_view'))
-      return 'Access denied';
+      return $lang->get('etc_access_denied');
     if(!preg_match('#^([0-9]+)$#', (string)$id1) ||
        !preg_match('#^([0-9]+)$#', (string)$id2  )) return 'SQL injection attempt';
     // OK we made it through security
     // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries
-    if(!$q1 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id1.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
-    if(!$q2 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id2.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
+    if(!$q1 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id=' . $id1 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: '.mysql_error();
+    if(!$q2 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM ' . table_prefix.'logs WHERE time_id=' . $id2 . ' AND log_type=\'page\' AND action=\'edit\' AND page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';')) return 'MySQL error: '.mysql_error();
     $row1 = $db->fetchrow($q1);
     $db->free_result($q1);
     $row2 = $db->fetchrow($q2);
@@ -1687,7 +1892,7 @@
     $time1 = date('F d, Y h:i a', $id1);
     $time2 = date('F d, Y h:i a', $id2);
     $_ob = "
-    <p>Comparing revisions: {$time1} &rarr; {$time2}</p>
+    <p>" . $lang->get('history_lbl_comparingrevisions') . " {$time1} &rarr; {$time2}</p>
     ";
     // Free some memory
     unset($row1, $row2, $q1, $q2);
@@ -1698,8 +1903,6 @@
   
   /**
    * Gets ACL information about the selected page for target type X and target ID Y.
-   * @param string $page_id The page ID
-   * @param string $namespace The namespace
    * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id.
    * @return array
    */
@@ -1707,19 +1910,21 @@
   function acl_editor($parms = Array())
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
+    
     if(!$session->get_permissions('edit_acl') && $session->user_level < USER_LEVEL_ADMIN)
     {
       return Array(
         'mode' => 'error',
-        'error' => 'You are not authorized to view or edit access control lists.'
+        'error' => $lang->get('acl_err_access_denied')
         );
     }
     $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false;
     $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false;
     $page_id =& $parms['page_id'];
     $namespace =& $parms['namespace'];
-    $page_where_clause      = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\''.$db->escape($page_id).'\' AND a.namespace=\''.$db->escape($namespace).'\'';
-    $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\'';
+    $page_where_clause      = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\'' . $db->escape($page_id) . '\' AND a.namespace=\'' . $db->escape($namespace) . '\'';
+    $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\'';
     //die(print_r($page_id,true));
     $template->load_theme();
     // $perms_obj = $session->fetch_page_acl($page_id, $namespace);
@@ -1729,7 +1934,7 @@
     {
       return Array(
         'mode' => 'error',
-        'error' => 'It seems that (a) the file acledit.tpl is missing from these theme, and (b) the JSON response is working.',
+        'error' => $lang->get('acl_err_missing_template'),
       );
     }
     $return['template'] = $template->extract_vars('acledit.tpl');
@@ -1741,7 +1946,7 @@
       {
         case 'listgroups':
           $return['groups'] = Array();
-          $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups ORDER BY group_name ASC;');
+          $q = $db->sql_query('SELECT group_id,group_name FROM ' . table_prefix.'groups ORDER BY group_name ASC;');
           while($row = $db->fetchrow())
           {
             $return['groups'][] = Array(
@@ -1751,7 +1956,7 @@
           }
           $db->free_result();
           $return['page_groups'] = Array();
-          $q = $db->sql_query('SELECT pg_id,pg_name FROM '.table_prefix.'page_groups ORDER BY pg_name ASC;');
+          $q = $db->sql_query('SELECT pg_id,pg_name FROM ' . table_prefix.'page_groups ORDER BY pg_name ASC;');
           if ( !$q )
             return Array(
               'mode' => 'error',
@@ -1775,22 +1980,22 @@
           switch($parms['target_type'])
           {
             case ACL_TYPE_USER:
-              $q = $db->sql_query('SELECT a.rules,u.user_id FROM '.table_prefix.'users AS u
-                  LEFT JOIN '.table_prefix.'acl AS a
+              $q = $db->sql_query('SELECT a.rules,u.user_id FROM ' . table_prefix.'users AS u
+                  LEFT JOIN ' . table_prefix.'acl AS a
                     ON a.target_id=u.user_id
                   WHERE a.target_type='.ACL_TYPE_USER.'
-                    AND u.username=\''.$db->escape($parms['target_id']).'\'
-                    '.$page_where_clause.';');
+                    AND u.username=\'' . $db->escape($parms['target_id']) . '\'
+                    ' . $page_where_clause . ';');
               if(!$q)
                 return(Array('mode'=>'error','error'=>mysql_error()));
               if($db->numrows() < 1)
               {
                 $return['type'] = 'new';
-                $q = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($parms['target_id']).'\';');
+                $q = $db->sql_query('SELECT user_id FROM ' . table_prefix.'users WHERE username=\'' . $db->escape($parms['target_id']) . '\';');
                 if(!$q)
                   return(Array('mode'=>'error','error'=>mysql_error()));
                 if($db->numrows() < 1)
-                  return Array('mode'=>'error','error'=>'The username you entered was not found.');
+                  return Array('mode'=>'error','error'=>$lang->get('acl_err_user_not_found'));
                 $row = $db->fetchrow();
                 $return['target_name'] = $return['target_id'];
                 $return['target_id'] = intval($row['user_id']);
@@ -1822,22 +2027,22 @@
               }
               break;
             case ACL_TYPE_GROUP:
-              $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM '.table_prefix.'groups AS g
-                  LEFT JOIN '.table_prefix.'acl AS a
+              $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM ' . table_prefix.'groups AS g
+                  LEFT JOIN ' . table_prefix.'acl AS a
                     ON a.target_id=g.group_id
                   WHERE a.target_type='.ACL_TYPE_GROUP.'
                     AND g.group_id=\''.intval($parms['target_id']).'\'
-                    '.$page_where_clause.';');
+                    ' . $page_where_clause . ';');
               if(!$q)
                 return(Array('mode'=>'error','error'=>mysql_error()));
               if($db->numrows() < 1)
               {
                 $return['type'] = 'new';
-                $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';');
+                $q = $db->sql_query('SELECT group_id,group_name FROM ' . table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';');
                 if(!$q)
                   return(Array('mode'=>'error','error'=>mysql_error()));
                 if($db->numrows() < 1)
-                  return Array('mode'=>'error','error'=>'The group ID you submitted is not valid.');
+                  return Array('mode'=>'error','error'=>$lang->get('acl_err_bad_group_id'));
                 $row = $db->fetchrow();
                 $return['target_name'] = $row['group_name'];
                 $return['target_id'] = intval($row['group_id']);
@@ -1879,10 +2084,10 @@
         case 'save_edit':
           if ( defined('ENANO_DEMO_MODE') )
           {
-            return Array('mode'=>'error','error'=>'Editing access control lists is disabled in the administration demo.');
+            return Array('mode'=>'error','error'=>$lang->get('acl_err_demo'));
           }
-          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
-            '.$page_where_clause_lite.';');
+          $q = $db->sql_query('DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
+            ' . $page_where_clause_lite . ';');
           if(!$q)
             return Array('mode'=>'error','error'=>mysql_error());
           $rules = $session->perm_to_string($parms['perms']);
@@ -1890,13 +2095,13 @@
           {
             return array(
                 'mode' => 'error', 
-                'error' => 'Supplied rule list has a length of zero'
+                'error' => $lang->get('acl_err_zero_list')
               );
           }
-          $q = ($page_id && $namespace) ? 'INSERT INTO '.table_prefix.'acl ( target_type, target_id, page_id, namespace, rules )
-                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($page_id).'\', \''.$db->escape($namespace).'\', \''.$db->escape($rules).'\' )' :
-                                          'INSERT INTO '.table_prefix.'acl ( target_type, target_id, rules )
-                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($rules).'\' )';
+          $q = ($page_id && $namespace) ? 'INSERT INTO ' . table_prefix.'acl ( target_type, target_id, page_id, namespace, rules )
+                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \'' . $db->escape($page_id) . '\', \'' . $db->escape($namespace) . '\', \'' . $db->escape($rules) . '\' )' :
+                                          'INSERT INTO ' . table_prefix.'acl ( target_type, target_id, rules )
+                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \'' . $db->escape($rules) . '\' )';
           if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>mysql_error());
           return Array(
               'mode' => 'success',
@@ -1910,10 +2115,10 @@
         case 'delete':
           if ( defined('ENANO_DEMO_MODE') )
           {
-            return Array('mode'=>'error','error'=>'Editing access control lists is disabled in the administration demo.');
+            return Array('mode'=>'error','error'=>$lang->get('acl_err_demo'));
           }
-          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
-            '.$page_where_clause_lite.';');
+          $q = $db->sql_query('DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
+            ' . $page_where_clause_lite . ';');
           if(!$q)
             return Array('mode'=>'error','error'=>mysql_error());
           return Array(
@@ -1957,6 +2162,7 @@
   function aclmanager($parms)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
     ob_start();
     // Convenience
     $formstart = '<form 
@@ -1977,20 +2183,21 @@
         echo '<pre>' . htmlspecialchars($response['text']) . '</pre>';
         break;
       case 'stage1':
-        echo '<h3>Manage page access</h3>
-              <p>Please select who should be affected by this access rule.</p>';
+        echo '<h3>' . $lang->get('acl_lbl_welcome_title') . '</h3>
+              <p>' . $lang->get('acl_lbl_welcome_body') . '</p>';
         echo $formstart;
-        echo '<p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_GROUP . '" checked="checked" /> A usergroup</label></p>
+        echo '<p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_GROUP . '" checked="checked" /> ' . $lang->get('acl_radio_usergroup') . '</label></p>
               <p><select name="data[target_id_grp]">';
         foreach ( $response['groups'] as $group )
         {
           echo '<option value="' . $group['id'] . '">' . $group['name'] . '</option>';
         }
+        
         // page group selector
         $groupsel = '';
         if ( count($response['page_groups']) > 0 )
         {
-          $groupsel = '<p><label><input type="radio" name="data[scope]" value="page_group" /> A group of pages</label></p>
+          $groupsel = '<p><label><input type="radio" name="data[scope]" value="page_group" /> ' . $lang->get('acl_radio_scope_pagegroup') . '</label></p>
                        <p><select name="data[pg_id]">';
           foreach ( $response['page_groups'] as $grp )
           {
@@ -2000,24 +2207,24 @@
         }
         
         echo '</select></p>
-              <p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_USER . '" /> A specific user</label></p>
+              <p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_USER . '" /> ' . $lang->get('acl_radio_user') . '</label></p>
               <p>' . $template->username_field('data[target_id_user]') . '</p>
-              <p>What should this access rule control?</p>
-              <p><label><input name="data[scope]" value="only_this" type="radio" checked="checked" /> Only this page</p>
+              <p>' . $lang->get('acl_lbl_scope') . '</p>
+              <p><label><input name="data[scope]" value="only_this" type="radio" checked="checked" /> ' . $lang->get('acl_radio_scope_thispage') . '</p>
               ' . $groupsel . '
-              <p><label><input name="data[scope]" value="entire_site" type="radio" /> The entire site</p>
+              <p><label><input name="data[scope]" value="entire_site" type="radio" /> ' . $lang->get('acl_radio_scope_wholesite') . '</p>
               <div style="margin: 0 auto 0 0; text-align: right;">
                 <input name="data[mode]" value="seltarget" type="hidden" />
                 <input type="hidden" name="data[page_id]" value="' . $paths->cpage['urlname_nons'] . '" />
                 <input type="hidden" name="data[namespace]" value="' . $paths->namespace . '" />
-                <input type="submit" value="Next &gt;" />
+                <input type="submit" value="' . htmlspecialchars($lang->get('etc_wizard_next')) . '" />
               </div>';
         echo $formend;
         break;
       case 'success':
         echo '<div class="info-box">
-                <b>Permissions updated</b><br />
-                The permissions for ' . $response['target_name'] . ' on this page have been updated successfully.<br />
+                <b>' . $lang->get('acl_lbl_save_success_title') . '</b><br />
+                ' . $lang->get('acl_lbl_save_success_body', array( 'target_name' => $response['target_name'] )) . '<br />
                 ' . $formstart . '
                 <input type="hidden" name="data[mode]" value="seltarget" />
                 <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
@@ -2026,14 +2233,14 @@
                 <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
                 <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
                 <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
-                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
+                <input type="submit" value="' . $lang->get('acl_btn_returnto_editor') . '" /> <input type="submit" name="data[act_go_stage1]" value="' . $lang->get('acl_btn_returnto_userscope') . '" />
                 ' . $formend . '
               </div>';
         break;
       case 'delete':
         echo '<div class="info-box">
-                <b>Rule deleted</b><br />
-                The selected access rule has been successfully deleted.<br />
+                <b>' . $lang->get('acl_lbl_delete_success_title') . '</b><br />
+                ' . $lang->get('acl_lbl_delete_success_body', array('target_name' => $response['target_name'])) . '<br />
                 ' . $formstart . '
                 <input type="hidden" name="data[mode]" value="seltarget" />
                 <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
@@ -2042,22 +2249,27 @@
                 <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
                 <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
                 <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
-                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
+                <input type="submit" value="' . $lang->get('acl_btn_returnto_editor') . '" /> <input type="submit" name="data[act_go_stage1]" value="' . $lang->get('acl_btn_returnto_userscope') . '" />
                 ' . $formend . '
               </div>';
         break;
       case 'seltarget':
         if ( $response['type'] == 'edit' )
         {
-          echo '<h3>Editing permissions</h3>';
+          echo '<h3>' . $lang->get('acl_lbl_editwin_title_edit') . '</h3>';
         }
         else
         {
-          echo '<h3>Create new rule</h3>';
+          echo '<h3>' . $lang->get('acl_lbl_editwin_title_create') . '</h3>';
         }
-        $type  = ( $response['target_type'] == ACL_TYPE_GROUP ) ? 'group' : 'user';
-        $scope = ( $response['page_id'] ) ? ( $response['namespace'] == '__PageGroup' ? 'this group of pages' : 'this page' ) : 'this entire site';
-        echo 'This panel allows you to edit what the '.$type.' "'.$response['target_name'].'" can do on <b>'.$scope.'</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.';
+        $type  = ( $response['target_type'] == ACL_TYPE_GROUP ) ? $lang->get('acl_target_type_group') : $lang->get('acl_target_type_user');
+        $scope = ( $response['page_id'] ) ? ( $response['namespace'] == '__PageGroup' ? $lang->get('acl_scope_type_pagegroup') : $lang->get('acl_scope_type_thispage') ) : $lang->get('acl_scope_type_wholesite');
+        $subs = array(
+            'target_type' => $type,
+            'target' => $response['target_name'],
+            'scope_type' => $scope
+          );
+        echo $lang->get('acl_lbl_editwin_body', $subs);
         echo $formstart;
         $parser = $template->makeParserText( $response['template']['acl_field_begin'] );
         echo $parser->run();
@@ -2091,7 +2303,14 @@
               break;
           }
           $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']';
-          $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type];
+          if ( preg_match('/^([a-z0-9_]+)$/', $response['acl_descs'][$acl_type]) )
+          {
+            $vars['FIELD_DESC'] = $lang->get($response['acl_descs'][$acl_type]);
+          }
+          else
+          {
+            $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type];
+          }
           $parser->assign_vars($vars);
           echo $parser->run();
         }
@@ -2104,7 +2323,7 @@
                 <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
                 <input type="hidden" name="data[target_id]" value="' . $response['target_id'] . '" />
                 <input type="hidden" name="data[target_name]" value="' . $response['target_name'] . '" />
-                ' . ( ( $response['type'] == 'edit' ) ? '<input type="submit" value="Save changes" />&nbsp;&nbsp;<input type="submit" name="data[act_delete_rule]" value="Delete rule" style="color: #AA0000;" onclick="return confirm(\'Do you really want to delete this ACL rule?\');" />' : '<input type="submit" value="Create rule" />' ) . '
+                ' . ( ( $response['type'] == 'edit' ) ? '<input type="submit" value="' . $lang->get('etc_save_changes') . '" />&nbsp;&nbsp;<input type="submit" name="data[act_delete_rule]" value="' . $lang->get('acl_btn_deleterule') . '" style="color: #AA0000;" onclick="return confirm(\'' . addslashes($lang->get('acl_msg_deleterule_confirm')) . '\');" />' : '<input type="submit" value="' . $lang->get('acl_btn_createrule') . '" />' ) . '
               </div>';
         echo $formend;
         break;