Completely localized admin tree menu and page toolbar
authorDan
Sun, 28 Oct 2007 17:46:54 -0400
changeset 211 753dabeca1ee
parent 210 2b283402e4e4
child 212 30b857a6b811
Completely localized admin tree menu and page toolbar
includes/clientside/static/ajax.js
includes/paths.php
includes/template.php
language/english/enano.json
themes/oxygen/header.tpl
--- a/includes/clientside/static/ajax.js	Sun Oct 28 16:40:24 2007 -0400
+++ b/includes/clientside/static/ajax.js	Sun Oct 28 17:46:54 2007 -0400
@@ -1148,7 +1148,7 @@
     if ( keepalive_interval )
       clearInterval(keepalive_interval);
     var span = document.getElementById('keepalivestat');
-    span.firstChild.nodeValue = 'Turn on keep-alive';
+    span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_off');
   }
   else
   {
@@ -1156,7 +1156,7 @@
     if ( !keepalive_interval )
       keepalive_interval = setInterval('ajaxPingServer();', 600000);
     var span = document.getElementById('keepalivestat');
-    span.firstChild.nodeValue = 'Turn off keep-alive';
+    span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_on');
     ajaxPingServer();
   }
 }
@@ -1168,20 +1168,20 @@
     if ( !keepalive_interval )
       keepalive_interval = setInterval('ajaxPingServer();', 600000);
     var span = document.getElementById('keepalivestat');
-    span.firstChild.nodeValue = 'Turn off keep-alive';
+    span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_on');
   }
   else
   {
     if ( keepalive_interval )
       clearInterval(keepalive_interval);
     var span = document.getElementById('keepalivestat');
-    span.firstChild.nodeValue = 'Turn on keep-alive';
+    span.firstChild.nodeValue = $lang.get('adm_btn_keepalive_off');
   }
 };
 
 function aboutKeepAlive()
 {
-  new messagebox(MB_OK|MB_ICONINFORMATION, 'About the keep-alive feature', 'Keep-alive is a new Enano feature that keeps your administrative session from timing out while you are using the administration panel. This feature can be useful if you are editing a large page or doing something in the administration interface that will take longer than 15 minutes.<br /><br />For security reasons, Enano mandates that high-privilege logins last only 15 minutes, with the time being reset each time a page is loaded (or, more specifically, each time the session API is started). The consequence of this is that if you are performing an action in the administration panel that takes more than 15 minutes, your session may be terminated. The keep-alive feature attempts to relieve this by sending a "ping" to the server every 10 minutes.<br /><br />Please note that keep-alive state is determined by a cookie. Thus, if you log out and then back in as a different administrator, keep-alive will use the same setting that was used when you were logged in as the first administrative user. In the same way, if you log into the administration panel under your account from another computer, keep-alive will be set to "off".<br /><br /><b>For more information:</b><br /><a href="http://docs.enanocms.org/Help:Appendix_B" onclick="window.open(this.href); return false;">Overview of Enano'+"'"+'s security model');
+  new messagebox(MB_OK|MB_ICONINFORMATION, $lang.get('user_keepalive_info_title'), $lang.get('user_keepalive_info_body'));
 }
 
 function ajaxShowCaptcha(code)
--- a/includes/paths.php	Sun Oct 28 16:40:24 2007 -0400
+++ b/includes/paths.php	Sun Oct 28 17:46:54 2007 -0400
@@ -77,21 +77,21 @@
     $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'Edit access control lists', Array('read', 'post_comments', 'edit_comments', 'edit_page', 'view_source', 'mod_comments', 'history_view', 'history_rollback', 'history_rollback_extra', 'protect', 'rename', 'clear_logs', 'vote_delete', 'vote_reset', 'delete_page', 'set_wiki_mode', 'password_set', 'password_reset', 'mod_misc', 'edit_cat', 'even_when_protected', 'upload_files', 'upload_new_version', 'create_page', 'php_in_pages'));
     
     // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
