From 52a1d1bbe80422ca7a8c79dde6fd92db542b9b2d Mon Sep 17 00:00:00 2001
From: Dries Buytaert <dries@buytaert.net>
Date: Sat, 17 Feb 2001 12:59:24 +0000
Subject: [PATCH] - More updates on the translation support

---
 account.php                      | 120 +++++++++++++++++--------------
 database/database.mysql          |  11 ++-
 includes/comment.inc             |  78 ++++++++------------
 includes/common.inc              |   6 +-
 includes/function.inc            |  14 ++--
 includes/hostname.conf           |   9 +++
 includes/locale.inc              |   9 ++-
 includes/theme.inc               |  16 ++---
 modules/diary.module             |  10 +--
 modules/drupal.module            |   8 +--
 modules/drupal/drupal.module     |   8 +--
 modules/locale.module            |  89 +++++++++++++++++++++--
 modules/locale/locale.module     |  89 +++++++++++++++++++++--
 modules/watchdog.module          |   2 +-
 modules/watchdog/watchdog.module |   2 +-
 search.php                       |   2 +-
 story.php                        |  14 ++--
 submit.php                       | 120 ++++++++++++-------------------
 themes/marvin/marvin.theme       |  14 ++--
 updates/1.00-to-1.xx             |   3 +
 20 files changed, 379 insertions(+), 245 deletions(-)