-    $this->addAdminNode('General', 'General Configuration', 'GeneralConfig');
-    $this->addAdminNode('General', 'File uploads', 'UploadConfig');
-    $this->addAdminNode('General', 'Allowed file types', 'UploadAllowedMimeTypes');
-    $this->addAdminNode('General', 'Manage Plugins', 'PluginManager');
-    $this->addAdminNode('General', 'Backup database', 'DBBackup');
-    $this->addAdminNode('Content', 'Manage Pages', 'PageManager');
-    $this->addAdminNode('Content', 'Edit page content', 'PageEditor');
-    $this->addAdminNode('Content', 'Manage page groups', 'PageGroups');
-    $this->addAdminNode('Appearance', 'Manage themes', 'ThemeManager');
-    $this->addAdminNode('Users', 'Manage users', 'UserManager');
-    $this->addAdminNode('Users', 'Edit groups', 'GroupManager');
-    $this->addAdminNode('Users', 'COPPA support', 'COPPA');
-    $this->addAdminNode('Users', 'Mass e-mail', 'MassEmail');
-    $this->addAdminNode('Security', 'Security log', 'SecurityLog');
-    $this->addAdminNode('Security', 'Ban control', 'BanControl');
+    $this->addAdminNode('adm_cat_general',    'adm_page_general_config', 'GeneralConfig');
+    $this->addAdminNode('adm_cat_general',    'adm_page_file_uploads',   'UploadConfig');
+    $this->addAdminNode('adm_cat_general',    'adm_page_file_types',     'UploadAllowedMimeTypes');
+    $this->addAdminNode('adm_cat_general',    'adm_page_plugins',        'PluginManager');
+    $this->addAdminNode('adm_cat_general',    'adm_page_db_backup',      'DBBackup');
+    $this->addAdminNode('adm_cat_content',    'adm_page_manager',        'PageManager');
+    $this->addAdminNode('adm_cat_content',    'adm_page_editor',         'PageEditor');
+    $this->addAdminNode('adm_cat_content',    'adm_page_pg_groups',      'PageGroups');
+    $this->addAdminNode('adm_cat_appearance', 'adm_page_themes',         'ThemeManager');
+    $this->addAdminNode('adm_cat_users',      'adm_page_users',          'UserManager');
+    $this->addAdminNode('adm_cat_users',      'adm_page_user_groups',    'GroupManager');
+    $this->addAdminNode('adm_cat_users',      'adm_page_coppa',          'COPPA');
+    $this->addAdminNode('adm_cat_users',      'adm_page_mass_email',     'MassEmail');
+    $this->addAdminNode('adm_cat_security',   'adm_page_security_log',   'SecurityLog');
+    $this->addAdminNode('adm_cat_security',   'adm_page_ban_control',    'BanControl');
     
     $code = $plugins->setHook('acl_rule_init');
     foreach ( $code as $cmd )
@@ -493,24 +493,29 @@
   // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
   function parseAdminTree() 
   {
+    global $lang;
+    
     $k = array_keys($this->admin_tree);
     $i = 0;
     $ret = '';
-    $ret .= "var TREE_ITEMS = [\n  ['Administration panel home', 'javascript:ajaxPage(\'".$this->nslist['Admin']."Home\');',\n    ";
+    $ret .= "var TREE_ITEMS = [\n  ['" . $lang->get('adm_btn_home') . "', 'javascript:ajaxPage(\'".$this->nslist['Admin']."Home\');',\n    ";
     foreach($k as $key)
     {
       $i++;
-      $ret .= "['".$key."', 'javascript:trees[0].toggle($i)', \n";
+      $name = ( preg_match('/^[a-z0-9_]+$/', $key) ) ? $lang->get($key) : $key;
+      $ret .= "['".$name."', 'javascript:trees[0].toggle($i)', \n";
       foreach($this->admin_tree[$key] as $c)
       {
         $i++;
-        $ret .= "        ['".$c['name']."', 'javascript:ajaxPage(\\'".$this->nslist['Admin'].$c['pageid']."\\');'],\n";
+        $name = ( preg_match('/^[a-z0-9_]+$/', $key) ) ? $lang->get($c['name']) : $c['name'];
+        
+        $ret .= "        ['".$name."', 'javascript:ajaxPage(\\'".$this->nslist['Admin'].$c['pageid']."\\');'],\n";
       }
       $ret .= "      ],\n";
     }
-    $ret .= "    ['Log out of admin panel', 'javascript:ajaxPage(\\'".$this->nslist['Admin']."AdminLogout\\');'],\n";
-    $ret .= "    ['<span id=\\'keepalivestat\\'>Loading keep-alive control...</span>', 'javascript:ajaxToggleKeepalive();', 
-                   ['About keep-alive', 'javascript:aboutKeepAlive();']
+    $ret .= "    ['" . $lang->get('adm_btn_logout') . "', 'javascript:ajaxPage(\\'".$this->nslist['Admin']."AdminLogout\\');'],\n";
+    $ret .= "    ['<span id=\\'keepalivestat\\'>" . $lang->get('adm_btn_keepalive_loading') . "</span>', 'javascript:ajaxToggleKeepalive();', 
+                   ['" . $lang->get('adm_btn_keepalive_about') . "', 'javascript:aboutKeepAlive();']
                  ],\n";
     // I used this while I painstakingly wrote the Runt code that auto-expands certain nodes based on the value of a bitfield stored in a cookie. *shudders*
     // $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
--- a/includes/template.php	Sun Oct 28 16:40:24 2007 -0400
+++ b/includes/template.php	Sun Oct 28 17:46:54 2007 -0400
@@ -198,37 +198,38 @@
     switch($paths->namespace) {
       case "Article":
       default:
-        $ns = 'article';
+        $ns = $lang->get('onpage_lbl_page_article');
         break;
       case "Admin":
-        $ns = 'administration page';
+        $ns = $lang->get('onpage_lbl_page_admin');
         break;
       case "System":
-        $ns = 'system message';
+        $ns = $lang->get('onpage_lbl_page_system');
         break;
       case "File":
-        $ns = 'uploaded file';
+        $ns = $lang->get('onpage_lbl_page_file');
         break;
       case "Help":
-        $ns = 'documentation page';
+        $ns = $lang->get('onpage_lbl_page_help');
         break;
       case "User":
-        $ns = 'user page';
+        $ns = $lang->get('onpage_lbl_page_user');
         break;
       case "Special":
-        $ns = 'special page';
+        $ns = $lang->get('onpage_lbl_page_special');
         break;
       case "Template":
-        $ns = 'template';
+        $ns = $lang->get('onpage_lbl_page_template');
         break;
       case "Project":
-        $ns = 'project page';
+        $ns = $lang->get('onpage_lbl_page_project');
         break;
       case "Category":
-        $ns = 'category';
+        $ns = $lang->get('onpage_lbl_page_category');
         break;
     }
     $this->namespace_string = $ns;
+    unset($ns);
     $code = $plugins->setHook('page_type_string_set');
     foreach ( $code as $cmd )
     {
@@ -285,14 +286,25 @@
       $n = ( $session->get_permissions('mod_comments') ) ? (string)$nc : (string)$na;
       if ( $session->get_permissions('mod_comments') && $nu > 0 )
       {
-        $n .= ' total/'.$nu.' unapp.';
+        $subst = array(
+            'num_comments' => $nc,
+            'num_unapp' => $nu
+          );
+        $btn_text = $lang->get('onpage_btn_discussion_unapp', $subst);
+      }
+      else
+      {
+        $subst = array(
+          'num_comments' => $nc
+        );
+        $btn_text = $lang->get('onpage_btn_discussion', $subst);
       }
       
       $button->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxComments()); return false; }" title="View the comments that other users have posted about this page (alt-c)" accesskey="c"',
           'PARENTFLAGS' => 'id="mdgToolbar_discussion"',
           'HREF' => makeUrl($paths->page, 'do=comments', true),
-          'TEXT' => 'discussion ('.$n.')',
+          'TEXT' => $btn_text,
         ));
       
       $tb .= $button->run();
@@ -304,7 +316,7 @@
         'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxEditor()); return false; }" title="Edit the contents of this page (alt-e)" accesskey="e"',
         'PARENTFLAGS' => 'id="mdgToolbar_edit"',
         'HREF' => makeUrl($paths->page, 'do=edit', true),