diff --git a/account.php b/account.php
index 48be2b2b80d9..6a2ff7b5f5fa 100644
--- a/account.php
+++ b/account.php
@@ -10,17 +10,11 @@ function account_get_user($uname) {
 function account_email() {
   $output .= "<P>". t("Lost your password?  Fill out your username and e-mail address, and your password will be mailed to you.") ."</P>\n";
   $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
-  $output .= "<P>\n";
-  $output .= " <B>". t("Username") .":</B><BR>\n";
-  $output .= " <INPUT NAME=\"userid\"><BR>\n";
-  $output .= "</P>\n";
-  $output .= "<P>\n";
-  $output .= " <B>". t("E-mail address") .":</B><BR>\n";
-  $output .= " <INPUT NAME=\"email\"><BR>\n";
-  $output .= "</P>\n";
-  $output .= "<P>\n";
-  $output .= " <INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"E-mail new password\">\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Username") .":</B><BR>\n";
+  $output .= "<INPUT NAME=\"userid\"><P>\n";
+  $output .= "<B>". t("E-mail address") .":</B><BR>\n";
+  $output .= "<INPUT NAME=\"email\"><P>\n";
+  $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"". t("E-mail new password") ."\">\n";
   $output .= "</FORM>\n";
 
   return $output;
@@ -29,7 +23,7 @@ function account_email() {
 function account_create($user = "", $error = "") {
   global $theme;
 
-  if ($error) $output .= "<B><FONT COLOR=\"red\">Failed to create account:</FONT>$error</B>\n";
+  if ($error) $output .= "<P><FONT COLOR=\"red\">". t("Failed to create account: $error.") ."</FONT></P>\n";
   else $output .= "<P>". t("Registering allows you to comment on stories, to moderate comments and pending stories, to customize the look and feel of the site and generally helps you interact with the site more efficiently.") ."</P><P>". t("To create an account, simply fill out this form an click the 'Create account' button below.  An e-mail will then be sent to you with instructions on how to validate your account.") ."</P>\n";
 
   $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
@@ -39,7 +33,7 @@ function account_create($user = "", $error = "") {
   $output .= "<B>". t("E-mail address") .":</B><BR>\n";
   $output .= "<INPUT NAME=\"email\"><BR>\n";
   $output .= "<SMALL><I>". t("You will be sent instructions on how to validate your account via this e-mail address: make sure it is accurate.") ."</I></SMALL><P>\n";
-  $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Create account\">\n";
+  $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"". t("Create account") ."\">\n";
   $output .= "</FORM>\n";
 
   return $output;
@@ -72,31 +66,40 @@ function account_user_edit() {
   if ($user->id) {
     // Generate output/content:
     $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
+
     $output .= "<B>". t("Username") .":</B><BR>\n";
     $output .= "&nbsp; $user->userid<P>\n";
     $output .= "<I>". t("Required, unique, and can not be changed.") ."</I><P>\n";
+
     $output .= "<B>". t("Real name") .":</B><BR>\n";
     $output .= "<INPUT NAME=\"edit[name]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"$user->name\"><BR>\n";
-    $output .= "<I>". t("Optional.") ."</I><P>\n";
+    $output .= "<I>". t("Optional") .".</I><P>\n";
+
     $output .= "<B>". t("Real e-mail address") .":</B><BR>\n";
     $output .= "&nbsp; $user->real_email<P>\n";
     $output .= "<I>". t("Required, unique, can not be changed.") ." ". t("Your real e-mail address is never displayed publicly: only needed in case you lose your password.") ."</I><P>\n";
+
     $output .= "<B>". t("Fake e-mail address") .":</B><BR>\n";
     $output .= "<INPUT NAME=\"edit[fake_email]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"$user->fake_email\"><BR>\n";
-    $output .= "<I>". t("Optional.") ." ". t("Displayed publicly so you may spam proof your real e-mail address if you want.") ."</I><P>\n";
+    $output .= "<I>". t("Optional") .". ". t("Displayed publicly so you may spam proof your real e-mail address if you want.") ."</I><P>\n";
+
     $output .= "<B>". t("Homepage") .":</B><BR>\n";
     $output .= "<INPUT NAME=\"edit[url]\" MAXLENGTH=\"55\" SIZE=\"30\" VALUE=\"$user->url\"><BR>\n";
-    $output .= "<I>". t("Optional.") ." ". t("Make sure you enter fully qualified URLs only.  That is, remember to include \"http://\".") ."</I><P>\n";
+    $output .= "<I>". t("Optional") .". ". t("Make sure you enter fully qualified URLs only.  That is, remember to include \"http://\".") ."</I><P>\n";
+
     $output .= "<B>". t("Bio") .":</B> (". t("maximal 255 characters") .")<BR>\n";
     $output .= "<TEXTAREA NAME=\"edit[bio]\" COLS=\"35\" ROWS=\"5\" WRAP=\"virtual\">$user->bio</TEXTAREA><BR>\n";
-    $output .= "<I>". t("Optional.") ." ". t("This biographical information is publicly displayed on your user page.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I><P>\n";
+    $output .= "<I>". t("Optional") .". ". t("This biographical information is publicly displayed on your user page.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I><P>\n";
+
     $output .= "<B>". t("Signature") .":</B> (". t("maximal 255 characters") .")<BR>\n";
     $output .= "<TEXTAREA NAME=\"edit[signature]\" COLS=\"35\" ROWS=\"5\" WRAP=\"virtual\">$user->signature</TEXTAREA><BR>\n";
-    $output .= "<I>". t("Optional.") ." ". t("This information will be publicly displayed at the end of your comments.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I><P>\n";
+    $output .= "<I>". t("Optional") .". ". t("This information will be publicly displayed at the end of your comments.") ."<BR>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I><P>\n";
+
     $output .= "<B>". t("Password") .":</B><BR>\n";
     $output .= "<INPUT TYPE=\"password\" NAME=\"edit[pass1]\" SIZE=\"10\" MAXLENGTH=\"20\"> <INPUT TYPE=\"password\" NAME=\"edit[pass2]\" SIZE=\"10\" MAXLENGTH=\"20\"><BR>\n";
     $output .= "<I>". t("Enter your new password twice if you want to change your current password or leave it blank if you are happy with your current password.") ."</I><P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save user information\"><BR>\n";
+
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Save user information") ."\"><BR>\n";
     $output .= "</FORM>\n";
 
     // Display output/content:
@@ -129,34 +132,46 @@ function account_user_save($edit) {
 }
 
 function account_site_edit() {
-  global $cmodes, $corder, $theme, $themes, $user;
+  global $cmodes, $corder, $theme, $themes, $languages, $user;
 
   if ($user->id) {
     $output .= "<FORM ACTION=\"account.php\" METHOD=\"post\">\n";
+
     $output .= "<B>". t("Theme" ) .":</B><BR>\n";
     foreach ($themes as $key=>$value) $options1 .= " <OPTION VALUE=\"$key\"". (($user->theme == $key) ? " SELECTED" : "") .">$key - $value[1]</OPTION>\n";
     $output .= "<SELECT NAME=\"edit[theme]\">\n$options1</SELECT><BR>\n";
     $output .= "<I>". t("Selecting a different theme will change the look and feel of the site.") ."</I><P>\n";
+
     $output .= "<B>". t("Timezone") .":</B><BR>\n";
     $date = time() - date("Z");
     for ($zone = -43200; $zone <= 46800; $zone += 3600) $options2 .= " <OPTION VALUE=\"$zone\"". (($user->timezone == $zone) ? " SELECTED" : "") .">". date("l, F dS, Y - h:i A", $date + $zone) ." (GMT ". $zone / 3600 .")</OPTION>\n";
     $output .= "<SELECT NAME=\"edit[timezone]\">\n$options2</SELECT><BR>\n";
     $output .= "<I>". t("Select what time you currently have and your timezone settings will be set appropriate.") ."</I><P>\n";
+
+    $output .= "<B>". t("Language" ) .":</B><BR>\n";
+    foreach ($languages as $key=>$value) $options3 .= " <OPTION VALUE=\"$key\"". (($user->language == $key) ? " SELECTED" : "") .">$value - $key</OPTION>\n";
+    $output .= "<SELECT NAME=\"edit[language]\">\n$options3</SELECT><BR>\n";
+    $output .= "<I>". t("Selecting a different language will change the language the site.") ."</I><P>\n";
+
     $output .= "<B>". t("Maximum number of stories to display") .":</B><BR>\n";
-    for ($stories = 10; $stories <= 30; $stories += 5) $options3 .= "<OPTION VALUE=\"$stories\"". (($user->stories == $stories) ? " SELECTED" : "") .">$stories</OPTION>\n";
-    $output .= "<SELECT NAME=\"edit[stories]\">\n$options3</SELECT><BR>\n";
+    for ($stories = 10; $stories <= 30; $stories += 5) $options4 .= "<OPTION VALUE=\"$stories\"". (($user->stories == $stories) ? " SELECTED" : "") .">$stories</OPTION>\n";
+    $output .= "<SELECT NAME=\"edit[stories]\">\n$options4</SELECT><BR>\n";
     $output .= "<I>". t("The maximum number of stories that will be displayed on the main page.") ."</I><P>\n";
-    foreach ($cmodes as $key=>$value) $options4 .= "<OPTION VALUE=\"$key\"". ($user->mode == $key ? " SELECTED" : "") .">$value</OPTION>\n";
+    foreach ($cmodes as $key=>$value) $options5 .= "<OPTION VALUE=\"$key\"". ($user->mode == $key ? " SELECTED" : "") .">$value</OPTION>\n";
+
     $output .= "<B>". t("Comment display mode") .":</B><BR>\n";
-    $output .= "<SELECT NAME=\"edit[mode]\">$options4</SELECT><P>\n";
-    foreach ($corder as $key=>$value) $options5 .= "<OPTION VALUE=\"$key\"". ($user->sort == $key ? " SELECTED" : "") .">$value</OPTION>\n";
+    $output .= "<SELECT NAME=\"edit[mode]\">$options5</SELECT><P>\n";
+    foreach ($corder as $key=>$value) $options6 .= "<OPTION VALUE=\"$key\"". ($user->sort == $key ? " SELECTED" : "") .">$value</OPTION>\n";
+
     $output .= "<B>". t("Comment sort order") .":</B><BR>\n";
-    $output .= "<SELECT NAME=\"edit[sort]\">$options5</SELECT><P>\n";
-    for ($i = -1; $i < 6; $i++) $options6 .= " <OPTION VALUE=\"$i\"". ($user->threshold == $i ? " SELECTED" : "") .">Filter - $i</OPTION>";
+    $output .= "<SELECT NAME=\"edit[sort]\">$options6</SELECT><P>\n";
+    for ($i = -1; $i < 6; $i++) $options7 .= " <OPTION VALUE=\"$i\"". ($user->threshold == $i ? " SELECTED" : "") .">Filter - $i</OPTION>";
+
     $output .= "<B>". t("Comment filter") .":</B><BR>\n";
-    $output .= "<SELECT NAME=\"edit[threshold]\">$options6</SELECT><BR>\n";
+    $output .= "<SELECT NAME=\"edit[threshold]\">$options7</SELECT><BR>\n";
     $output .= "<I>". t("Comments that scored less than this threshold setting will be ignored.  Anonymous comments start at 0, comments of people logged on start at 1 and moderators can add and subtract points.") ."</I><P>\n";
-    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save site settings\"><BR>\n";
+
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Save site settings") ."\"><BR>\n";
     $output .= "</FORM>\n";
 
     $theme->header();
@@ -177,6 +192,7 @@ function account_site_save($edit) {
   if ($user->id) {
     $data[theme] = $edit[theme];
     $data[timezone] = $edit[timezone];
+    $data[language] = $edit[language];
     $data[stories] = $edit[stories];
     $data[mode] = $edit[mode];
     $data[sort] = $edit[sort];
@@ -197,7 +213,7 @@ function account_content_edit() {
       $output .= "<INPUT TYPE=\"checkbox\" NAME=\"edit[$block->name]\"". ($entry->user ? " CHECKED" : "") ."> ". t($block->name) ."<BR>\n";
     }
     $output .= "<P><I>". t("Enable the blocks you would like to see displayed in the side bars.") ."</I></P>\n";
-    $output .= "<P><INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save content settings\"></P>\n";
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Save content settings") ."\">\n";
     $output .= "</FORM>\n";
 
     $theme->header();
@@ -243,7 +259,7 @@ function module($name, $module, $username) {
 
     // Display account information:
     $theme->header();
-    $theme->box("Personal information", $output);
+    $theme->box(t("Personal information"), $output);
     $theme->footer();
   }
   elseif ($uname && $account = account_get_user($uname)) {
@@ -285,17 +301,17 @@ function account_validate($user) {
   global $type2index;
 
   // Verify username and e-mail address:
-  if (empty($user[real_email]) || (!eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $user[real_email]))) $error .= "<LI>". t("the specified e-mail address is not valid") .".</LI>\n";
-  if (empty($user[userid]) || (ereg("[^a-zA-Z0-9_-]", $user[userid]))) $error .= "<LI>". t("the specified username is not valid") .".</LI>\n";
-  if (strlen($user[userid]) > 15) $error .= "<LI>". t("the specified username is too long: it must be less than 15 characters") .".</LI>\n";
+  if (empty($user[real_email]) || (!eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $user[real_email]))) $error = t("the specified e-mail address is not valid");
+  if (empty($user[userid]) || (ereg("[^a-zA-Z0-9_-]", $user[userid]))) $error = t("the specified username is not valid");
+  if (strlen($user[userid]) > 15) $error = t("the specified username is too long: it must be less than 15 characters");
 
   // Check to see whether the username or e-mail address are banned:
-  if ($ban = ban_match($user[userid], $type2index[usernames])) $error .= "<LI>". t("the specified username is banned  for the following reason") .": <I>$ban->reason</I>.</LI>\n";
-  if ($ban = ban_match($user[real_email], $type2index[addresses])) $error .= "<LI>". t("the specified e-mail address is banned for the following reason") .": <I>$ban->reason</I>.</LI>\n";
+  if ($ban = ban_match($user[userid], $type2index[usernames])) $error = t("the specified username is banned") .": <I>$ban->reason</I>";
+  if ($ban = ban_match($user[real_email], $type2index[addresses])) $error = t("the specified e-mail address is banned") .": <I>$ban->reason</I>.";
 
   // Verify whether username and e-mail address are unique:
-  if (db_num_rows(db_query("SELECT userid FROM users WHERE LOWER(userid) = LOWER('$user[userid]')")) > 0) $error .= "<LI>". t("the specified username is already taken") .".</LI>\n";
-  if (db_num_rows(db_query("SELECT real_email FROM users WHERE LOWER(real_email)=LOWER('$user[real_email]')")) > 0) $error .= "<LI>". t("the specified e-mail address is already registered") .".</LI>\n";
+  if (db_num_rows(db_query("SELECT userid FROM users WHERE LOWER(userid) = LOWER('$user[userid]')")) > 0) $error = t("the specified username is already taken");
+  if (db_num_rows(db_query("SELECT real_email FROM users WHERE LOWER(real_email)=LOWER('$user[real_email]')")) > 0) $error = t("the specified e-mail address is already used for another account");
 
   return $error;
 }
@@ -463,7 +479,7 @@ function account_track_site() {
   }
 
   $theme->header();
-  $theme->box(t("Track $site_name"), $output);
+  $theme->box(strtr(t("Track %a"), array("%a" => $site_name)), ($output ? $output : t("No comments or stories posted recently.")));
   $theme->footer();
 }
 
@@ -474,31 +490,31 @@ function account_track_site() {
 }
 
 switch ($op) {
-  case "Login":
-    account_session_start($userid, $passwd);
-    header("Location: account.php?op=info");
-    break;
-  case "E-mail new password":
+  case t("E-mail new password"):
     account_email_submit($userid, $email);
     break;
-  case "Create account":
+  case t("Create account"):
     account_create_submit($userid, $email);
     break;
-  case "confirm":
-    account_create_confirm($name, $hash);
-    break;
-  case "Save user information":
+  case t("Save user information"):
     account_user_save($edit);
     account_user($user->userid);
     break;
-  case "Save site settings":
+  case t("Save site settings"):
     account_site_save($edit);
     header("Location: account.php?op=info");
     break;
-  case "Save content settings":
+  case t("Save content settings"):
     account_content_save($edit);
     account_user($user->userid);
     break;
+  case "confirm":
+    account_create_confirm($name, $hash);
+    break;
+  case "login":
+    account_session_start($userid, $passwd);
+    header("Location: account.php?op=info");
+    break;
   case "logout":
     account_session_close();
     header("Location: account.php?op=info");
@@ -540,4 +556,4 @@ function account_track_site() {
     account_user($user->userid);
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/database/database.mysql b/database/database.mysql
index 009895c51272..07cd2813e669 100644
--- a/database/database.mysql
+++ b/database/database.mysql
@@ -110,8 +110,16 @@ CREATE TABLE layout (
 
 CREATE TABLE locales (
   id int(11) DEFAULT '0' NOT NULL auto_increment,
-  english TEXT DEFAULT '' NOT NULL,
   location varchar(128) DEFAULT '' NOT NULL,
+  string TEXT DEFAULT '' NOT NULL,
+  da TEXT DEFAULT '' NOT NULL,
+  fi TEXT DEFAULT '' NOT NULL,
+  fr TEXT DEFAULT '' NOT NULL,
+  en TEXT DEFAULT '' NOT NULL,
+  es TEXT DEFAULT '' NOT NULL,
+  nl TEXT DEFAULT '' NOT NULL,
+  no TEXT DEFAULT '' NOT NULL,
+  sw TEXT DEFAULT '' NOT NULL,
   PRIMARY KEY (id)
 );
 
@@ -168,6 +176,7 @@ CREATE TABLE users (
   hash varchar(12) DEFAULT '' NOT NULL,
   rating decimal(8,4) DEFAULT '0' NOT NULL,
   timezone varchar(8) DEFAULT '0' NOT NULL,
+  language varchar(2) DEFAULT '0' NOT NULL,
   PRIMARY KEY (id)
 );
 
diff --git a/includes/comment.inc b/includes/comment.inc
index dcd4557eb329..c64a3e4ddf2c 100644
--- a/includes/comment.inc
+++ b/includes/comment.inc
@@ -56,7 +56,6 @@ function comment_settings($mode, $order, $threshold) {
 function comment_reply($pid, $id) {
   global $allowed_html, $link, $REQUEST_URI, $theme, $user;
 
-  // Extract parent-information/data:
   if ($pid) {
     $item = db_fetch_object(db_query("SELECT comments.*, users.userid FROM comments LEFT JOIN users ON comments.author = users.id WHERE comments.cid = $pid"));
     $theme->comment(new Comment($item->userid, $item->subject, $item->comment, $item->timestamp, $item->url, $item->fake_email, comment_score($comment), $comment->votes, $item->cid, $item->lid), "reply to this comment");
@@ -73,31 +72,23 @@ function comment_reply($pid, $id) {
   $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
 
   // Name field:
-  $output .= "<P>\n";
-  $output .= " <B>Your name:</B><BR>\n";
-  $output .= format_username($user->userid);
-  $output .= "</P>\n";
+  $output .= "<B>". t("Your name") .":</B><BR>\n";
+  $output .= format_username($user->userid) ."<P>\n";
 
   // Subject field:
-  $output .= "<P>\n";
-  $output .= " <B>Subject:</B><BR>\n";
-  $output .= " <INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\">\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Subject") .":</B><BR>\n";
+  $output .= "<INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\"><P>\n";
 
   // Comment field:
-  $output .= "<P>\n";
-  $output .= " <B>Comment:</B><BR>\n";
-  $output .= " <TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"comment\">". check_textarea($user->signature) ."</TEXTAREA><BR>\n";
-  $output .= " <SMALL><I>Allowed HTML tags: ". htmlspecialchars($allowed_html) .".</I></SMALL>\n";
-  $output .= "</P>\n";
+  $output .= "<B>".t("Comment") .":</B><BR>\n";
+  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"comment\">". check_textarea($user->signature) ."</TEXTAREA><BR>\n";
+  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
 
   // Preview button:
-  $output .= "<P>\n";
-  $output .= " <SMALL><I>You must preview at least once before you can submit:</I></SMALL><BR>\n";
-  $output .= " <INPUT TYPE=\"hidden\" NAME=\"pid\" VALUE=\"$pid\">\n";
-  $output .= " <INPUT TYPE=\"hidden\" NAME=\"id\" VALUE=\"$id\">\n";
-  $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Preview comment\"><BR>\n";
-  $output .= "</P>\n";
+  $output .= "<SMALL><I>". t("You must preview at least once before you can submit") .":</I></SMALL><BR>\n";
+  $output .= "<INPUT TYPE=\"hidden\" NAME=\"pid\" VALUE=\"$pid\">\n";
+  $output .= "<INPUT TYPE=\"hidden\" NAME=\"id\" VALUE=\"$id\">\n";
+  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview comment") ."\"><BR>\n";
 
   $output .= "</FORM>\n";
 
@@ -114,42 +105,32 @@ function comment_preview($pid, $id, $subject, $comment) {
   $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
 
   // Name field:
-  $output .= "<P>\n";
-  $output .= " <B>Your name:</B><BR>\n";
-  $output .= format_username($user->userid);
-  $output .= "</P>\n";
+  $output .= "<B>". t("Your name") .":</B><BR>\n";
+  $output .= format_username($user->userid) ."<P>\n";
 
   // Subject field:
-  $output .= "<P>\n";
-  $output .= " <B>Subject:</B><BR>\n";
-  $output .= " <INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\" VALUE=\"". check_textfield($subject) ."\">\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Subject") .":</B><BR>\n";
+  $output .= "<INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\" VALUE=\"". check_textfield($subject) ."\"><P>\n";
 
   // Comment field:
-  $output .= "<P>\n";
-  $output .= " <B>Comment:</B><BR>\n";
-  $output .= " <TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"comment\">". check_textarea($comment) ."</TEXTAREA><BR>\n";
-  $output .= " <SMALL><I>Allowed HTML tags: ". htmlspecialchars($allowed_html) .".</I></SMALL>\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Comment") .":</B><BR>\n";
+  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"comment\">". check_textarea($comment) ."</TEXTAREA><BR>\n";
+  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
 
   // Hidden fields:
   $output .= "<INPUT TYPE=\"hidden\" NAME=\"pid\" VALUE=\"$pid\">\n";
   $output .= "<INPUT TYPE=\"hidden\" NAME=\"id\" VALUE=\"$id\">\n";
 
   if (empty($subject)) {
-    $output .= "<P>\n";
-    $output .= " <FONT COLOR=\"red\"><B>Warning:</B></FONT> you did not supply a <U>subject</U>.\n";
-    $outout .= "</P>\n";
+    $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a subject.") ."</FONT><P>\n";
   }
 
   // Preview and submit button:
-  $output .= "<P>\n";
-  $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Preview comment\">\n";
-  $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Post comment\">\n";
-  $output .= " </FORM>\n";
-  $output .= "</P>\n";
+  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview comment") ."\">\n";
+  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Post comment") ."\">\n";
+  $output .= "</FORM>\n";
 
-  $theme->box("Reply", $output);
+  $theme->box(t("Reply"), $output);
 }
 
 function comment_post($pid, $id, $subject, $comment) {
@@ -205,7 +186,7 @@ function comment_moderation($comment) {
     $output .= "</SELECT>\n";
   }
   else {
-    $output .= "<TABLE BORDER=\"0\" CELLSPACING=\"1\" CELLPADDING=\"1\"><TR><TD>score:</TD><TD>". check_output($comment->score) ."</TD></TR><TR><TD>votes:</TD><TD>". check_output($comment->votes) ."</TR></TABLE>\n";
+    $output .= "<TABLE BORDER=\"0\" CELLSPACING=\"1\" CELLPADDING=\"1\"><TR><TD>". t("score") .":</TD><TD>". check_output($comment->score) ."</TD></TR><TR><TD>". t("votes") .":</TD><TD>". check_output($comment->votes) ."</TR></TABLE>\n";
   }
 
   return $output;
@@ -218,8 +199,8 @@ function comment_controls($threshold = 1, $mode = 3, $order = 1) {
   $output .= comment_mode(($user->id ? $user->mode : $mode));
   $output .= comment_order(($user->id ? $user->sort : $order));
   $output .= comment_threshold(($user->id ? $user->threshold : $threshold));
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Update settings\">\n";
-  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Add comment\">\n";
+  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Update settings") ."\">\n";
+  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Add comment") ."\">\n";
   $output .= "</FORM>\n";
   $output .= "</FONT>\n";
   return $output;
@@ -228,7 +209,7 @@ function comment_controls($threshold = 1, $mode = 3, $order = 1) {
 function comment_threshold($threshold) {
   $output .= "<SELECT NAME=\"threshold\">\n";
   for ($i = -1; $i < 6; $i++) {
-    $output .= " <OPTION VALUE=\"$i\"". ($threshold == $i ? " SELECTED" : "") .">Filter - $i</OPTION>";
+    $output .= " <OPTION VALUE=\"$i\"". ($threshold == $i ? " SELECTED" : "") .">". t("Filter") ." - $i</OPTION>";
   }
   $output .= "</SELECT>\n";
   return $output;
@@ -313,9 +294,8 @@ function comment_thread_max($cid, $mode, $threshold, $level = 0, $dummy = 0) {
       $theme->comment($comment, comment_link($comment, 0));
     }
     else {
-      print "<P>";
       comment_comment($comment);
-      print "</P>";
+      print "<P>";
     }
     comment_thread_max($comment->cid, $mode, $threshold, $level + 1, $dummy + 1);
   }
@@ -385,7 +365,7 @@ function comment_render($lid, $cid) {
   if ($user->id) {
     // Print moderation form:
     print " <INPUT TYPE=\"hidden\" NAME=\"id\" VALUE=\"$lid\">\n";
-    print " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Moderate comments\">\n";
+    print " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Moderate comments") ."\">\n";
     print "</FORM>\n";
   }
 }
diff --git a/includes/common.inc b/includes/common.inc
index 3cda625af18c..7ee1034c6877 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -15,14 +15,14 @@ function conf_load() {
 include_once "includes/database.inc";
 include_once "includes/watchdog.inc";
 include_once "includes/function.inc";
-include_once "includes/search.inc";
-include_once "includes/locale.inc";
 include_once "includes/module.inc";
+include_once "includes/locale.inc";
+include_once "includes/search.inc";
 include_once "includes/theme.inc";
 include_once "includes/user.inc";
 
 user_load();
-
+$locale = locale_load();
 $theme = theme_load();
 
 ?>
\ No newline at end of file
diff --git a/includes/function.inc b/includes/function.inc
index 1305d4b96c4c..04402f5a7783 100644
--- a/includes/function.inc
+++ b/includes/function.inc
@@ -3,8 +3,7 @@
 $na = "<I>na</I>";
 
 function check_textfield($message) {
-  global $allowed_html;
-  return strip_tags(str_replace("\"", "&quot;", stripslashes($message)), $allowed_html);
+  return strip_tags(str_replace("\"", "&quot;", stripslashes($message)));
 }
 
 function check_textarea($message) {
@@ -60,19 +59,16 @@ function format_date($timestamp, $type = "medium") {
 
   switch ($type) {
     case "small":
-      $date = date("D, m/d/y - H:i", $timestamp);
+      $date = date("m/d/y - H:i", $timestamp);
       break;
     case "medium":
-      $date = date("l, m/d/Y - H:i", $timestamp);
+      $date = t(date("l", $timestamp)) .", ". date("m/d/Y - H:i", $timestamp);
       break;
     case "large":
-      $date = date("D, M d, Y - H:i", $timestamp);
-      break;
-    case "extra large":
-      $date = date("l, F dS, Y - H:i", $timestamp);
+      $date = t(date("l", $timestamp)) .", ". t(date("F", $timestamp)) ." ". date("d, Y - H:i", $timestamp);
       break;
     default:
-      $date = date("D, M d, Y - H:i", $timestamp);
+      $date = t(date("l", $timestamp)) .", ". date("m/d/Y - H:i", $timestamp);
   }
   return $date;
 }
diff --git a/includes/hostname.conf b/includes/hostname.conf
index e9b597b2e95e..78882cc7d228 100644
--- a/includes/hostname.conf
+++ b/includes/hostname.conf
@@ -54,6 +54,15 @@ $themes = array("UnConeD" => array(
                   "themes/marvin/marvin.theme",
                   "classic theme, white, basic design with a fresh look"));
 
+#
+# Languages / translation / internationalization:
+#   the first language listed in this associative array will
+#   automatically become the default language.  You can add
+#   a lanaguage but make sure your SQL table, called locales
+#   is updated appropriatly.
+#
+$languages = array("en" => "English");
+
 #
 # Submission moderation votes:
 #   the keys of this associative array are displayed in each
diff --git a/includes/locale.inc b/includes/locale.inc
index 3e35bfd7018e..85b03eccb749 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -1,9 +1,12 @@
 <?
 
+function locale_load() {
+  global $languages, $user;
+  return ($user->language) ? $user->language : key($languages);
+}
+
 function t($string) {
-  $result = db_query("SELECT id FROM locales WHERE english = '". addslashes($string) ."'");
-  if (!db_fetch_object($result)) db_query("INSERT INTO locales (english, location) VALUES ('". addslashes($string) ."', '". check_input(getenv("REQUEST_URI")) ."')");
-  return $string;
+  return locale($string);
 }
 
 ?>
\ No newline at end of file
diff --git a/includes/theme.inc b/includes/theme.inc
index 57b2f7d29ad9..5791ed04903b 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -32,7 +32,7 @@ function menu($name, $module) {
     // Display account settings:
     $content .= "<LI><A HREF=\"account.php?op=track&topic=comments\">". t("track your comments") ."</A></LI>\n";
     $content .= "<LI><A HREF=\"account.php?op=track&topic=stories\">". t("track your stories") ."</A></LI>\n";
-    $content .= "<LI><A HREF=\"account.php?op=track&topic=site\">". t("track") ." $site_name</A></LI>\n";
+    $content .= "<LI><A HREF=\"account.php?op=track&topic=site\">". strtr(t("track %a"), array("%a" => $site_name)) ."</A></LI>\n";
     $content .= "<P>\n";
     $content .= "<LI><A HREF=\"account.php?op=edit&topic=user\">". t("edit your information") ."</A></LI>\n";
     $content .= "<LI><A HREF=\"account.php?op=edit&topic=site\">". t("edit your preferences") ."</A></LI>\n";
@@ -54,15 +54,15 @@ function menu($name, $module) {
 
     $content .= "<LI><A HREF=\"account.php?op=logout\">". t("logout") ."</A></LI>\n";
 
-    $theme->box(strtr(t("%s's configuration"), array("%s" => $user->userid)), "$content");
+    $theme->box(strtr(t("%a's configuration"), array("%a" => $user->userid)), "$content");
   }
   else {
     $output .= "<CENTER>\n";
-    $output .= " <FORM ACTION=\"account.php?op=Login\" METHOD=\"post\">\n";
-    $output .= "  <P><B>". t("Username") .":</B><BR><INPUT NAME=\"userid\" SIZE=\"15\"></P>\n";
-    $output .= "  <P><B>". t("Password") .":</B><BR><INPUT NAME=\"passwd\" SIZE=\"15\" TYPE=\"password\"></P>\n";
-    $output .= "  <P><INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Login\"></P>\n";
-    $output .= "  <P><A HREF=\"account.php\">". t("REGISTER") ."</A></P>\n";
+    $output .= " <FORM ACTION=\"account.php?op=login\" METHOD=\"post\">\n";
+    $output .= "  <B>". t("Username") .":</B><BR><INPUT NAME=\"userid\" SIZE=\"15\"><P>\n";
+    $output .= "  <B>". t("Password") .":</B><BR><INPUT NAME=\"passwd\" SIZE=\"15\" TYPE=\"password\"><BR>\n";
+    $output .= "  <INPUT TYPE=\"submit\" VALUE=\"". t("Login") ."\"><BR>\n";
+    $output .= "  <A HREF=\"account.php\">". t("REGISTER") ."</A>\n";
     $output .= " </FORM>\n";
     $output .= "</CENTER>\n";
 
@@ -92,7 +92,7 @@ function theme_blocks($region, $theme) {
 }
 
 function theme_morelink($theme, $story) {
-  return ($story->article) ? "[ <A HREF=\"story.php?id=$story->id\"><FONT COLOR=\"$theme->link\"><B>read more</B></FONT></A> | ". strlen($story->article) ." bytes | <A HREF=\"story.php?id=$story->id\"><FONT COLOR=\"$theme->link\">". format_plural($story->comments, "comment", "comments") ."</FONT></A> ]" : "[ <A HREF=\"story.php?id=$story->id\"><FONT COLOR=\"$theme->link\">". format_plural($story->comments, "comment", "comments") ."</FONT></A> ]";
+  return ($story->article) ? "[ <A HREF=\"story.php?id=$story->id\"><FONT COLOR=\"$theme->link\"><B>". t("read more") ."</B></FONT></A> | ". sizeof(explode(" ", $story->article)) ." ". t("words") ." | <A HREF=\"story.php?id=$story->id\"><FONT COLOR=\"$theme->link\">". format_plural($story->comments, "comment", "comments") ."</FONT></A> ]" : "[ <A HREF=\"story.php?id=$story->id\"><FONT COLOR=\"$theme->link\">". format_plural($story->comments, "comment", "comments") ."</FONT></A> ]";
 }
 
 function theme_moderation_results($theme, $story) {
diff --git a/modules/diary.module b/modules/diary.module
index c4939bdcac5f..381afc887abd 100644
--- a/modules/diary.module
+++ b/modules/diary.module
@@ -35,7 +35,7 @@ function diary_page_overview($num = 20) {
 
   while ($diary = db_fetch_object($result)) {
     if ($time != date("F jS", $diary->timestamp)) {
-      $output .= "<B>". date("l, F jS", $diary->timestamp) ."</B>\n";
+      $output .= "<B>". $date = t(date("l", $timestamp)) .", ". t(date("F", $timestamp)) ." ". date("j", $diary->timestamp) ."</B>\n";
       $time = date("F jS", $diary->timestamp);
     }
     $output .= "<DL>\n";
@@ -55,13 +55,13 @@ function diary_page_overview($num = 20) {
 function diary_page_entry($timestamp, $text, $id = 0) {
   if ($id) {
     $output .= "<DL>\n";
-    $output .= " <DT><B>". date("l, F jS", $timestamp) .":</B> </DT>\n";
+    $output .= " <DT><B>". format_date($timestamp, "large") .":</B></DT>\n";
     $output .= " <DD><P>[ <A HREF=\"module.php?mod=diary&op=edit&id=$id\">". t("edit") ."</A> ]</P><P>". check_output($text, 1) ."</P></DD>\n";
     $output .= "</DL>\n";
   }
   else {
     $output .= "<DL>\n";
-    $output .= " <DT><B>". date("l, F jS", $timestamp) .":</B></DT>\n";
+    $output .= " <DT><B>". format_date($timestamp, "large") .":</B></DT>\n";
     $output .= " <DD><P>". check_output($text, 1) ."</P></DD>\n";
     $output .= "</DL>\n";
   }
@@ -215,7 +215,7 @@ function diary_user($username, $section, $operation) {
   if ($section == "user" && $operation == "view") {
     $result = db_query("SELECT d.* FROM diaries d LEFT JOIN users u ON u.id = d.author WHERE u.userid = '$username' AND d.timestamp > ". (time() - 1209600) ." ORDER BY id DESC LIMIT 2");
     while ($diary = db_fetch_object($result)) {
-      $content .= "<DL><DT><B>". date("l, F jS", $diary->timestamp) .":</B></DT><DD><P>". check_output($diary->text) ."</P><P>[ <A HREF=\"module.php?mod=diary&op=view&name=$username\">more</A> ]</P></DD></DL>\n";
+      $content .= "<DL><DT><B>". format_date($diary->timestamp, "large") .":</B></DT><DD><P>". check_output($diary->text) ."</P><P>[ <A HREF=\"module.php?mod=diary&op=view&name=$username\">more</A> ]</P></DD></DL>\n";
       $diaries++;
     }
 
@@ -236,7 +236,7 @@ function diary_block() {
 
   while ($diary = db_fetch_object($result)) {
     if ($time != date("F jS", $diary->timestamp)) {
-      $content .= "<P><B>". date("l, M jS", $diary->timestamp) ."</B></P>\n";
+      $content .= "<P><B>". t(date("l", $diary->timestamp)) ."</B> (". date("m/d/Y", $diary->timestamp) .")</P>\n";
       $time = date("F jS", $diary->timestamp);
     }
     $content .= "<LI><A HREF=\"module.php?mod=diary&op=view&name=$diary->userid\">$diary->userid</A></LI>\n";
diff --git a/modules/drupal.module b/modules/drupal.module
index 8ece0a6d9105..47a08265a470 100644
--- a/modules/drupal.module
+++ b/modules/drupal.module
@@ -43,12 +43,12 @@ function drupal_page() {
   global $cid, $comment, $id, $op, $pid, $lid, $link, $mode, $order, $subject, $theme, $threshold;
 
   switch($op) {
-    case "Preview comment":
+    case t("Preview comment"):
       $theme->header();
       comment_preview($pid, $id, $subject, $comment);
       $theme->footer();
       break;
-    case "Post comment":
+    case t("Post comment"):
       comment_post($pid, $id, $subject, $comment);
       $theme->header();
       drupal_render($id, $cid);
@@ -59,13 +59,13 @@ function drupal_page() {
       comment_reply($pid, $id);
       $theme->footer();
       break;
-    case "Update settings":
+    case t("Update settings"):
       comment_settings($mode, $order, $threshold);
       $theme->header();
       drupal_render($id, $cid);
       $theme->footer();
       break;
-    case "Moderate comments":
+    case t("Moderate comments"):
       comment_moderate($moderate);
       $theme->header();
       drupal_render($id, $cid);
diff --git a/modules/drupal/drupal.module b/modules/drupal/drupal.module
index 8ece0a6d9105..47a08265a470 100644
--- a/modules/drupal/drupal.module
+++ b/modules/drupal/drupal.module
@@ -43,12 +43,12 @@ function drupal_page() {
   global $cid, $comment, $id, $op, $pid, $lid, $link, $mode, $order, $subject, $theme, $threshold;
 
   switch($op) {
-    case "Preview comment":
+    case t("Preview comment"):
       $theme->header();
       comment_preview($pid, $id, $subject, $comment);
       $theme->footer();
       break;
-    case "Post comment":
+    case t("Post comment"):
       comment_post($pid, $id, $subject, $comment);
       $theme->header();
       drupal_render($id, $cid);
@@ -59,13 +59,13 @@ function drupal_page() {
       comment_reply($pid, $id);
       $theme->footer();
       break;
-    case "Update settings":
+    case t("Update settings"):
       comment_settings($mode, $order, $threshold);
       $theme->header();
       drupal_render($id, $cid);
       $theme->footer();
       break;
-    case "Moderate comments":
+    case t("Moderate comments"):
       comment_moderate($moderate);
       $theme->header();
       drupal_render($id, $cid);
diff --git a/modules/locale.module b/modules/locale.module
index 95594a65a655..8a1c3e1ac4a4 100644
--- a/modules/locale.module
+++ b/modules/locale.module
@@ -1,17 +1,92 @@
 <?
 
-$module = array("page" => "locale",
-                "admin" => "locale");
+$module = array("help" => "locale_help",
+                "admin" => "locale_admin",
+                "locale" => "locale_locale");
 
-function locale() {
-  $result = db_query("SELECT * FROM locales ORDER BY english");
+function locale_help() {
+  print "under construction";
+}
+
+function locale_delete($id) {
+  db_query("DELETE FROM locales WHERE id = '$id'");
+}
+
+function locale_save($id, $edit) {
+  foreach ($edit as $key=>$value) {
+    db_query("UPDATE locales SET $key = '". check_input($value) ."' WHERE id = '$id'");
+  }
+}
+
+function locale_edit($id) {
+  global $languages;
+  $result = db_query("SELECT * FROM locales WHERE id = '$id'");
+  if ($translation = db_fetch_object($result)) {
+    $output .= "<FORM ACTION=\"admin.php?mod=locale\" METHOD=\"post\">\n";
+    $output .= "<B>Original string:</B><BR>\n";
+    $output .= check_output($translation->string) ."<P>";
+    foreach ($languages as $code=>$language) {
+      $output .= "<B>$language:</B><BR>";
+      $output .= "<INPUT TYPE=\"text\" NAME=\"edit[$code]\" VALUE=\"". check_textfield($translation->$code) ."\"><P>";
+    }
+    $output .= "<INPUT NAME=\"id\" TYPE=\"hidden\" VALUE=\"$id\">\n";
+    $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Save translations\">\n";
+    $output .= "</FORM>\n";
+
+    print $output;
+  }
+}
+
+function locale_languages($translation) {
+  global $languages;
+  foreach ($languages as $key=>$value) {
+    $output .= ($translation->$key) ? "$key " : "<STRIKE>$key</STRIKE> ";
+  }
+  return $output;
+}
+
+function locale_display() {
+  $result = db_query("SELECT * FROM locales ORDER BY string");
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
-  $output .= " <TR><TH>string</TH><TH COLSPAN=\"2\">operations</TH><TR>\n";
+  $output .= " <TR><TH>string</TH><TH>languages</TH><TH COLSPAN=\"2\">operations</TH><TR>\n";
   while ($locale = db_fetch_object($result)) {
-    $output .= " <TR><TD>". check_output($locale->english) ."<BR><SMALL><I>$locale->location</I></SMALL></TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">edit</A></TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">delete</A></TD></TR>";
+    $languages = locale_languages($locale);
+    $output .= " <TR><TD>". check_output($locale->string) ."<BR><SMALL><I>$locale->location</I></SMALL></TD><TD ALIGN=\"center\">$languages</TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">edit</A></TD><TD><A HREF=\"admin.php?mod=locale&op=delete&id=$locale->id\">delete</A></TD></TR>";
   }
   $output .= "</TABLE>\n";
   print $output;
 }
 
-?>
+function locale_admin() {
+  global $id, $edit, $op;
+
+  print "<SMALL><A HREF=\"admin.php?mod=locale\">overview</A> | <A HREF=\"admin.php?mod=locale&op=help\">help</A></SMALL><HR>\n";
+
+  switch ($op) {
+    case "delete":
+      locale_delete($id);
+      locale_display();
+      break;
+    case "help":
+      locale_help();
+      break;
+    case "edit":
+      locale_edit($id);
+      break;
+    case "Save translations":
+      locale_save($id, $edit);
+      // fall through
+    default:
+      locale_display();
+  }
+}
+
+function locale($string) {
+  global $locale;
+  $result = db_query("SELECT id, $locale FROM locales WHERE STRCMP(string, '". addslashes($string) ."') = 0");
+  if ($translation = db_fetch_object($result)) $string = ($translation->$locale) ? check_output($translation->$locale) : $string;
+  else db_query("INSERT INTO locales (string, location) VALUES ('". addslashes($string) ."', '". check_input(getenv("REQUEST_URI")) ."')");
+  return $string;
+}
+
+?>
\ No newline at end of file
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 95594a65a655..8a1c3e1ac4a4 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -1,17 +1,92 @@
 <?
 
-$module = array("page" => "locale",
-                "admin" => "locale");
+$module = array("help" => "locale_help",
+                "admin" => "locale_admin",
+                "locale" => "locale_locale");
 
-function locale() {
-  $result = db_query("SELECT * FROM locales ORDER BY english");
+function locale_help() {
+  print "under construction";
+}
+
+function locale_delete($id) {
+  db_query("DELETE FROM locales WHERE id = '$id'");
+}
+
+function locale_save($id, $edit) {
+  foreach ($edit as $key=>$value) {
+    db_query("UPDATE locales SET $key = '". check_input($value) ."' WHERE id = '$id'");
+  }
+}
+
+function locale_edit($id) {
+  global $languages;
+  $result = db_query("SELECT * FROM locales WHERE id = '$id'");
+  if ($translation = db_fetch_object($result)) {
+    $output .= "<FORM ACTION=\"admin.php?mod=locale\" METHOD=\"post\">\n";
+    $output .= "<B>Original string:</B><BR>\n";
+    $output .= check_output($translation->string) ."<P>";
+    foreach ($languages as $code=>$language) {
+      $output .= "<B>$language:</B><BR>";
+      $output .= "<INPUT TYPE=\"text\" NAME=\"edit[$code]\" VALUE=\"". check_textfield($translation->$code) ."\"><P>";
+    }
+    $output .= "<INPUT NAME=\"id\" TYPE=\"hidden\" VALUE=\"$id\">\n";
+    $output .= "<INPUT NAME=\"op\" TYPE=\"submit\" VALUE=\"Save translations\">\n";
+    $output .= "</FORM>\n";
+
+    print $output;
+  }
+}
+
+function locale_languages($translation) {
+  global $languages;
+  foreach ($languages as $key=>$value) {
+    $output .= ($translation->$key) ? "$key " : "<STRIKE>$key</STRIKE> ";
+  }
+  return $output;
+}
+
+function locale_display() {
+  $result = db_query("SELECT * FROM locales ORDER BY string");
   $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"2\" CELLSPACING=\"2\">\n";
-  $output .= " <TR><TH>string</TH><TH COLSPAN=\"2\">operations</TH><TR>\n";
+  $output .= " <TR><TH>string</TH><TH>languages</TH><TH COLSPAN=\"2\">operations</TH><TR>\n";
   while ($locale = db_fetch_object($result)) {
-    $output .= " <TR><TD>". check_output($locale->english) ."<BR><SMALL><I>$locale->location</I></SMALL></TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">edit</A></TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">delete</A></TD></TR>";
+    $languages = locale_languages($locale);
+    $output .= " <TR><TD>". check_output($locale->string) ."<BR><SMALL><I>$locale->location</I></SMALL></TD><TD ALIGN=\"center\">$languages</TD><TD><A HREF=\"admin.php?mod=locale&op=edit&id=$locale->id\">edit</A></TD><TD><A HREF=\"admin.php?mod=locale&op=delete&id=$locale->id\">delete</A></TD></TR>";
   }
   $output .= "</TABLE>\n";
   print $output;
 }
 
-?>
+function locale_admin() {
+  global $id, $edit, $op;
+
+  print "<SMALL><A HREF=\"admin.php?mod=locale\">overview</A> | <A HREF=\"admin.php?mod=locale&op=help\">help</A></SMALL><HR>\n";
+
+  switch ($op) {
+    case "delete":
+      locale_delete($id);
+      locale_display();
+      break;
+    case "help":
+      locale_help();
+      break;
+    case "edit":
+      locale_edit($id);
+      break;
+    case "Save translations":
+      locale_save($id, $edit);
+      // fall through
+    default:
+      locale_display();
+  }
+}
+
+function locale($string) {
+  global $locale;
+  $result = db_query("SELECT id, $locale FROM locales WHERE STRCMP(string, '". addslashes($string) ."') = 0");
+  if ($translation = db_fetch_object($result)) $string = ($translation->$locale) ? check_output($translation->$locale) : $string;
+  else db_query("INSERT INTO locales (string, location) VALUES ('". addslashes($string) ."', '". check_input(getenv("REQUEST_URI")) ."')");
+  return $string;
+}
+
+?>
\ No newline at end of file
diff --git a/modules/watchdog.module b/modules/watchdog.module
index 81593d4c0a40..f1bb7925fac7 100644
--- a/modules/watchdog.module
+++ b/modules/watchdog.module
@@ -50,7 +50,7 @@ function watchdog_view($id) {
   if ($watchdog = db_fetch_object($result)) {
     $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>Level:</B></TD><TD>$watchdog->level</TD></TR>\n";
-    $output .= " <TR><TD ALIGN=\"right\"><B>Date:</B></TD><TD>". format_date($watchdog->timestamp, "extra large") ."</TD></TR>\n";
+    $output .= " <TR><TD ALIGN=\"right\"><B>Date:</B></TD><TD>". format_date($watchdog->timestamp, "large") ."</TD></TR>\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>User:</B></TD><TD>". format_username($watchdog->userid) ."</TD></TR>\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>Location:</B></TD><TD>$watchdog->location</TD></TR>\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>Message:</B></TD><TD>$watchdog->message</TD></TR>\n";
diff --git a/modules/watchdog/watchdog.module b/modules/watchdog/watchdog.module
index 81593d4c0a40..f1bb7925fac7 100644
--- a/modules/watchdog/watchdog.module
+++ b/modules/watchdog/watchdog.module
@@ -50,7 +50,7 @@ function watchdog_view($id) {
   if ($watchdog = db_fetch_object($result)) {
     $output .= "<TABLE BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\">\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>Level:</B></TD><TD>$watchdog->level</TD></TR>\n";
-    $output .= " <TR><TD ALIGN=\"right\"><B>Date:</B></TD><TD>". format_date($watchdog->timestamp, "extra large") ."</TD></TR>\n";
+    $output .= " <TR><TD ALIGN=\"right\"><B>Date:</B></TD><TD>". format_date($watchdog->timestamp, "large") ."</TD></TR>\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>User:</B></TD><TD>". format_username($watchdog->userid) ."</TD></TR>\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>Location:</B></TD><TD>$watchdog->location</TD></TR>\n";
     $output .= " <TR><TD ALIGN=\"right\"><B>Message:</B></TD><TD>$watchdog->message</TD></TR>\n";
diff --git a/search.php b/search.php
index 77d2ff50ae0c..23daad6dc7e0 100644
--- a/search.php
+++ b/search.php
@@ -12,7 +12,7 @@ function find_module($name, $module) {
 $search .= "<FORM ACTION=\"search.php\" METHOD=\"POST\">\n";
 $search .= " <INPUT SIZE=\"50\" VALUE=\"". check_textfield($keys) ."\" NAME=\"keys\" TYPE=\"text\">\n";
 $search .= " <SELECT NAME=\"type\">$options</SELECT>\n";
-$search .= " <INPUT TYPE=\"submit\" VALUE=\"Search\">\n";
+$search .= " <INPUT TYPE=\"submit\" VALUE=\"". t("Search") ."\">\n";
 $search .= "</FORM>\n";
 
 $output = search_data($keys, $type);
diff --git a/story.php b/story.php
index 7f12e535f727..1e640d9a0749 100644
--- a/story.php
+++ b/story.php
@@ -9,27 +9,27 @@ function story_render($id, $cid) {
   $story = db_fetch_object(db_query("SELECT s.*, u.userid FROM stories s LEFT JOIN users u ON s.author = u.id WHERE s.id = $id"));
 
   if (story_visible($story)) {
-    $theme->article($story, "[ <A HREF=\"story.php?op=reply&id=$id&pid=0\">reply to this story</A> ]");
+    $theme->article($story, "[ <A HREF=\"story.php?op=reply&id=$id&pid=0\">". t("reply to this story") ."</A> ]");
     comment_render($id, $cid);
   }
   else {
-    $theme->box("Warning message", "The story you requested is not available or does not exist.");
+    $theme->box(t("Warning message"), t("The story you requested is not available or does not exist."));
   }
 }
 
 switch($op) {
-  case "Preview comment":
+  case t("Preview comment"):
     $theme->header();
     comment_preview($pid, $id, $subject, $comment);
     $theme->footer();
     break;
-  case "Post comment":
+  case t("Post comment"):
     comment_post($pid, $id, $subject, $comment);
     $theme->header();
     story_render($id, $cid);
     $theme->footer();
     break;
-  case "Add comment":
+  case t("Add comment"):
     $theme->header();
     comment_reply($cid, $id);
     $theme->footer();
@@ -39,13 +39,13 @@ function story_render($id, $cid) {
     comment_reply($pid, $id);
     $theme->footer();
     break;
-  case "Update settings":
+  case t("Update settings"):
     comment_settings($mode, $order, $threshold);
     $theme->header();
     story_render($id, $cid);
     $theme->footer();
     break;
-  case "Moderate comments":
+  case t("Moderate comments"):
     comment_moderate($moderate);
     $theme->header();
     story_render($id, $cid);
diff --git a/submit.php b/submit.php
index 7db513f90a3d..337aa69a217e 100644
--- a/submit.php
+++ b/submit.php
@@ -1,5 +1,7 @@
 <?
 
+include_once "includes/common.inc";
+
 function submit_enter() {
   global $anonymous, $allowed_html, $theme, $user;
 
@@ -11,44 +13,31 @@ function submit_enter() {
   // Submission form:
   $output .= "<FORM ACTION=\"submit.php\" METHOD=\"post\">\n";
 
-  $output .= "<P>\n";
-  $output .= " <B>". t("Your name") .":</B><BR>\n";
-  $output .= format_username($user->userid);
-  $output .= "</P>\n";
-
-  $output .= "<P>\n";
-  $output .= " <B>". t("Subject") .":</B><BR>\n";
-  $output .= " <INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\"><BR>\n";
-  $output .= "</P>\n";
-
-  $output .= "<P>\n";
-  $output .= " <B>". t("Section") .":</B><BR>\n";
-  $output .= " <SELECT NAME=\"section\">\n";
-  foreach ($sections = section_get() as $value) $output .= "  <OPTION VALUE=\"$value\">$value</OPTION>\n";
-  $output .= " </SELECT>\n";
-  $output .= "</P>\n";
-
-  $output .= "<P>\n";
-  $output .= " <B>". t("Abstract") .":</B><BR>\n";
-  $output .= " <TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"abstract\" MAXLENGTH=\"20\"></TEXTAREA><BR>\n";
-  $output .= " <SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL>\n";
-  $output .= "</P>\n";
-
-  $output .= "<P>\n";
-  $output .= " <B>". t("Extended story") .":</B><BR>\n";
-  $output .= " <TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"15\" NAME=\"article\"></TEXTAREA><BR>\n";
-  $output .= " <SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL>\n";
-  $output .= "</P>\n";
-
-  $output .= "<P>\n";
-  $output .= " <SMALL><I>". t("You must preview at least once before you can submit") .":</I></SMALL><BR>\n";
-  $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Preview submission\">\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Your name") .":</B><BR>\n";
+  $output .= format_username($user->userid) ."<P>\n";
+
+  $output .= "<B>". t("Subject") .":</B><BR>\n";
+  $output .= "<INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\"><P>\n";
+
+  $output .= "<B>". t("Section") .":</B><BR>\n";
+  foreach ($sections = section_get() as $value) $options .= "  <OPTION VALUE=\"$value\">$value</OPTION>\n";
+  $output .= "<SELECT NAME=\"section\">$options</SELECT><P>\n";
+
+  $output .= "<B>". t("Abstract") .":</B><BR>\n";
+  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"abstract\" MAXLENGTH=\"20\"></TEXTAREA><BR>\n";
+  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
+
+  $output .= "<B>". t("Extended story") .":</B><BR>\n";
+  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"15\" NAME=\"article\"></TEXTAREA><BR>\n";
+  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
+
+  $output .= "<SMALL><I>". t("You must preview at least once before you can submit") .":</I></SMALL><BR>\n";
+  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview submission") ."\"><P>\n";
 
   $output .= "</FORM>\n";
 
   $theme->header();
-  $theme->box(t("Submit a story"), $output);
+  $theme->box(t("New submission"), $output);
   $theme->footer();
 }
 
@@ -59,54 +48,35 @@ function submit_preview($subject, $abstract, $article, $section) {
 
   $output .= "<FORM ACTION=\"submit.php\" METHOD=\"post\">\n";
 
-  $output .= "<P>\n";
-  $output .= " <B>". t("Your name") .":</B><BR>\n";
-  $output .= format_username($user->userid);
-  $output .= "</P>\n";
+  $output .= "<B>". t("Your name") .":</B><BR>\n";
+  $output .= format_username($user->userid) ."<P>";
 
-  $output .= "<P>\n";
-  $output .= " <B>". t("Subject") .":</B><BR>\n";
-  $output .= " <INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\" VALUE=\"". check_output(check_textfield($subject)) ."\"><BR>\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Subject") .":</B><BR>\n";
+  $output .= "<INPUT TYPE=\"text\" NAME=\"subject\" SIZE=\"50\" MAXLENGTH=\"60\" VALUE=\"". check_textfield($subject) ."\"><BR><P>\n";
 
-  $output .= "<P>\n";
-  $output .= " <B>". t("Section") .":</B><BR>\n";
-  $output .= " <SELECT NAME=\"section\">\n";
-  foreach ($sections = section_get() as $value) $output .= "  <OPTION VALUE=\"$value\"". ($section == $value ? " SELECTED" : "") .">$value</OPTION>\n";
-  $output .= "</SELECT>\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Section") .":</B><BR>\n";
+  foreach ($sections = section_get() as $value) $options .= "  <OPTION VALUE=\"$value\"". ($section == $value ? " SELECTED" : "") .">$value</OPTION>\n";
+  $output .= "<SELECT NAME=\"section\">$options</SELECT><P>\n";
 
-  $output .= "<P>\n";
   $output .= "<B>". t("Abstract") .":</B><BR>\n";
-  $output .= " <TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"abstract\">". check_textarea($abstract) ."</TEXTAREA><BR>\n";
-  $output .= " <SMALL><I>Allowed HTML tags: ". htmlspecialchars($allowed_html) .".</I></SMALL>\n";
-  $output .= "</P>\n";
+  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"10\" NAME=\"abstract\">". check_textarea($abstract) ."</TEXTAREA><BR>\n";
+  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
 
-  $output .= "<P>\n";
-  $output .= " <B>". t("Extended story") .":</B><BR>\n";
-  $output .= " <TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"15\" NAME=\"article\">". check_textarea($article) ."</TEXTAREA><BR>\n";
-  $output .= " <SMALL><I>Allowed HTML tags: ". htmlspecialchars($allowed_html) .".</I></SMALL>\n";
-  $output .= "</P>\n";
+  $output .= "<B>". t("Extended story") .":</B><BR>\n";
+  $output .= "<TEXTAREA WRAP=\"virtual\" COLS=\"50\" ROWS=\"15\" NAME=\"article\">". check_textarea($article) ."</TEXTAREA><BR>\n";
+  $output .= "<SMALL><I>". t("Allowed HTML tags") .": ". htmlspecialchars($allowed_html) .".</I></SMALL><P>\n";
 
   if (empty($subject)) {
-    $output .= "<P><FONT COLOR=\"red\">". t("Warning: you did not supply a subject.") ."</FONT></P>\n";
-    $output .= "<P>\n";
-    $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Preview submission\">\n";
-    $output .= "</P>\n";
+    $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply a subject.") ."</FONT><P>\n";
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview submission") ."\">\n";
   }
   else if (empty($abstract)) {
-    $output .= "<P>\n";
-    $output .= " <FONT COLOR=\"red\">". t("Warning: you did not supply an abstract.") ."\n";
-    $outout .= "</P>\n";
-    $output .= "<P>\n";
-    $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Preview submission\">\n";
-    $output .= "</P>\n";
+    $output .= "<FONT COLOR=\"red\">". t("Warning: you did not supply an abstract.") ."</FONT><P>\n";
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview submission") ."\">\n";
   }
   else {
-    $output .= "<P>\n";
-    $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Preview submission\">\n";
-    $output .= " <INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Submit submission\">\n";
-    $output .= "</P>\n";
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Preview submission") ."\">\n";
+    $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"". t("Submit submission") ."\">\n";
   }
   $output .= "</FORM>\n";
 
@@ -127,17 +97,15 @@ function submit_submit($subject, $abstract, $article, $section) {
 
   // Display confirmation message:
   $theme->header();
-  $theme->box("Thank you for your submission.", "Thank you for your submission. Your submission has been whisked away to our submission queue where our registered users will frown at it, poke at it and hopefully carry it to the front page for discussion.");
+  $theme->box(t("Submission completed"), t("Thank you for your submission. Your submission has been whisked away to our submission queue where our registered users will frown at it, poke at it and hopefully carry it to the front page for discussion."));
   $theme->footer();
 }
 
-include_once "includes/common.inc";
-
 switch($op) {
-  case "Preview submission":
+  case t("Preview submission"):
     submit_preview($subject, $abstract, $article, $section);
     break;
-  case "Submit submission":
+  case t("Submit submission"):
     submit_submit($subject, $abstract, $article, $section);
     break;
   default:
diff --git a/themes/marvin/marvin.theme b/themes/marvin/marvin.theme
index 287c8a524cc0..50622d264d86 100644
--- a/themes/marvin/marvin.theme
+++ b/themes/marvin/marvin.theme
@@ -45,7 +45,7 @@ function header() {
         <TD ALIGN="right" COLSPAN="2"><SMALL><A HREF="index.php">home</A> | <A HREF="module.php?mod=faq">faq</A> | <A HREF="module.php?mod=diary">diary</A> | <A HREF="search.php">search</A> | <A HREF="submit.php">submit news</A> | <A HREF="account.php">user account</A></SMALL></TD>
        </TR>
        <TR>
-        <TD VALIGN="top" WIDTH="100%">
+        <TD VALIGN="top" WIDTH="85%">
     <?
    }
 
@@ -56,7 +56,7 @@ function abstract($story) {
      print " <TR VALIGN=\"bottom\"><TD COLSPAN=\"2\" BGCOLOR=\"#000000\" WIDTH=\"100%\"><IMG SRC=\"themes/marvin/images/pixel.gif\" WIDTH=\"1\" HEIGHT=\"0\" ALT=\"\"></TD></TR>\n";
      print " <TR>\n";
      print "  <TD>\n";
-     print "   <FONT COLOR=\"#7C7C7C\"><SMALL>Submitted by ". format_username($story->userid) ." on ". format_date($story->timestamp, "extra large"). ""; ?><? if ($story->department) print "<BR>from the $story->department dept."; ?><? print "</SMALL></FONT></TD><TD ALIGN=\"right\" VALIGN=\"top\" NOWRAP><SMALL><A HREF=\"?section=". urlencode($story->section) ."\"><FONT COLOR=\"#83997A\">$story->section</FONT></A></SMALL>\n";
+     print "   <FONT COLOR=\"#7C7C7C\"><SMALL>". strtr(t("Submitted by %a on %b"), array("%a" => format_username($story->userid), "%b" => format_date($story->timestamp, "large"))); ?><? if ($story->department) print "<BR>from the $story->department dept."; ?><? print "</SMALL></FONT></TD><TD ALIGN=\"right\" VALIGN=\"top\" NOWRAP><SMALL><A HREF=\"?section=". urlencode($story->section) ."\"><FONT COLOR=\"#83997A\">$story->section</FONT></A></SMALL>\n";
      print "  </TD>\n";
      print " </TR>\n";
      print " <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n";
@@ -79,7 +79,7 @@ function article($story, $reply = "") {
      print " <TR VALIGN=\"bottom\"><TD COLSPAN=\"2\" BGCOLOR=\"#000000\" WIDTH=\"100%\"><IMG SRC=\"themes/marvin/images/pixel.gif\" WIDTH=\"1\" HEIGHT=\"0\" ALT=\"\"></TD></TR>\n";
      print " <TR>\n";
      print "  <TD>\n";
-     print "   <FONT COLOR=\"#7C7C7C\"><SMALL>Submitted by ". format_username($story->userid) ." on ". format_date($story->timestamp, "extra large") .""; ?><? if ($story->department) print "<BR>from the $story->department dept."; ?><? print "</SMALL></FONT></TD><TD ALIGN=\"right\" VALIGN=\"top\" NOWRAP><SMALL><A HREF=\"index.php?section=". urlencode($story->section) ."\"><FONT COLOR=\"#83997A\">$story->section</FONT></A></SMALL>\n";
+     print "   <FONT COLOR=\"#7C7C7C\"><SMALL>". strtr(t("Submitted by %a on %b"), array("%a" => format_username($story->userid), "%b" => format_date($story->timestamp, "large"))); ?><? if ($story->department) print "<BR>from the $story->department dept."; ?><? print "</SMALL></FONT></TD><TD ALIGN=\"right\" VALIGN=\"top\" NOWRAP><SMALL><A HREF=\"index.php?section=". urlencode($story->section) ."\"><FONT COLOR=\"#83997A\">$story->section</FONT></A></SMALL>\n";
      print "  </TD>\n";
      print " </TR>\n";
      print " <TR><TD COLSPAN=\"2\">&nbsp;</TD></TR>\n";
@@ -119,7 +119,7 @@ function comment($comment, $link = "", $thread = "") {
      print "       <TR>\n";
 
      // Subject:
-     print "        <TD ALIGN=\"right\" WIDTH=\"5%\"><B>Subject:</FONT></TD>\n";
+     print "        <TD ALIGN=\"right\" WIDTH=\"5%\"><B>". t("Subject") .":</FONT></TD>\n";
      print "        <TD WIDTH=\"80%\"><B><FONT COLOR=\"$this->hlcolor1\">". check_output($comment->subject) ."</FONT></B></TD>\n";
 
      // Moderation:
@@ -130,12 +130,12 @@ function comment($comment, $link = "", $thread = "") {
 
      // Author:
      print "       <TR>\n";
-     print "        <TD ALIGN=\"right\" VALIGN=\"top\">Author:</TD><TD>". format_username($comment->userid) ."</TD>\n";
+     print "        <TD ALIGN=\"right\" VALIGN=\"top\">". t("Author") .":</TD><TD>". format_username($comment->userid) ."</TD>\n";
      print "       </TR>\n";
 
      // Date
      print "       <TR>\n";
-     print "        <TD ALIGN=\"right\">Date:</TD><TD>". format_date($comment->timestamp) ."</TD>\n";
+     print "        <TD ALIGN=\"right\">". t("Date") .":</TD><TD>". format_date($comment->timestamp) ."</TD>\n";
      print "       </TR>\n";
 
      print "      </TABLE>\n";
@@ -175,7 +175,7 @@ function box($subject, $content, $options = "") {
    function footer() {
      ?>
        </TD>
-       <TD VALIGN="top">
+       <TD VALIGN="top" WIDTH=\"200\">
          <?
           theme_account($this);
           theme_blocks("all", $this);
diff --git a/updates/1.00-to-1.xx b/updates/1.00-to-1.xx
index 5d9b70e5a292..7cc514ec03a2 100644
--- a/updates/1.00-to-1.xx
+++ b/updates/1.00-to-1.xx
@@ -21,3 +21,6 @@ create table locales (
   location varchar(128) DEFAULT '' NOT NULL,
   PRIMARY KEY (id)
 );
+
+# 14/02/2001: locale / internationalisation
+alter table users add language varchar(2) DEFAULT '' NOT NULL;
-- 
GitLab