-        'TEXT' => 'edit this page'
+        'TEXT' => $lang->get('onpage_btn_edit')
         ));
       $tb .= $button->run();
     // View source button
@@ -315,7 +327,7 @@
         'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxViewSource()); return false; }" title="View the source code (wiki markup) that this page uses (alt-e)" accesskey="e"',
         'PARENTFLAGS' => 'id="mdgToolbar_edit"',
         'HREF' => makeUrl($paths->page, 'do=viewsource', true),
-        'TEXT' => 'view source'
+        'TEXT' => $lang->get('onpage_btn_viewsource')
         ));
       $tb .= $button->run();
     }
@@ -326,7 +338,7 @@
         'FLAGS'       => 'onclick="if ( !KILL_SWITCH ) { void(ajaxHistory()); return false; }" title="View a log of actions taken on this page (alt-h)" accesskey="h"',
         'PARENTFLAGS' => 'id="mdgToolbar_history"',
         'HREF'        => makeUrl($paths->page, 'do=history', true),
-        'TEXT'        => 'history'
+        'TEXT'        => $lang->get('onpage_btn_history')
         ));
       $tb .= $button->run();
     }
@@ -340,7 +352,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxRename()); return false; }" title="Change the display name of this page (alt-r)" accesskey="r"',
           'HREF'  => makeUrl($paths->page, 'do=rename', true),
-          'TEXT'  => 'rename',
+          'TEXT'  => $lang->get('onpage_btn_rename'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -351,7 +363,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxDelVote()); return false; }" title="Vote to have this page deleted (alt-d)" accesskey="d"',
           'HREF'  => makeUrl($paths->page, 'do=delvote', true),
-          'TEXT'  => 'vote to delete this page',
+          'TEXT'  => $lang->get('onpage_btn_votedelete'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -362,7 +374,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxResetDelVotes()); return false; }" title="Vote to have this page deleted (alt-y)" accesskey="y"',
           'HREF'  => makeUrl($paths->page, 'do=resetvotes', true),
-          'TEXT'  => 'reset deletion votes',
+          'TEXT'  => $lang->get('onpage_btn_votedelete_reset'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -373,7 +385,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'title="View a version of this page that is suitable for printing"',
           'HREF'  => makeUrl($paths->page, 'printable=yes', true),
-          'TEXT'  => 'view printable version',
+          'TEXT'  => $lang->get('onpage_btn_printable'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -383,7 +395,7 @@
     {
       
       $label = $this->makeParserText($tplvars['toolbar_label']);
-      $label->assign_vars(array('TEXT' => 'protection:'));
+      $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_protect')));
       $t0 = $label->run();
       
       $ctmp = ''; 
@@ -394,7 +406,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'accesskey="i" onclick="if ( !KILL_SWITCH ) { ajaxProtect(1); return false; }" id="protbtn_1" title="Prevents all non-administrators from editing this page. [alt-i]"'.$ctmp,
           'HREF'  => makeUrl($paths->page, 'do=protect&level=1', true),
-          'TEXT'  => 'on'
+          'TEXT'  => $lang->get('onpage_btn_protect_on')
         ));
       $t1 = $menubtn->run();
       
@@ -406,7 +418,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'accesskey="o" onclick="if ( !KILL_SWITCH ) { ajaxProtect(0); return false; }" id="protbtn_0" title="Allows everyone to edit this page. [alt-o]"'.$ctmp,
           'HREF'  => makeUrl($paths->page, 'do=protect&level=0', true),
-          'TEXT'  => 'off'
+          'TEXT'  => $lang->get('onpage_btn_protect_off')
         ));
       $t2 = $menubtn->run();
       
@@ -418,7 +430,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'accesskey="p" onclick="if ( !KILL_SWITCH ) { ajaxProtect(2); return false; }" id="protbtn_2" title="Allows only users who have been registered for 4 days to edit this page. [alt-p]"'.$ctmp,
           'HREF'  => makeUrl($paths->page, 'do=protect&level=2', true),
-          'TEXT'  => 'semi'
+          'TEXT'  => $lang->get('onpage_btn_protect_semi')
         ));
       $t3 = $menubtn->run();
       
@@ -437,7 +449,7 @@
     {
       // label at start
       $label = $this->makeParserText($tplvars['toolbar_label']);
-      $label->assign_vars(array('TEXT' => 'page wiki mode:'));
+      $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_wikimode')));
       $t0 = $label->run();
       
       // on button
@@ -449,7 +461,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => /* 'onclick="if ( !KILL_SWITCH ) { ajaxSetWikiMode(1); return false; }" id="wikibtn_1" title="Forces wiki functions to be allowed on this page."'. */ $ctmp,
           'HREF' => makeUrl($paths->page, 'do=setwikimode&level=1', true),
-          'TEXT' => 'on'
+          'TEXT' => $lang->get('onpage_btn_wikimode_on')
         ));
       $t1 = $menubtn->run();
       
@@ -462,7 +474,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => /* 'onclick="if ( !KILL_SWITCH ) { ajaxSetWikiMode(0); return false; }" id="wikibtn_0" title="Forces wiki functions to be disabled on this page."'. */ $ctmp,
           'HREF' => makeUrl($paths->page, 'do=setwikimode&level=0', true),
-          'TEXT' => 'off'
+          'TEXT' => $lang->get('onpage_btn_wikimode_off')
         ));
       $t2 = $menubtn->run();
       
@@ -475,7 +487,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => /* 'onclick="if ( !KILL_SWITCH ) { ajaxSetWikiMode(2); return false; }" id="wikibtn_2" title="Causes this page to use the global wiki mode setting (default)"'. */ $ctmp,
           'HREF' => makeUrl($paths->page, 'do=setwikimode&level=2', true),
-          'TEXT' => 'global'
+          'TEXT' => $lang->get('onpage_btn_wikimode_global')
         ));
       $t3 = $menubtn->run();
       
@@ -496,7 +508,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxClearLogs()); return false; }" title="Remove all edit and action logs for this page from the database. IRREVERSIBLE! (alt-l)" accesskey="l"',
           'HREF'  => makeUrl($paths->page, 'do=flushlogs', true),
-          'TEXT'  => 'clear page logs',
+          'TEXT'  => $lang->get('onpage_btn_clearlogs'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -504,14 +516,22 @@
     // Delete page button
     if ( $session->get_permissions('read') && $session->get_permissions('delete_page') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
     {
-      $s = 'delete this page';
+      $s = $lang->get('onpage_btn_deletepage');
       if ( $paths->cpage['delvotes'] == 1 )
       {
-        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> vote)';
+        $subst = array(
+          'num_votes' => $paths->cpage['delvotes'],
+          'plural' => ''
+          );
+        $s .= $lang->get('onpage_btn_deletepage_votes', $subst);
       }
       else if ( $paths->cpage['delvotes'] > 1 )
       {
-        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> votes)';
+        $subst = array(
+          'num_votes' => $paths->cpage['delvotes'],
+          'plural' => $lang->get('meta_plural')
+          );
+        $s .= $lang->get('onpage_btn_deletepage_votes', $subst);
       }
       
       $menubtn->assign_vars(array(
@@ -543,13 +563,13 @@
     {
       // label at start
       $label = $this->makeParserText($tplvars['toolbar_label']);
-      $label->assign_vars(array('TEXT' => 'page password:'));
+      $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_password')));
       $t0 = $label->run();
       
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxSetPassword()); return false; }" title="Require a password in order for this page to be viewed"',
           'HREF'  => '#',
-          'TEXT'  => 'set',
+          'TEXT'  => $lang->get('onpage_btn_password_set'),
         ));
       $t = $menubtn->run();
       
@@ -562,7 +582,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { return ajaxOpenACLManager(); }" title="Manage who can do what with this page (alt-m)" accesskey="m"',
           'HREF'  => makeUrl($paths->page, 'do=aclmanager', true),
-          'TEXT'  => 'manage page access',
+          'TEXT'  => $lang->get('onpage_btn_acl'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -573,7 +593,7 @@
       $menubtn->assign_vars(array(
           'FLAGS' => 'onclick="if ( !KILL_SWITCH ) { void(ajaxAdminPage()); return false; }" title="Administrative options for this page" accesskey="g"',
           'HREF'  => makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'PageManager', true),
-          'TEXT'  => 'administrative options',
+          'TEXT'  => $lang->get('onpage_btn_admin'),
         ));
       $this->toolbar_menu .= $menubtn->run();
     }
@@ -584,7 +604,7 @@
         'FLAGS'       => 'id="mdgToolbar_moreoptions" onclick="if ( !KILL_SWITCH ) { return false; }" title="Additional options for working with this page"',
         'PARENTFLAGS' => '',
         'HREF'        => makeUrl($paths->page, 'do=moreoptions', true),
-        'TEXT'        => 'more options'
+        'TEXT'        => $lang->get('onpage_btn_moreoptions')
         ));
       $tb .= $button->run();
     }
@@ -1145,7 +1165,7 @@
       // matches the MD5 of the file that the compiled file was compiled from.
       if ( isset($md5) && $md5 == md5($text) )
       {
-        return str_replace('\\"', '"', $tpl_text);
+        return $this->compile_template_text_post(str_replace('\\"', '"', $tpl_text));
       }
     }
     
@@ -1184,7 +1204,7 @@
       fclose($h);
     }
     
-    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
+    return $this->compile_template_text_post($text); //('<pre>'.htmlspecialchars($text).'</pre>');
   }
   
   
@@ -1197,7 +1217,7 @@
   function compile_template_text($text)
   {
     // this might do something else in the future, possibly cache large templates
-    return $this->compile_tpl_code($text);
+    return $this->compile_template_text_post($this->compile_tpl_code($text));
   }
   
   /**
@@ -1209,9 +1229,30 @@
   function parse($text)
   {
     $text = $this->compile_template_text($text);
+    $text = $this->compile_template_text_post($text);
     return eval($text);
   }
   
+  /**
+   * Post-processor for template code. Basically what this does is it localizes {lang:foo} blocks.
+   * @param string Mostly-processed TPL code
+   * @return string
+   */
+  
+  function compile_template_text_post($text)
+  {
+    global $lang;
+    preg_match_all('/\{lang:([a-z0-9]+_[a-z0-9_]+)\}/', $text, $matches);
+    foreach ( $matches[1] as $i => $string_id )
+    {
+      $string = $lang->get($string_id);
+      $string = str_replace('\\', '\\\\', $string);
+      $string = str_replace('\'', '\\\'', $string);
+      $text = str_replace_once($matches[0][$i], $string, $text);
+    }
+    return $text;
+  }
+  
   // Steps to turn this:
   //   [[Project:Community Portal]]
   // into this:
--- a/language/english/enano.json	Sun Oct 28 16:40:24 2007 -0400
+++ b/language/english/enano.json	Sun Oct 28 17:46:54 2007 -0400
@@ -17,7 +17,7 @@
 
 var enano_lang = {
   categories: [
-    'meta', 'user', 'page', 'comment', 'onpage', 'etc'
+    'adm', 'meta', 'user', 'page', 'comment', 'onpage', 'etc'
   ],
   strings: {
     meta: {
@@ -71,11 +71,87 @@
       logout_confirm_body: 'If you log out, you will no longer be able to access your user preferences, your private messages, or certain areas of this site until you log in again.',
       logout_confirm_title_elev: 'Are you sure you want to de-authenticate?',
       logout_confirm_body_elev: 'If you de-authenticate, you will no longer be able to use the administration panel until you re-authenticate again. You may do so at any time using the Administration button on the sidebar.',
+      
+      keepalive_info_title: 'About the keep-alive feature',
+      keepalive_info_body: 'Keep-alive is a new Enano feature that keeps your administrative session from timing out while you are using the administration panel. This feature can be useful if you are editing a large page or doing something in the administration interface that will take longer than 15 minutes.<br /><br />For security reasons, Enano mandates that high-privilege logins last only 15 minutes, with the time being reset each time a page is loaded (or, more specifically, each time the session API is started). The consequence of this is that if you are performing an action in the administration panel that takes more than 15 minutes, your session may be terminated. The keep-alive feature attempts to relieve this by sending a "ping" to the server every 10 minutes.<br /><br />Please note that keep-alive state is determined by a cookie. Thus, if you log out and then back in as a different administrator, keep-alive will use the same setting that was used when you were logged in as the first administrative user. In the same way, if you log into the administration panel under your account from another computer, keep-alive will be set to "off".<br /><br /><b>For more information:</b><br /><a href="http://docs.enanocms.org/Help:Appendix_B" onclick="window.open(this.href); return false;">Overview of Enano\'s security model</a>',
     },
-    page: {
+    onpage: {
+      lbl_pagetools: 'Page tools',
+      lbl_page_article: 'article',
+      lbl_page_admin: 'administration page',
+      lbl_page_system: 'system message',
+      lbl_page_file: 'uploaded file',
+      lbl_page_help: 'documentation page',
+      lbl_page_user: 'user page',
+      lbl_page_special: 'special page',
+      lbl_page_template: 'template',
+      lbl_page_project: 'project page',
+      lbl_page_category: 'category',
+      
+      btn_discussion: 'discussion (%num_comments%)',
+      btn_discussion_unapp: 'discussion (%num_comments% total, %num_unapp% unapp.)',
+      btn_edit: 'edit this page',
+      btn_viewsource: 'view source',
+      btn_history: 'history',
+      btn_moreoptions: 'more options',
+      
+      btn_rename: 'rename',
+      btn_printable: 'view printable version',
+      btn_votedelete: 'vote to delete this page',
+      btn_votedelete_reset: 'reset deletion votes',
+      lbl_wikimode: 'page wiki mode:',
+      btn_wikimode_on: 'on',
+      btn_wikimode_off: 'off',
+      btn_wikimode_global: 'global',
+      lbl_protect: 'protection:',
+      btn_protect_on: 'on',
+      btn_protect_off: 'off',
+      btn_protect_semi: 'semi',
+      btn_clearlogs: 'clear page logs',
+      btn_deletepage: 'delete this page',
+      btn_deletepage_votes: ' (<b>%num_votes%</b> vote%plural%)',
+      lbl_password: 'page password:',
+      btn_password_set: 'set',
+      btn_acl: 'manage page access',
+      btn_admin: 'administrative options',
     },
     comment: {
     },
+    adm: {
+      cat_general: 'General',
+      cat_content: 'Content',
+      cat_appearance: 'Appearance',
+      cat_users: 'Users',
+      cat_security: 'Security',
+      cat_plugins: 'Plugin configuration',
+      
+      page_general_config: 'General configuration',
+      page_file_uploads: 'File uploads',
+      page_file_types: 'Allowed file types',
+      page_plugins: 'Manage plugins',
+      page_db_backup: 'Backup database',
+      
+      page_manager: 'Manage pages',
+      page_editor: 'Edit page content',
+      page_pg_groups: 'Manage page groups',
+      
+      page_themes: 'Manage themes',
+      
+      page_users: 'Manage users',
+      page_user_groups: 'Edit user groups',
+      page_coppa: 'COPPA support',
+      page_mass_email: 'Mass e-mail',
+      
+      page_security_log: 'Security log',
+      page_ban_control: 'Ban control',
+      
+      btn_home: 'Administration panel home',
+      btn_logout: 'Log out of admin panel',
+      btn_keepalive_off: 'Turn on keep-alive',
+      btn_keepalive_on: 'Turn off keep-alive',
+      btn_keepalive_about: 'About keep-alive',
+      btn_keepalive_loading: 'Loading keep-alive button...'
+    },
     admhome: {
     },
     etc: {
--- a/themes/oxygen/header.tpl	Sun Oct 28 16:40:24 2007 -0400
+++ b/themes/oxygen/header.tpl	Sun Oct 28 17:46:54 2007 -0400
@@ -154,7 +154,7 @@
           <td id="mdg-bl"></td>
           <td class="menu_bg">
           <div class="menu_nojs" id="pagebar_main">
-            <div class="label">Page tools</div>
+            <div class="label">{lang:onpage_lbl_pagetools}</div>
             {TOOLBAR}
             <ul>
               {TOOLBAR_EXTRAS}