afuna: Cat under a blanket. Text: "Cats are just little people with Fur and Fangs" (Default)
afuna ([personal profile] afuna) wrote in [site community profile] changelog2010-02-16 03:27 pm

[dw-free] move /translate to /admin/translate

[commit: http://hg.dwscoalition.org/dw-free/rev/8428f0b6ae2d]

http://bugs.dwscoalition.org/show_bug.cgi?id=2323

Move all pages under /translate to /admin/translate.

Patch by [staff profile] denise.

Files modified:
  • cgi-bin/redirect.dat
  • htdocs/admin/index.bml
  • htdocs/admin/index.bml.text
  • htdocs/admin/translate/diff.bml
  • htdocs/admin/translate/edit.bml
  • htdocs/admin/translate/editpage.bml
  • htdocs/admin/translate/help-severity.bml
  • htdocs/admin/translate/index.bml
  • htdocs/admin/translate/index.bml.text
  • htdocs/admin/translate/search.bml
  • htdocs/admin/translate/searchform.bml
  • htdocs/admin/translate/teams.bml
  • htdocs/admin/translate/teams.bml.text
  • htdocs/admin/translate/welcome.bml
  • htdocs/translate/diff.bml
  • htdocs/translate/edit.bml
  • htdocs/translate/editpage.bml
  • htdocs/translate/help-severity.bml
  • htdocs/translate/index.bml
  • htdocs/translate/index.bml.text
  • htdocs/translate/search.bml
  • htdocs/translate/searchform.bml
  • htdocs/translate/teams.bml
  • htdocs/translate/teams.bml.text
  • htdocs/translate/welcome.bml
--------------------------------------------------------------------------------
diff -r 9323f181bcb6 -r 8428f0b6ae2d cgi-bin/redirect.dat
--- a/cgi-bin/redirect.dat	Tue Feb 16 15:09:47 2010 +0000
+++ b/cgi-bin/redirect.dat	Tue Feb 16 15:26:10 2010 +0000
@@ -45,3 +45,13 @@
 /mobile/friends.bml                 /mobile/read
 /misc/import                        /tools/importer
 /misc/import.bml                    /tools/importer
+/translate                          /admin/translate
+/translate/                         /admin/translate
+/translate/diff.bml                 /admin/translate/diff
+/translate/edit.bml                 /admin/translate/edit
+/translate/editpage.bml             /admin/translate/editpage
+/translate/help-severity.bml        /admin/translate/help-severity
+/translate/search.bml               /admin/translate/search
+/translate/searchform.bml           /admin/translate/searchform
+/translate/teams.bml                /admin/translate/teams
+/translate/welcome.bml              /admin/translate/welcome
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/index.bml
--- a/htdocs/admin/index.bml	Tue Feb 16 15:09:47 2010 +0000
+++ b/htdocs/admin/index.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -100,6 +100,8 @@ body<=
             '<?_ml .admin.sysban.link _ml?>', '<?_ml .admin.sysban.text _ml?>', [ 'sysban' ] ],
         [ 'theschwartz',
             '<?_ml .admin.theschwartz.link _ml?>', '<?_ml .admin.theschwartz.text _ml?>', [ 'siteadmin:theschwartz' ] ],
+        [ 'translate/',
+            '<?_ml .admin.translate.link _ml?>', '<?_ml .admin.translate.text _ml?>' ],
         [ 'userlog',
             '<?_ml .admin.userlog.link _ml?>', '<?_ml .admin.userlog.text _ml?>', [ 'canview:userlog', 'canview:*' ] ],
     );
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/index.bml.text
--- a/htdocs/admin/index.bml.text	Tue Feb 16 15:09:47 2010 +0000
+++ b/htdocs/admin/index.bml.text	Tue Feb 16 15:26:10 2010 +0000
@@ -80,6 +80,9 @@
 .admin.theschwartz.link=TheSchwartz Queue/Error Viewer
 .admin.theschwartz.text=View the status of jobs in the TheSchwartz queue.
 
+.admin.translate.link=Translation & Site Copy
+.admin.translate.text=View and edit the site copy and translations.
+
 .admin.userlog.link=Userlog Viewer
 .admin.userlog.text=Shows you a user's logged actions.
 
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/diff.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/diff.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,156 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<style type="text/css">
+del {
+    text-decoration: none;
+    color: #ff0000;
+    background-color: #ffd0d0;
+}
+ins {
+    text-decoration: none;
+    color: #002000;
+    background-color: #20ff20;
+}
+</style>
+</head>
+<body>
+<?_code
+{
+    use strict;
+    use vars qw(%GET);
+    use File::Temp qw/tempfile/;
+    
+    BML::set_content_type("text/html; charset=utf-8");
+    
+    my $lang = $GET{'lang'};
+    my $l = LJ::Lang::get_lang($lang);
+    return "<b>Invalid language</b>" unless $l;
+
+    return "<b>Invalid item</b>" unless $GET{'it'} =~ /^(\d+):(\d+)$/;
+    my ($dmid, $itid) = ($1, $2);
+    
+    my @lnids = $l->{'lnid'};
+    {
+        my $il = $l;
+        while ($il && $il->{'parentlnid'}) {
+            push @lnids, $il->{'parentlnid'};
+            $il = LJ::Lang::get_lang_id($il->{'parentlnid'});
+        }
+    }
+    my $lnids = join(",", @lnids);
+
+    my $dbr = LJ::get_db_reader();
+    my ($sth, $ret);
+
+    my $sth = $dbr->prepare("select * from ml_text where dmid=$dmid and itid=$itid and lnid in ($lnids) ORDER BY txtid");
+    $sth->execute;
+    my @tlist;
+    while (my $t = $sth->fetchrow_hashref) { 
+        next if @tlist && $t->{'text'} eq $tlist[-1]->{'text'};
+        push @tlist, $t; 
+    }
+
+    my $changes = scalar @tlist - 1;
+    return "<b>No changes</b>" unless $changes;
+
+    my $view_change = $GET{'change'} || $changes;
+    return "bogus change" if $view_change < 1 || $view_change > $changes;
+    for (1..$changes) {
+        if ($_ eq $view_change) {
+            $ret .= "<b>[Change $_]</b>\n";
+        } else {
+            $ret .= "<a href='diff?lang=$lang&it=$GET{'it'}&change=$_'>[Change $_]</a>\n";
+        }
+    }
+    $ret .= "<hr>";
+    my $was = $tlist[$view_change-1]->{'text'};
+    my $then = $tlist[$view_change]->{'text'};
+
+    my ($was_alt, $then_alt) = ($was, $then);
+    foreach (\$was_alt, \$then_alt) {
+        $$_ =~ s/\n/*NEWLINE*/g;
+        $$_ =~ s/\s+/\1\n/g;
+        $$_ .= "\n";
+    }
+
+    my ($was_file, $then_file, $fh);
+    my $tries = 0;
+
+    ($fh, $was_file) = tempfile();
+    print $fh $was_alt; close $fh;
+    ($fh, $then_file) = tempfile();
+    print $fh $then_alt; close $fh;
+
+    my @words = split(/\n/, $was_alt);
+    my $diff = `diff -u $was_file $then_file`;
+
+    my $pos = 0;
+    my $mode;
+    my $setmode = sub {
+        my $newmode = shift;
+        return " " if $newmode eq $mode;
+        my $ret;
+        $ret .= "</$mode>" if $mode;
+        $ret .= " ";
+        $ret .= "<$newmode>" if $newmode;
+        $mode = $newmode;
+        return $ret;
+    };
+
+    foreach my $dl (split(/\n/, $diff)) {
+        next if $dl =~ /^(\+\+\+|\-\-\-)/;
+        if ($dl =~ /^\@\@ \-(\d+),(\d+)/) {
+            my $newpos = $1;
+            $ret .= $setmode->("");
+            for (my $i=$pos+1; $i<$newpos; $i++) {
+                my $word = LJ::ehtml($words[$i-1]);
+                $word =~ s/\*NEWLINE\*/<br>\n/g;
+                $ret .= "$word ";
+                $pos++;
+            }
+            next;
+        }
+        if ($dl =~ /^ /) {
+            $pos++;
+            my $word = LJ::ehtml($words[$pos-1]);
+            $word =~ s/\*NEWLINE\*/<br>\n/g;
+            $ret .= $setmode->("") . $word;
+        }
+        if ($dl =~ /^\-/) {
+            $pos++;
+            my $word = LJ::ehtml($words[$pos-1]);
+            $word =~ s/\*NEWLINE\*/<br>\n/g;  
+            $ret .= $setmode->("del") . $word;
+        }
+        if ($dl =~ /^\+(.*)/) {
+            my $word = LJ::ehtml($1);
+            $word =~ s/\*NEWLINE\*/<br>\n/g;
+            $ret .= $setmode->("ins") . $word;
+        }
+    }
+
+    $ret .= $setmode->("");
+    while ($pos < @words) {
+        my $word = LJ::ehtml($words[$pos]);
+        $word =~ s/\*NEWLINE\*/<br>\n/g;
+        $ret .= "$word ";
+        $pos++;
+    }
+
+    $was = LJ::eall($was);
+    $was =~ s/\n( *)/"<br \/>" . "&nbsp;"x length($1)/eg;
+    $then = LJ::eall($then);
+    $then =~ s/\n( *)/"<br \/>" . "&nbsp;"x length($1)/eg;
+    
+    $ret .= "<p><table width='100%' border='1'><tr valign='top'><td width='50%'><b>Before:</b><br>$was</td>";
+    $ret .= "<td width='50%'><b>After:</b><br>$then</td></tr></table>";
+
+    unlink($was_file, $then_file);
+
+    return $ret;
+
+}
+_code?>
+</body>
+</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/edit.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/edit.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,14 @@
+<html>
+<head>
+ <title>Language Editor</title>
+</head>
+
+<frameset cols="200,*">
+  <frameset rows="230,*">
+    <frame name="search" src="searchform?lang=<?_code return $FORM{'lang'}; _code?>">
+    <frame name="res" src="search?lang=<?_code return $FORM{'lang'}; _code?>&amp;stale=1%2B&amp;search=sev">
+  </frameset>
+  <frame name="main" src="welcome">
+</frameset>
+
+</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/editpage.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/editpage.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,363 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<?_code
+{
+    LJ::Hooks::run_hook('trans_editpage_bml_postsave_begin');
+    return LJ::res_includes();
+}
+ _code?>
+</head>
+<body>
+<?_code
+ use strict;
+ use vars qw(%FORM);
+
+ BML::set_content_type("text/html; charset=utf-8");
+
+ my $lang = $FORM{'lang'};
+ my $l = LJ::Lang::get_lang($lang);
+ return "<b>Invalid language</b>" unless $l;
+ my $lp = $l->{'parentlnid'} ? LJ::Lang::get_lang_id($l->{'parentlnid'}) : undef;
+
+ my $dbr = LJ::get_db_reader();
+ my $dbh;
+ my ($sth, $ret);
+
+ my $remote = LJ::get_remote();
+ my $can_edit   = $remote && $remote->has_priv( "translate", $l->{'lncode'} );
+ my $can_delete = $remote && $remote->has_priv( "translate", "[itemdelete]" );
+ my $can_rename = $remote && $remote->has_priv( "translate", "[itemrename]" );
+
+ # Extra checkboxes for default language and root language (DW: en_DW and en)
+ my $extra_checkboxes = $l->{'lncode'} eq $LJ::DEFAULT_LANG || !defined $lp;
+
+ my $mode = {
+     '' => 'view',
+     'save' => 'save',
+ }->{$FORM{'mode'}};
+ return "bogus mode" unless $mode;
+
+ my $MAX_EDIT = 100;
+
+ if ($mode eq "view")
+ {
+     my @load;
+     foreach (split /,/, $FORM{'items'})
+     {
+         next unless /^(\d+):(\d+)$/;
+         last if @load >= $MAX_EDIT;
+         push @load, { 'dmid' => $1, 'itid'=> $2 };
+     }
+
+     return "Nothing to show." unless @load;
+
+     $ret .= "<form method='post' action='editpage'>";
+     $ret .= LJ::html_hidden('lang', $lang,
+                             'mode', 'save');
+
+     # load item info
+     my %ml_items;
+     my $itwhere = join(" OR ", map { "(dmid=$_->{'dmid'} AND itid=$_->{'itid'})" } @load);
+     $sth = $dbr->prepare("SELECT dmid, itid, itcode, proofed, updated, notes FROM ml_items WHERE $itwhere");
+     $sth->execute;
+     while (my ($dmid, $itid, $itcode, $proofed, $updated, $notes) = $sth->fetchrow_array) {
+         $ml_items{"$dmid-$itid"} = { 'itcode' => $itcode, 'proofed' => $proofed, 'updated' => $updated, 'notes' => $notes };
+     }
+
+     # getting latest mappings for this lang and parent
+     my %ml_text;
+     my %ml_latest;
+     $sth = $dbr->prepare("SELECT lnid, dmid, itid, txtid, chgtime, staleness FROM ml_latest ".
+                          "WHERE ($itwhere) AND lnid IN ($l->{'lnid'}, $l->{'parentlnid'})");
+     $sth->execute;
+     return $dbr->errstr if $dbr->err;
+     while ($_ = $sth->fetchrow_hashref) {
+         $ml_latest{"$_->{'dmid'}-$_->{'itid'}"}->{$_->{'lnid'}} = $_;
+         $ml_text{"$_->{'dmid'}-$_->{'txtid'}"} = undef;  # mark to load later
+     }
+
+     # load text
+     $sth = $dbr->prepare("SELECT dmid, txtid, lnid, itid, text FROM ml_text ".
+                          "WHERE " . join(" OR ",
+                                          map { "(dmid=$_->[0] AND txtid=$_->[1])" }
+                                          map { [ split(/-/, $_) ] } keys %ml_text));
+     $sth->execute;
+     while ($_ = $sth->fetchrow_hashref) {
+         $ml_text{"$_->{'dmid'}-$_->{'txtid'}"} = $_;
+     }
+
+     if ($can_delete) {
+         $ret .= "<p style='font-size:9pt'><b>To delete an item:</b> edit text to be \"XXDELXX\"</p>";
+     }
+
+     # show all editing items
+     my $ict = 0;
+     foreach my $i (@load)
+     {
+         my ($dmid, $itid) = ($i->{'dmid'}, $i->{'itid'});
+         my $ituq = "$dmid-$itid";
+         my $it = $ml_items{$ituq};
+         my $lat = $ml_latest{$ituq}->{$l->{'lnid'}};
+         next unless $it and $lat;
+         $ict++;
+
+         my $plat;
+         if ($lp && defined $ml_latest{$ituq}->{$lp->{'lnid'}}) {
+             $plat = $ml_latest{$ituq}->{$lp->{'lnid'}};
+         }
+
+         $ret .= LJ::html_hidden("dom_$ict", $dmid,
+                                 "itid_$ict", $itid,
+                                 "oldtxtid_$ict", $lat->{'txtid'},
+                                 "oldptxtid_$ict", $plat ? $plat->{'txtid'} : 0,
+                                 );
+
+         # top bar
+         $ret .= "<table bgcolor='#c0c0c0' width='100%'><tr><td><b>Code:</b> ";
+         if ($dmid != 1) {
+             my $d = LJ::Lang::get_dom_id($dmid);
+             $ret .= "[$d->{'uniq'}] ";
+         }
+
+         my $difflink;
+         if ($lat->{'staleness'}) {
+             $difflink = "($plat->{'chgtime'}, <a target='_new' href='diff?it=$i->{'dmid'}:$i->{'itid'}&lang=$lp->{'lncode'}'>diff</a>)";
+         }
+
+         $ret .= "$it->{'itcode'} $difflink</td>";
+         $ret .= "<td align='right'><b><a target='_new' href='help-severity'>Sev</a>:</b> $lat->{'staleness'}</td>";
+         $ret .= "</tr></table>";
+
+         $ret .= "<dl>";
+         if ($it->{'notes'}) {
+             my $notes = $it->{'notes'};
+             $notes =~ s!\n!<br />!g;
+             $ret .= "<dt><b>Notes:</b></dt><dd>$notes</dd>";
+         }
+
+         my $show_edit = 0;
+         my $use_textarea = 0;
+
+         if ($plat) {
+             $ret .= "<dt><b>$lp->{'lnname'}:</b></dt>";
+             my $t = $ml_text{"$plat->{'dmid'}-$plat->{'txtid'}"}->{'text'};
+             if ($t =~ /\n/) { $use_textarea = 1; }
+             if (length($t) > 255) { $use_textarea = 1; }
+             $t = LJ::eall($t);
+             $t =~ s/\n( *)/"<br \/>" . "&nbsp;"x length($1)/eg;
+             $ret .= "<dd>$t</dd>";
+         }
+
+         my $curtext = LJ::eall($ml_text{"$lat->{'dmid'}-$lat->{'txtid'}"}->{'text'});
+         if ($curtext =~ /\n/) { $use_textarea = 1; }
+         if (length($curtext) > 255) { $use_textarea = 1; }
+         if ($lat->{'staleness'} >= 3) {
+             # if wrong language, why populate it with stuff they'll just have to delete?
+             $curtext = "";
+         }
+
+         $ret .= "<dt><b>$l->{'lnname'}</b>:</b></dt><dd>";
+         my $disabled = "disabled='disabled'";
+         if ($lat->{'staleness'} >= 3) {
+             $disabled = "";
+             # when something's this stale, assume both it's being
+             # edited and that the severity is major (going from wrong
+             # language to right language is a major change, afterall)
+             $ret .= LJ::html_hidden("ed_$ict", "1",
+                                     "sev_$ict", "2",
+                                     );
+         } else {
+             my $js = "a=document.getElementById(\"newtext_$ict\"); a.disabled=!this.checked; if (this.checked) a.focus();";
+             $js .= "a=document.getElementById(\"pr_$ict\"); a.disabled=!this.checked; a=document.getElementById(\"up_$ict\"); a.disabled=!this.checked;"
+                 if $extra_checkboxes;
+             $ret .= "<input name='ed_$ict' type='checkbox' value='1' id='ed_$ict' onClick='$js' /><label for='ed_$ict'>Edit Text</label>";
+             if ($l->{'children'} && @{$l->{'children'}}) {
+                 $ret .= " Severity: ";
+                 $ret .= LJ::html_select({ 'name' => "sev_$ict", "selected" => 1 },
+                                         0 => "Typo/etc (no notify)",
+                                         1 => "Minor (notify translators)",
+                                         2 => "Major (require translation updates)");
+             }
+             $ret .= "<br />" unless $extra_checkboxes;
+         }
+
+         if ( $extra_checkboxes ) {
+             $ret .= " ";
+             $ret .= LJ::html_check( { type => 'checkbox', label => 'Proofed',
+                                       selected => $it->{proofed}, value => 1,
+                                       name => "pr_$ict", id => "pr_$ict",
+                                       disabled => $disabled eq '' ? 0 : 1 } );
+             $ret .= " ";
+             $ret .= LJ::html_check( { type => 'checkbox', label => 'Updated',
+                                       selected => $it->{updated}, value => 1,
+                                       name => "up_$ict", id => "up_$ict",
+                                       disabled => $disabled eq '' ? 0 : 1 } );
+             $ret .= "<br />";
+         }
+
+         if ($use_textarea) {
+             $ret .= "<textarea name='newtext_$ict' id='newtext_$ict' $disabled wrap='soft' rows='10' cols='60'>$curtext</textarea>";
+         } else {
+             $ret .= "<input name='newtext_$ict' id='newtext_$ict' $disabled size='60' value=\"$curtext\"/>";
+         }
+         $ret .= "</dd>\n";
+         $ret .= "</dl>";
+     }
+
+     if ($ict) {
+         $ret .= LJ::html_hidden("ict", $ict);
+         my $disabled = $can_edit ? "" : "disabled='disabled'";
+         $ret .= "<table width='100%' bgcolor='#e0e0e0'><tr><td align='center'><input type='submit' $disabled value='Save' /></td></tr></table>";
+     } else {
+         $ret .= "No items to show.  (since been deleted, perhaps?)";
+     }
+     $ret .= "</form>";
+
+     return $ret;
+ }
+
+ if ($mode eq "save")
+ {
+     my $num = $FORM{'ict'}+0;
+     $num = $MAX_EDIT if $num > $MAX_EDIT;
+
+     my (@errors, @info);
+     unless ($can_edit) {
+         push @errors, "You don't have access to edit text for this language.";
+         $num = 0;
+     }
+
+     unless (LJ::text_in(\%FORM)) {
+         push @errors, "You seem to have changed your browser's encoding to something other than UTF-8.  It needs to be in UTF-8.";
+         push @errors, "Nothing saved.";
+         $num = 0;
+     }
+
+     my $saved = 0;  # do any saves?
+
+     for (my $i=1; $i<=$num; $i++)
+     {
+         next unless $FORM{"ed_$i"};
+         my ($dom, $itid, $oldtxtid, $oldptxtid, $sev, $proofed, $updated) =
+             map { int($FORM{"${_}_$i"}+0) }
+                 qw(dom itid oldtxtid oldptxtid sev pr up);
+
+         my $itcode = $dbr->selectrow_array("SELECT itcode FROM ml_items WHERE dmid=$dom AND itid=$itid");
+         unless (defined $itcode) {
+             push @errors, "Bogus dmid/itid: $dom/$itid";
+             next;
+         }
+
+         $dbh ||= LJ::get_db_writer();
+         my $lat = $dbh->selectrow_hashref("SELECT * FROM ml_latest WHERE lnid=$l->{'lnid'} AND dmid=$dom AND itid=$itid");
+         unless ($lat) {
+             push @errors, "No existing mapping for $itcode";
+             next;
+         }
+         unless ($lat->{'txtid'} == $oldtxtid) {
+             push @errors, "Another translator updated '$itcode' before you saved, so your edit has been ignored.";
+             next;
+         }
+
+         my $plat;
+         if ($lp) {
+             $plat = $dbh->selectrow_hashref("SELECT * FROM ml_latest WHERE lnid=$lp->{'lnid'} ".
+                                             "AND dmid=$dom AND itid=$itid");
+             my $ptid = $plat ? $plat->{'txtid'} : 0;
+             unless ($ptid == $oldptxtid) {
+                 push @errors, "The source text of item '$itcode' changed while you were editing, so your edit has been ignored.";
+                 next;
+             }
+         }
+
+         # did they type anything?
+         my $text = $FORM{"newtext_$i"};
+         next unless $text =~ /\S/;
+
+         # delete
+         if ($text eq "XXDELXX") {
+             if ($can_delete) {
+                 $dbh->do("DELETE FROM ml_latest WHERE dmid=$dom AND itid=$itid");
+                 push @info, "Deleted: '$itcode'";
+             } else {
+                 push @errors, "You don't have access to delete items.";
+             }
+             next;
+         }
+
+         # did anything even change, though?
+         my $oldtext = $dbr->selectrow_array("SELECT text FROM ml_text WHERE dmid=$dom AND txtid=$lat->{'txtid'}");
+         if ($oldtext eq $text && $lat->{'staleness'} == 2) {
+             push @errors, "Severity of source language change requires change in text for item '$itcode'";
+             next;
+         }
+
+         # keep old txtid if text didn't change.
+         my $opts = {};
+         if ($oldtext eq $text) {
+             $opts->{'txtid'} = $lat->{'txtid'};
+             $text = undef;
+             $sev = 0;
+         }
+
+         # if setting text for first time, push down to children langs
+         if ($lat->{'staleness'} == 4) {
+             $opts->{'childrenlatest'} = 1;
+         }
+
+         # severity of change:
+         $opts->{'changeseverity'} = $sev;
+
+         # set userid of writer
+         $opts->{'userid'} = $remote->{'userid'};
+
+         my ($res, $msg) = LJ::Lang::web_set_text($dom, $l->{'lncode'}, $itcode, $text, $opts);
+         if ($res) {
+             push @info, "OK: $itcode";
+             $saved = 1;
+
+             if ( $extra_checkboxes ) {
+                 # Not gonna bother to refactor to LJ::Lang as the whole
+                 # translation system will get thrown away and redone later.
+                 # FIXME: make sure my words don't come back to haunt me.
+                 $dbh->do( "UPDATE ml_items SET proofed = ?, updated = ? " .
+                           "WHERE dmid = ? AND itid = ?", undef, $proofed ? 1 : 0,
+                           $updated ? 1 : 0, $dom, $itid );
+
+                 if ( $dbh->err ) {
+                     push @errors, $dbh->errstr;
+                 } else {
+                     push @info, "OK: $itcode (flags)";
+                 }
+             }
+         } else {
+             push @errors, $msg;
+         }
+
+         push @info, LJ::Hooks::run_hook('trans_editpage_bml_postsave', $opts)
+             if LJ::Hooks::are_hooks('trans_editpage_bml_postsave');
+     }
+
+     $dbh ||= LJ::get_db_writer();
+     $dbh->do("UPDATE ml_langs SET lastupdate=NOW() WHERE lnid=$l->{'lnid'}") if $saved;
+
+     if (@errors) {
+         $ret .= "<b>ERRORS:</b><ul>";
+         foreach (@errors) { $ret .= "<li>$_</li>"; }
+         $ret .= "</ul>";
+     }
+     if (@info) {
+         $ret .= "<b>Results:</b><ul>";
+         foreach (@info) { $ret .= "<li>$_</li>"; }
+         $ret .= "</ul>";
+     }
+     if (! @errors && ! @info) {
+         $ret .= "<i>No errors & nothing saved.</i>";
+     }
+     return $ret;
+ }
+
+_code?>
+</body>
+</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/help-severity.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/help-severity.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,12 @@
+<h1>Description of severity levels:</h1>
+
+<table cellpadding='3'>
+<tr valign='top'><td><b>0</b></td><td>Translate is up-to-date</td></tr>
+<tr valign='top'><td><b>1</b></td><td>Parent language has changed a little.  Your translation might need updating.</td></tr>
+<tr valign='top'><td><b>2</b></td><td>Parent language has changed.  Your translation probably needs updating.</td></tr>
+<tr valign='top'><td><b>3</b></td><td>New text was added in parent language which you haven't yet translated.</td></tr>
+<tr valign='top'><td><b>4</b></td><td>Item code in use but no text exists yet for any language.</td></tr>
+</table>
+
+<h2>Searching</h2>
+When searching, you can search for a certain severity level (0, 1, 2, 3, 4) or search for everything at or above a certain severity level (0+, 1+, 2+, 3+).
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/index.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/index.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,78 @@
+<?page
+title=><?_ml .title _ml?>
+body<=
+
+<?_code
+{
+    use strict;
+    
+    my $dbr = LJ::get_db_reader();
+    my $sth;
+
+    LJ::set_active_crumb('translate');
+    
+    $sth = $dbr->prepare("SELECT lnid, lncode, lnname, lastupdate FROM ml_langs");
+    $sth->execute;
+    my %lang;
+    $lang{$_->{'lnid'}} = $_ while $_ = $sth->fetchrow_hashref;
+ 
+    $sth = $dbr->prepare("SELECT lnid, staleness > 1, COUNT(*) FROM ml_latest GROUP by 1, 2");
+    $sth->execute;
+    while (my ($lnid, $stale, $ct) = $sth->fetchrow_array) {
+        next unless exists $lang{$lnid};
+        $lang{$lnid}->{'_total'} += $ct;
+        $lang{$lnid}->{'_good'} += (1-$stale) * $ct;
+        $lang{$lnid}->{'percent'} = 100 * $lang{$lnid}->{'_good'} / ($lang{$lnid}->{'_total'}||1);
+    }
+
+    my $sortcol = exists $lang{'1'}->{$FORM{'s'}} ? $FORM{'s'} : "lnname";
+    my @cols = (['lncode', $ML{'.table.code'}],
+                ['lnname', $ML{'.table.langname'}, sub {
+                    my $r = shift;
+                    "<td><a href='edit?lang=$r->{'lncode'}'>$r->{'lnname'}</a></td>";
+                }],
+                ['percent', $ML{'.table.done'}, sub {
+                    my $r = shift;
+                    "<td align='right'><b>" .
+                    sprintf("%.02f%%", $r->{'percent'}) . "</b><br />" .
+                    "<font size='-1'>$r->{'_good'}/$r->{'_total'}</font>" .
+                    "</td>";
+                },
+                    sub {
+                        $b->{'percent'} <=> $a->{'percent'} || $b->{'_total'} <=> $a->{'_total'}
+                }],
+                ['lastupdate', $ML{'.table.lastupdate'}, undef, sub {
+                    $b->{'lastupdate'} cmp $a->{'lastupdate'}
+                }]);
+    my $ret;
+    my $sorter = sub { $a->{$sortcol} cmp $b->{$sortcol} };
+
+    $ret .= BML::ml('.text', {'aopts' => "href='$LJ::SITEROOT/admin/translate/teams'"});
+
+    $ret .= "<p><table border='1' cellspacing='1' cellpadding='3'><tr>";
+    foreach (@cols) {
+        if ($sortcol eq $_->[0]) {
+            $ret .= "<td><b>$_->[1]</b></td>";
+        } else {
+            $ret .= "<td><b><a href=\"./?s=$_->[0]\">$_->[1]</a></b></td>";
+        }
+        if ($_->[0] eq $sortcol && $_->[3]) { $sorter = $_->[3]; }
+    }
+    $ret .= "</tr>\n";
+
+    foreach my $r (sort $sorter values %lang) {
+        $ret .= "<tr>";
+        foreach (@cols) {
+            $ret .= $_->[2] ? $_->[2]->($r) : "<td>$r->{$_->[0]}</td>";
+        }
+        $ret .= "</tr>\n";
+    }
+
+    $ret .= "</table>\n";
+    
+    return $ret;
+}
+_code?>
+
+<=body
+page?>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/index.bml.text
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/index.bml.text	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,13 @@
+;; -*- coding: utf-8 -*-
+.table.code=Code
+
+.table.done=% Done
+
+.table.langname=Language Name
+
+.table.lastupdate=Last Update
+
+.text=The following table lists the progress by each of the different <a [[aopts]]>translation teams</a>.
+
+.title=Translation Area
+
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/search.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/search.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,100 @@
+<?_code
+{
+    my $lang = $FORM{'lang'};
+    my $l = LJ::Lang::get_lang($lang);
+    return "<b>Invalid language</b>" unless $l;
+
+    my $dbr = LJ::get_db_reader();
+    my $sth;
+
+    my $sql;
+
+    # all queries use the visible flag
+    my $vis_flag = '';
+    $vis_flag = 'AND i.visible = 1' unless $LJ::IS_DEV_SERVER;
+
+    if ($FORM{'search'} eq 'sev')
+    {
+        my $what = ">= 1";
+        if ($FORM{'stale'} =~ /^(\d+)(\+?)$/) {
+            $what = ($2 ? ">=" : "=") . $1;
+        }
+        $sql = qq(
+            SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l
+            WHERE l.lnid=$l->{'lnid'} AND l.staleness $what AND l.dmid=i.dmid AND l.itid=i.itid $vis_flag
+            ORDER BY i.dmid, i.itcode
+        );
+    }
+
+    if ($FORM{'search'} eq 'txt')
+    {
+        my $remote = LJ::get_remote();
+        return "This search type is restricted to $l->{'lnname'} translators." unless
+            $remote && ( $remote->has_priv( "translate", $l->{'lncode'} ) ||
+                         $remote->has_priv( "faqedit", "*" ) ); # FAQ admins can search too
+
+        my $qtext = $dbr->quote($FORM{'searchtext'});
+        my $dmid = $FORM{'searchdomain'}+0;
+        my $dmidwhere = $dmid ? "AND i.dmid=$dmid" : "";
+        if ($FORM{'searchwhat'} eq "code") {
+            $sql = qq{
+                SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l
+                WHERE l.lnid=$l->{'lnid'} AND l.dmid=i.dmid AND i.itid=l.itid $vis_flag
+                $dmidwhere AND LOCATE($qtext, i.itcode)
+            };
+        } else {
+            my $lnid = $l->{'lnid'};
+            if ($FORM{'searchwhat'} eq "parent") { $lnid = $l->{'parentlnid'}; }
+            $sql = qq{
+                SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l, ml_text t
+                WHERE l.lnid=$lnid AND l.dmid=i.dmid AND i.itid=l.itid
+                $dmidwhere AND t.dmid=l.dmid AND t.txtid=l.txtid AND LOCATE($qtext, t.text) $vis_flag
+                ORDER BY i.itcode
+            };
+        }
+    }
+
+    if ($FORM{'search'} eq 'flg') {
+        return "This type of search isn't available for this language."
+            unless $l->{'lncode'} eq $LJ::DEFAULT_LANG || !$l->{'parentlnid'};
+
+        my $whereflags = join ' AND ',
+            map { $FORM{"searchflag$_"} eq 'yes' ? "$_ = 1" : "$_ = 0" }
+                grep { $FORM{"searchflag$_"} ne 'whatev' } qw(proofed updated);
+        $whereflags = "AND $whereflags"
+            if $whereflags ne '';
+        $sql = qq(
+            SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l
+            WHERE l.lnid=$l->{lnid} AND l.dmid=i.dmid AND l.itid=i.itid $whereflags $vis_flag
+            ORDER BY i.dmid, i.itcode
+        );
+    }
+
+    return "Bogus or unimplemented query type." unless $sql;
+
+    my $ret;
+    $sth = $dbr->prepare($sql);
+    $sth->execute;
+    my $page = 0;
+    my @page = ();
+    my $addlink = sub {
+        return unless @page;
+        $page++;
+        my $link = "editpage?lang=$lang&amp;items=" . LJ::eurl(join(",",map{"$_->[0]:$_->[1]"}@page));
+        $ret .= "<b><a target='main' href='$link'>Page $page</a></b><br /><span style='font-size:8pt'>\n";
+        $ret .= "$page[0]->[2]<br />\n";
+        $ret .= "$page[-1]->[2]<br /></span>\n";
+        @page = ();
+    };
+    while (my ($dmid, $itid, $itcode) = $sth->fetchrow_array) {
+        push @page, [ $dmid, $itid, $itcode ];
+        $addlink->() if @page >= 10;
+    }
+    $addlink->();
+
+    if ($page == 0) { $ret .= "<i>(No matches)</i>"; }
+
+    return $ret;
+
+}
+_code?>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/searchform.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/searchform.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,80 @@
+<html>
+<head><title>Search Form</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body marginwidth='0' marginheight='0'>
+
+<form target='res' action='search' method='get'>
+<input type='hidden' name='lang' value='<?_code $FORM{'lang'} _code?>'>
+<input type='hidden' name='search' value='sev'>
+
+[<a href="./" target='_top'>&lt;-- Back</a>]
+<?_code
+ my $lang = $FORM{'lang'};
+ my $l = LJ::Lang::get_lang($lang);
+ BML::finish() unless $l;
+ return "<b>" . ($l ? $l->{'lnname'} : "Invalid language") . "</b>";
+_code?>
+
+<p>By Severity: (<a href='help-severity' target='main'>help</a>)<br /><select name='stale'>
+<option value="0">0</option>
+<option value="0+">0+</option>
+<option value="1">1</option>
+<option value="1+" selected='selected'>1+</option>
+<option value="2">2</option>
+<option value="2+">2+</option>
+<option value="3">3</option>
+<option value="3+">3+</option>
+<option value="4">4</option>
+</select><input type='submit' value='Search'/>
+</p>
+</form>
+
+<form target='res' action='search' method='get'>
+<input type='hidden' name='lang' value='<?_code $FORM{'lang'} _code?>'>
+<input type='hidden' name='search' value='txt'>
+
+<p>Search
+<?_code
+ my $ret;
+ my $l = LJ::Lang::get_lang($FORM{'lang'});
+ my $pl = LJ::Lang::get_lang_id($l->{'parentlnid'});
+ my @opt = ("src" => $l->{'lnname'});
+ if ($pl) { push @opt, "parent", $pl->{'lnname'} };
+ push @opt, "code", "Item Code";
+ $ret .= LJ::html_select({ 'name' => 'searchwhat' },
+                         @opt);
+ $ret .= "<br />Area: ";
+ $ret .= LJ::html_select({ 'name' => 'searchdomain' },
+                         0, "(all)",
+                         map { $_->{'dmid'}, $_->{'uniq'} }
+                         sort { $a->{'dmid'} <=> $b->{'dmid'} } LJ::Lang::get_domains());
+ return $ret;
+_code?>
+    <br />Text: <input name='searchtext' size='15'><input type='submit' value='Search'>
+</p>
+</form>
+
+<?_code
+ my $l = LJ::Lang::get_lang($FORM{'lang'});
+ return '' unless $l->{'lncode'} eq $LJ::DEFAULT_LANG || !$l->{'parentlnid'};
+
+ my $ret = <<HTML;
+<form target='res' action='search' method='get'>
+<input type='hidden' name='lang' value='$l->{lncode}'>
+<input type='hidden' name='search' value='flg'>
+<p><table><tr><td>Prf:</td>
+<td><input type='radio' name='searchflagproofed' value='whatev'>Both</td>
+<td><input type='radio' name='searchflagproofed' value='yes'>Yes</td>
+<td><input type='radio' name='searchflagproofed' value='no'>No</td></tr>
+<tr><td>Upd:</td>
+<td><input type='radio' name='searchflagupdated' value='whatev'>Both</td>
+<td><input type='radio' name='searchflagupdated' value='yes'>Yes</td>
+<td><input type='radio' name='searchflagupdated' value='no'>No</td></tr></table>
+<input type='submit' value='Search'></p></form>
+HTML
+ return $ret;
+_code?>
+
+</body>
+</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/teams.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/teams.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,63 @@
+<?page
+title=><?_ml .title _ml?>
+body<=
+<?_code
+{
+    use strict;
+
+    my $dbr = LJ::get_db_reader();
+    my ($ret, $sth);
+
+    LJ::set_active_crumb('translateteams');
+
+    $ret .= "<?h1 $ML{'.teams.header'} h1?>";
+    $ret .= "<?p $ML{'.teams.text'} p?>";
+
+    # get langs
+    $sth = $dbr->prepare("SELECT lnid, lncode, lnname, lastupdate FROM ml_langs");
+    $sth->execute;
+    my %lang;
+    $lang{$_->{'lnid'}} = $_ while $_ = $sth->fetchrow_hashref;
+
+    # get each lang's community
+    $sth = $dbr->prepare("SELECT l.lnid, t.text ".
+                        "FROM ml_latest l, ml_items i, ml_text t ".
+                        "WHERE l.dmid=1 AND t.dmid=1 AND i.dmid=1 AND i.itcode='thislang.community' ".
+                        "AND l.itid=i.itid AND t.txtid=l.txtid AND t.lnid=l.lnid");
+    $sth->execute;
+    while ($_ = $sth->fetchrow_hashref) {
+        next unless exists $lang{$_->{'lnid'}};
+        $lang{$_->{'lnid'}}->{'community'} = $_->{'text'};
+    }
+
+    # get people with privs
+    $sth = $dbr->prepare("SELECT pm.arg, u.user FROM useridmap u, priv_list pl, priv_map pm ".
+                        "WHERE pm.userid=u.userid AND pm.prlid=pl.prlid AND pl.privcode='translate'");
+    $sth->execute;
+    my %team;
+    while (my ($arg, $user) = $sth->fetchrow_array) {
+        push @{$team{$arg}}, $user;
+    }
+
+    $ret .= "<p><table cellpadding='5' border='1'>";
+    $ret .= "<tr><th>$ML{'.table.language'}</th><th>$ML{'.table.community'}</th><th>$ML{'.table.users'}</th></tr>";
+
+    foreach my $l (sort { $a->{'lnname'} cmp $b->{'lnname'} } values %lang) {
+        $ret .= "<tr valign='top' align='left'><td><b>$l->{'lnname'}</b></td>";
+        $ret .= "<td>";
+        $ret .= "<?ljcomm $l->{'community'} ljcomm?>" if $l->{'community'};
+        $ret .= "</td><td>";
+        if ($team{$l->{'lncode'}}) {
+            $ret .= join(", ", map { LJ::ljuser($_) }
+            sort @{$team{$l->{'lncode'}}});
+        }
+        $ret .= "</td></tr>\n";
+    }
+
+    $ret .= "</table>";
+    return $ret;
+}
+_code?>
+
+<=body
+page?>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/teams.bml.text
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/teams.bml.text	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,13 @@
+;; -*- coding: utf-8 -*-
+.table.community=Community
+
+.table.language=Language
+
+.table.users=Users With Privs
+
+.teams.header=Teams
+
+.teams.text=Translation is being done by the following teams:
+
+.title=Translation Teams
+
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/admin/translate/welcome.bml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/htdocs/admin/translate/welcome.bml	Tue Feb 16 15:26:10 2010 +0000
@@ -0,0 +1,7 @@
+Welcome to the translation area.
+
+<p>In the top-left frame you search for phrases to translate.
+
+<p>The lower-left frame shows your search result links, paginated.
+
+<p>This large frame is the work area, in which text is edited.
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/diff.bml
--- a/htdocs/translate/diff.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<style type="text/css">
-del {
-    text-decoration: none;
-    color: #ff0000;
-    background-color: #ffd0d0;
-}
-ins {
-    text-decoration: none;
-    color: #002000;
-    background-color: #20ff20;
-}
-</style>
-</head>
-<body>
-<?_code
-{
-    use strict;
-    use vars qw(%GET);
-    use File::Temp qw/tempfile/;
-    
-    BML::set_content_type("text/html; charset=utf-8");
-    
-    my $lang = $GET{'lang'};
-    my $l = LJ::Lang::get_lang($lang);
-    return "<b>Invalid language</b>" unless $l;
-
-    return "<b>Invalid item</b>" unless $GET{'it'} =~ /^(\d+):(\d+)$/;
-    my ($dmid, $itid) = ($1, $2);
-    
-    my @lnids = $l->{'lnid'};
-    {
-        my $il = $l;
-        while ($il && $il->{'parentlnid'}) {
-            push @lnids, $il->{'parentlnid'};
-            $il = LJ::Lang::get_lang_id($il->{'parentlnid'});
-        }
-    }
-    my $lnids = join(",", @lnids);
-
-    my $dbr = LJ::get_db_reader();
-    my ($sth, $ret);
-
-    my $sth = $dbr->prepare("select * from ml_text where dmid=$dmid and itid=$itid and lnid in ($lnids) ORDER BY txtid");
-    $sth->execute;
-    my @tlist;
-    while (my $t = $sth->fetchrow_hashref) { 
-        next if @tlist && $t->{'text'} eq $tlist[-1]->{'text'};
-        push @tlist, $t; 
-    }
-
-    my $changes = scalar @tlist - 1;
-    return "<b>No changes</b>" unless $changes;
-
-    my $view_change = $GET{'change'} || $changes;
-    return "bogus change" if $view_change < 1 || $view_change > $changes;
-    for (1..$changes) {
-        if ($_ eq $view_change) {
-            $ret .= "<b>[Change $_]</b>\n";
-        } else {
-            $ret .= "<a href='diff?lang=$lang&it=$GET{'it'}&change=$_'>[Change $_]</a>\n";
-        }
-    }
-    $ret .= "<hr>";
-    my $was = $tlist[$view_change-1]->{'text'};
-    my $then = $tlist[$view_change]->{'text'};
-
-    my ($was_alt, $then_alt) = ($was, $then);
-    foreach (\$was_alt, \$then_alt) {
-        $$_ =~ s/\n/*NEWLINE*/g;
-        $$_ =~ s/\s+/\1\n/g;
-        $$_ .= "\n";
-    }
-
-    my ($was_file, $then_file, $fh);
-    my $tries = 0;
-
-    ($fh, $was_file) = tempfile();
-    print $fh $was_alt; close $fh;
-    ($fh, $then_file) = tempfile();
-    print $fh $then_alt; close $fh;
-
-    my @words = split(/\n/, $was_alt);
-    my $diff = `diff -u $was_file $then_file`;
-
-    my $pos = 0;
-    my $mode;
-    my $setmode = sub {
-        my $newmode = shift;
-        return " " if $newmode eq $mode;
-        my $ret;
-        $ret .= "</$mode>" if $mode;
-        $ret .= " ";
-        $ret .= "<$newmode>" if $newmode;
-        $mode = $newmode;
-        return $ret;
-    };
-
-    foreach my $dl (split(/\n/, $diff)) {
-        next if $dl =~ /^(\+\+\+|\-\-\-)/;
-        if ($dl =~ /^\@\@ \-(\d+),(\d+)/) {
-            my $newpos = $1;
-            $ret .= $setmode->("");
-            for (my $i=$pos+1; $i<$newpos; $i++) {
-                my $word = LJ::ehtml($words[$i-1]);
-                $word =~ s/\*NEWLINE\*/<br>\n/g;
-                $ret .= "$word ";
-                $pos++;
-            }
-            next;
-        }
-        if ($dl =~ /^ /) {
-            $pos++;
-            my $word = LJ::ehtml($words[$pos-1]);
-            $word =~ s/\*NEWLINE\*/<br>\n/g;
-            $ret .= $setmode->("") . $word;
-        }
-        if ($dl =~ /^\-/) {
-            $pos++;
-            my $word = LJ::ehtml($words[$pos-1]);
-            $word =~ s/\*NEWLINE\*/<br>\n/g;  
-            $ret .= $setmode->("del") . $word;
-        }
-        if ($dl =~ /^\+(.*)/) {
-            my $word = LJ::ehtml($1);
-            $word =~ s/\*NEWLINE\*/<br>\n/g;
-            $ret .= $setmode->("ins") . $word;
-        }
-    }
-
-    $ret .= $setmode->("");
-    while ($pos < @words) {
-        my $word = LJ::ehtml($words[$pos]);
-        $word =~ s/\*NEWLINE\*/<br>\n/g;
-        $ret .= "$word ";
-        $pos++;
-    }
-
-    $was = LJ::eall($was);
-    $was =~ s/\n( *)/"<br \/>" . "&nbsp;"x length($1)/eg;
-    $then = LJ::eall($then);
-    $then =~ s/\n( *)/"<br \/>" . "&nbsp;"x length($1)/eg;
-    
-    $ret .= "<p><table width='100%' border='1'><tr valign='top'><td width='50%'><b>Before:</b><br>$was</td>";
-    $ret .= "<td width='50%'><b>After:</b><br>$then</td></tr></table>";
-
-    unlink($was_file, $then_file);
-
-    return $ret;
-
-}
-_code?>
-</body>
-</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/edit.bml
--- a/htdocs/translate/edit.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-<html>
-<head>
- <title>Language Editor</title>
-</head>
-
-<frameset cols="200,*">
-  <frameset rows="230,*">
-    <frame name="search" src="searchform?lang=<?_code return $FORM{'lang'}; _code?>">
-    <frame name="res" src="search?lang=<?_code return $FORM{'lang'}; _code?>&amp;stale=1%2B&amp;search=sev">
-  </frameset>
-  <frame name="main" src="welcome">
-</frameset>
-
-</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/editpage.bml
--- a/htdocs/translate/editpage.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,363 +0,0 @@
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-<?_code
-{
-    LJ::Hooks::run_hook('trans_editpage_bml_postsave_begin');
-    return LJ::res_includes();
-}
- _code?>
-</head>
-<body>
-<?_code
- use strict;
- use vars qw(%FORM);
-
- BML::set_content_type("text/html; charset=utf-8");
-
- my $lang = $FORM{'lang'};
- my $l = LJ::Lang::get_lang($lang);
- return "<b>Invalid language</b>" unless $l;
- my $lp = $l->{'parentlnid'} ? LJ::Lang::get_lang_id($l->{'parentlnid'}) : undef;
-
- my $dbr = LJ::get_db_reader();
- my $dbh;
- my ($sth, $ret);
-
- my $remote = LJ::get_remote();
- my $can_edit   = $remote && $remote->has_priv( "translate", $l->{'lncode'} );
- my $can_delete = $remote && $remote->has_priv( "translate", "[itemdelete]" );
- my $can_rename = $remote && $remote->has_priv( "translate", "[itemrename]" );
-
- # Extra checkboxes for default language and root language (DW: en_DW and en)
- my $extra_checkboxes = $l->{'lncode'} eq $LJ::DEFAULT_LANG || !defined $lp;
-
- my $mode = {
-     '' => 'view',
-     'save' => 'save',
- }->{$FORM{'mode'}};
- return "bogus mode" unless $mode;
-
- my $MAX_EDIT = 100;
-
- if ($mode eq "view")
- {
-     my @load;
-     foreach (split /,/, $FORM{'items'})
-     {
-         next unless /^(\d+):(\d+)$/;
-         last if @load >= $MAX_EDIT;
-         push @load, { 'dmid' => $1, 'itid'=> $2 };
-     }
-
-     return "Nothing to show." unless @load;
-
-     $ret .= "<form method='post' action='editpage'>";
-     $ret .= LJ::html_hidden('lang', $lang,
-                             'mode', 'save');
-
-     # load item info
-     my %ml_items;
-     my $itwhere = join(" OR ", map { "(dmid=$_->{'dmid'} AND itid=$_->{'itid'})" } @load);
-     $sth = $dbr->prepare("SELECT dmid, itid, itcode, proofed, updated, notes FROM ml_items WHERE $itwhere");
-     $sth->execute;
-     while (my ($dmid, $itid, $itcode, $proofed, $updated, $notes) = $sth->fetchrow_array) {
-         $ml_items{"$dmid-$itid"} = { 'itcode' => $itcode, 'proofed' => $proofed, 'updated' => $updated, 'notes' => $notes };
-     }
-
-     # getting latest mappings for this lang and parent
-     my %ml_text;
-     my %ml_latest;
-     $sth = $dbr->prepare("SELECT lnid, dmid, itid, txtid, chgtime, staleness FROM ml_latest ".
-                          "WHERE ($itwhere) AND lnid IN ($l->{'lnid'}, $l->{'parentlnid'})");
-     $sth->execute;
-     return $dbr->errstr if $dbr->err;
-     while ($_ = $sth->fetchrow_hashref) {
-         $ml_latest{"$_->{'dmid'}-$_->{'itid'}"}->{$_->{'lnid'}} = $_;
-         $ml_text{"$_->{'dmid'}-$_->{'txtid'}"} = undef;  # mark to load later
-     }
-
-     # load text
-     $sth = $dbr->prepare("SELECT dmid, txtid, lnid, itid, text FROM ml_text ".
-                          "WHERE " . join(" OR ",
-                                          map { "(dmid=$_->[0] AND txtid=$_->[1])" }
-                                          map { [ split(/-/, $_) ] } keys %ml_text));
-     $sth->execute;
-     while ($_ = $sth->fetchrow_hashref) {
-         $ml_text{"$_->{'dmid'}-$_->{'txtid'}"} = $_;
-     }
-
-     if ($can_delete) {
-         $ret .= "<p style='font-size:9pt'><b>To delete an item:</b> edit text to be \"XXDELXX\"</p>";
-     }
-
-     # show all editing items
-     my $ict = 0;
-     foreach my $i (@load)
-     {
-         my ($dmid, $itid) = ($i->{'dmid'}, $i->{'itid'});
-         my $ituq = "$dmid-$itid";
-         my $it = $ml_items{$ituq};
-         my $lat = $ml_latest{$ituq}->{$l->{'lnid'}};
-         next unless $it and $lat;
-         $ict++;
-
-         my $plat;
-         if ($lp && defined $ml_latest{$ituq}->{$lp->{'lnid'}}) {
-             $plat = $ml_latest{$ituq}->{$lp->{'lnid'}};
-         }
-
-         $ret .= LJ::html_hidden("dom_$ict", $dmid,
-                                 "itid_$ict", $itid,
-                                 "oldtxtid_$ict", $lat->{'txtid'},
-                                 "oldptxtid_$ict", $plat ? $plat->{'txtid'} : 0,
-                                 );
-
-         # top bar
-         $ret .= "<table bgcolor='#c0c0c0' width='100%'><tr><td><b>Code:</b> ";
-         if ($dmid != 1) {
-             my $d = LJ::Lang::get_dom_id($dmid);
-             $ret .= "[$d->{'uniq'}] ";
-         }
-
-         my $difflink;
-         if ($lat->{'staleness'}) {
-             $difflink = "($plat->{'chgtime'}, <a target='_new' href='diff?it=$i->{'dmid'}:$i->{'itid'}&lang=$lp->{'lncode'}'>diff</a>)";
-         }
-
-         $ret .= "$it->{'itcode'} $difflink</td>";
-         $ret .= "<td align='right'><b><a target='_new' href='help-severity'>Sev</a>:</b> $lat->{'staleness'}</td>";
-         $ret .= "</tr></table>";
-
-         $ret .= "<dl>";
-         if ($it->{'notes'}) {
-             my $notes = $it->{'notes'};
-             $notes =~ s!\n!<br />!g;
-             $ret .= "<dt><b>Notes:</b></dt><dd>$notes</dd>";
-         }
-
-         my $show_edit = 0;
-         my $use_textarea = 0;
-
-         if ($plat) {
-             $ret .= "<dt><b>$lp->{'lnname'}:</b></dt>";
-             my $t = $ml_text{"$plat->{'dmid'}-$plat->{'txtid'}"}->{'text'};
-             if ($t =~ /\n/) { $use_textarea = 1; }
-             if (length($t) > 255) { $use_textarea = 1; }
-             $t = LJ::eall($t);
-             $t =~ s/\n( *)/"<br \/>" . "&nbsp;"x length($1)/eg;
-             $ret .= "<dd>$t</dd>";
-         }
-
-         my $curtext = LJ::eall($ml_text{"$lat->{'dmid'}-$lat->{'txtid'}"}->{'text'});
-         if ($curtext =~ /\n/) { $use_textarea = 1; }
-         if (length($curtext) > 255) { $use_textarea = 1; }
-         if ($lat->{'staleness'} >= 3) {
-             # if wrong language, why populate it with stuff they'll just have to delete?
-             $curtext = "";
-         }
-
-         $ret .= "<dt><b>$l->{'lnname'}</b>:</b></dt><dd>";
-         my $disabled = "disabled='disabled'";
-         if ($lat->{'staleness'} >= 3) {
-             $disabled = "";
-             # when something's this stale, assume both it's being
-             # edited and that the severity is major (going from wrong
-             # language to right language is a major change, afterall)
-             $ret .= LJ::html_hidden("ed_$ict", "1",
-                                     "sev_$ict", "2",
-                                     );
-         } else {
-             my $js = "a=document.getElementById(\"newtext_$ict\"); a.disabled=!this.checked; if (this.checked) a.focus();";
-             $js .= "a=document.getElementById(\"pr_$ict\"); a.disabled=!this.checked; a=document.getElementById(\"up_$ict\"); a.disabled=!this.checked;"
-                 if $extra_checkboxes;
-             $ret .= "<input name='ed_$ict' type='checkbox' value='1' id='ed_$ict' onClick='$js' /><label for='ed_$ict'>Edit Text</label>";
-             if ($l->{'children'} && @{$l->{'children'}}) {
-                 $ret .= " Severity: ";
-                 $ret .= LJ::html_select({ 'name' => "sev_$ict", "selected" => 1 },
-                                         0 => "Typo/etc (no notify)",
-                                         1 => "Minor (notify translators)",
-                                         2 => "Major (require translation updates)");
-             }
-             $ret .= "<br />" unless $extra_checkboxes;
-         }
-
-         if ( $extra_checkboxes ) {
-             $ret .= " ";
-             $ret .= LJ::html_check( { type => 'checkbox', label => 'Proofed',
-                                       selected => $it->{proofed}, value => 1,
-                                       name => "pr_$ict", id => "pr_$ict",
-                                       disabled => $disabled eq '' ? 0 : 1 } );
-             $ret .= " ";
-             $ret .= LJ::html_check( { type => 'checkbox', label => 'Updated',
-                                       selected => $it->{updated}, value => 1,
-                                       name => "up_$ict", id => "up_$ict",
-                                       disabled => $disabled eq '' ? 0 : 1 } );
-             $ret .= "<br />";
-         }
-
-         if ($use_textarea) {
-             $ret .= "<textarea name='newtext_$ict' id='newtext_$ict' $disabled wrap='soft' rows='10' cols='60'>$curtext</textarea>";
-         } else {
-             $ret .= "<input name='newtext_$ict' id='newtext_$ict' $disabled size='60' value=\"$curtext\"/>";
-         }
-         $ret .= "</dd>\n";
-         $ret .= "</dl>";
-     }
-
-     if ($ict) {
-         $ret .= LJ::html_hidden("ict", $ict);
-         my $disabled = $can_edit ? "" : "disabled='disabled'";
-         $ret .= "<table width='100%' bgcolor='#e0e0e0'><tr><td align='center'><input type='submit' $disabled value='Save' /></td></tr></table>";
-     } else {
-         $ret .= "No items to show.  (since been deleted, perhaps?)";
-     }
-     $ret .= "</form>";
-
-     return $ret;
- }
-
- if ($mode eq "save")
- {
-     my $num = $FORM{'ict'}+0;
-     $num = $MAX_EDIT if $num > $MAX_EDIT;
-
-     my (@errors, @info);
-     unless ($can_edit) {
-         push @errors, "You don't have access to edit text for this language.";
-         $num = 0;
-     }
-
-     unless (LJ::text_in(\%FORM)) {
-         push @errors, "You seem to have changed your browser's encoding to something other than UTF-8.  It needs to be in UTF-8.";
-         push @errors, "Nothing saved.";
-         $num = 0;
-     }
-
-     my $saved = 0;  # do any saves?
-
-     for (my $i=1; $i<=$num; $i++)
-     {
-         next unless $FORM{"ed_$i"};
-         my ($dom, $itid, $oldtxtid, $oldptxtid, $sev, $proofed, $updated) =
-             map { int($FORM{"${_}_$i"}+0) }
-                 qw(dom itid oldtxtid oldptxtid sev pr up);
-
-         my $itcode = $dbr->selectrow_array("SELECT itcode FROM ml_items WHERE dmid=$dom AND itid=$itid");
-         unless (defined $itcode) {
-             push @errors, "Bogus dmid/itid: $dom/$itid";
-             next;
-         }
-
-         $dbh ||= LJ::get_db_writer();
-         my $lat = $dbh->selectrow_hashref("SELECT * FROM ml_latest WHERE lnid=$l->{'lnid'} AND dmid=$dom AND itid=$itid");
-         unless ($lat) {
-             push @errors, "No existing mapping for $itcode";
-             next;
-         }
-         unless ($lat->{'txtid'} == $oldtxtid) {
-             push @errors, "Another translator updated '$itcode' before you saved, so your edit has been ignored.";
-             next;
-         }
-
-         my $plat;
-         if ($lp) {
-             $plat = $dbh->selectrow_hashref("SELECT * FROM ml_latest WHERE lnid=$lp->{'lnid'} ".
-                                             "AND dmid=$dom AND itid=$itid");
-             my $ptid = $plat ? $plat->{'txtid'} : 0;
-             unless ($ptid == $oldptxtid) {
-                 push @errors, "The source text of item '$itcode' changed while you were editing, so your edit has been ignored.";
-                 next;
-             }
-         }
-
-         # did they type anything?
-         my $text = $FORM{"newtext_$i"};
-         next unless $text =~ /\S/;
-
-         # delete
-         if ($text eq "XXDELXX") {
-             if ($can_delete) {
-                 $dbh->do("DELETE FROM ml_latest WHERE dmid=$dom AND itid=$itid");
-                 push @info, "Deleted: '$itcode'";
-             } else {
-                 push @errors, "You don't have access to delete items.";
-             }
-             next;
-         }
-
-         # did anything even change, though?
-         my $oldtext = $dbr->selectrow_array("SELECT text FROM ml_text WHERE dmid=$dom AND txtid=$lat->{'txtid'}");
-         if ($oldtext eq $text && $lat->{'staleness'} == 2) {
-             push @errors, "Severity of source language change requires change in text for item '$itcode'";
-             next;
-         }
-
-         # keep old txtid if text didn't change.
-         my $opts = {};
-         if ($oldtext eq $text) {
-             $opts->{'txtid'} = $lat->{'txtid'};
-             $text = undef;
-             $sev = 0;
-         }
-
-         # if setting text for first time, push down to children langs
-         if ($lat->{'staleness'} == 4) {
-             $opts->{'childrenlatest'} = 1;
-         }
-
-         # severity of change:
-         $opts->{'changeseverity'} = $sev;
-
-         # set userid of writer
-         $opts->{'userid'} = $remote->{'userid'};
-
-         my ($res, $msg) = LJ::Lang::web_set_text($dom, $l->{'lncode'}, $itcode, $text, $opts);
-         if ($res) {
-             push @info, "OK: $itcode";
-             $saved = 1;
-
-             if ( $extra_checkboxes ) {
-                 # Not gonna bother to refactor to LJ::Lang as the whole
-                 # translation system will get thrown away and redone later.
-                 # FIXME: make sure my words don't come back to haunt me.
-                 $dbh->do( "UPDATE ml_items SET proofed = ?, updated = ? " .
-                           "WHERE dmid = ? AND itid = ?", undef, $proofed ? 1 : 0,
-                           $updated ? 1 : 0, $dom, $itid );
-
-                 if ( $dbh->err ) {
-                     push @errors, $dbh->errstr;
-                 } else {
-                     push @info, "OK: $itcode (flags)";
-                 }
-             }
-         } else {
-             push @errors, $msg;
-         }
-
-         push @info, LJ::Hooks::run_hook('trans_editpage_bml_postsave', $opts)
-             if LJ::Hooks::are_hooks('trans_editpage_bml_postsave');
-     }
-
-     $dbh ||= LJ::get_db_writer();
-     $dbh->do("UPDATE ml_langs SET lastupdate=NOW() WHERE lnid=$l->{'lnid'}") if $saved;
-
-     if (@errors) {
-         $ret .= "<b>ERRORS:</b><ul>";
-         foreach (@errors) { $ret .= "<li>$_</li>"; }
-         $ret .= "</ul>";
-     }
-     if (@info) {
-         $ret .= "<b>Results:</b><ul>";
-         foreach (@info) { $ret .= "<li>$_</li>"; }
-         $ret .= "</ul>";
-     }
-     if (! @errors && ! @info) {
-         $ret .= "<i>No errors & nothing saved.</i>";
-     }
-     return $ret;
- }
-
-_code?>
-</body>
-</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/help-severity.bml
--- a/htdocs/translate/help-severity.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-<h1>Description of severity levels:</h1>
-
-<table cellpadding='3'>
-<tr valign='top'><td><b>0</b></td><td>Translate is up-to-date</td></tr>
-<tr valign='top'><td><b>1</b></td><td>Parent language has changed a little.  Your translation might need updating.</td></tr>
-<tr valign='top'><td><b>2</b></td><td>Parent language has changed.  Your translation probably needs updating.</td></tr>
-<tr valign='top'><td><b>3</b></td><td>New text was added in parent language which you haven't yet translated.</td></tr>
-<tr valign='top'><td><b>4</b></td><td>Item code in use but no text exists yet for any language.</td></tr>
-</table>
-
-<h2>Searching</h2>
-When searching, you can search for a certain severity level (0, 1, 2, 3, 4) or search for everything at or above a certain severity level (0+, 1+, 2+, 3+).
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/index.bml
--- a/htdocs/translate/index.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-<?page
-title=><?_ml .title _ml?>
-body<=
-
-<?_code
-{
-    use strict;
-    
-    my $dbr = LJ::get_db_reader();
-    my $sth;
-
-    LJ::set_active_crumb('translate');
-    
-    $sth = $dbr->prepare("SELECT lnid, lncode, lnname, lastupdate FROM ml_langs");
-    $sth->execute;
-    my %lang;
-    $lang{$_->{'lnid'}} = $_ while $_ = $sth->fetchrow_hashref;
- 
-    $sth = $dbr->prepare("SELECT lnid, staleness > 1, COUNT(*) FROM ml_latest GROUP by 1, 2");
-    $sth->execute;
-    while (my ($lnid, $stale, $ct) = $sth->fetchrow_array) {
-        next unless exists $lang{$lnid};
-        $lang{$lnid}->{'_total'} += $ct;
-        $lang{$lnid}->{'_good'} += (1-$stale) * $ct;
-        $lang{$lnid}->{'percent'} = 100 * $lang{$lnid}->{'_good'} / ($lang{$lnid}->{'_total'}||1);
-    }
-
-    my $sortcol = exists $lang{'1'}->{$FORM{'s'}} ? $FORM{'s'} : "lnname";
-    my @cols = (['lncode', $ML{'.table.code'}],
-                ['lnname', $ML{'.table.langname'}, sub {
-                    my $r = shift;
-                    "<td><a href='edit?lang=$r->{'lncode'}'>$r->{'lnname'}</a></td>";
-                }],
-                ['percent', $ML{'.table.done'}, sub {
-                    my $r = shift;
-                    "<td align='right'><b>" .
-                    sprintf("%.02f%%", $r->{'percent'}) . "</b><br />" .
-                    "<font size='-1'>$r->{'_good'}/$r->{'_total'}</font>" .
-                    "</td>";
-                },
-                    sub {
-                        $b->{'percent'} <=> $a->{'percent'} || $b->{'_total'} <=> $a->{'_total'}
-                }],
-                ['lastupdate', $ML{'.table.lastupdate'}, undef, sub {
-                    $b->{'lastupdate'} cmp $a->{'lastupdate'}
-                }]);
-    my $ret;
-    my $sorter = sub { $a->{$sortcol} cmp $b->{$sortcol} };
-
-    $ret .= BML::ml('.text', {'aopts' => "href='$LJ::SITEROOT/translate/teams'"});
-
-    $ret .= "<p><table border='1' cellspacing='1' cellpadding='3'><tr>";
-    foreach (@cols) {
-        if ($sortcol eq $_->[0]) {
-            $ret .= "<td><b>$_->[1]</b></td>";
-        } else {
-            $ret .= "<td><b><a href=\"./?s=$_->[0]\">$_->[1]</a></b></td>";
-        }
-        if ($_->[0] eq $sortcol && $_->[3]) { $sorter = $_->[3]; }
-    }
-    $ret .= "</tr>\n";
-
-    foreach my $r (sort $sorter values %lang) {
-        $ret .= "<tr>";
-        foreach (@cols) {
-            $ret .= $_->[2] ? $_->[2]->($r) : "<td>$r->{$_->[0]}</td>";
-        }
-        $ret .= "</tr>\n";
-    }
-
-    $ret .= "</table>\n";
-    
-    return $ret;
-}
-_code?>
-
-<=body
-page?>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/index.bml.text
--- a/htdocs/translate/index.bml.text	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-;; -*- coding: utf-8 -*-
-.table.code=Code
-
-.table.done=% Done
-
-.table.langname=Language Name
-
-.table.lastupdate=Last Update
-
-.text=The following table lists the progress by each of the different <a [[aopts]]>translation teams</a>.
-
-.title=Translation Area
-
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/search.bml
--- a/htdocs/translate/search.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-<?_code
-{
-    my $lang = $FORM{'lang'};
-    my $l = LJ::Lang::get_lang($lang);
-    return "<b>Invalid language</b>" unless $l;
-
-    my $dbr = LJ::get_db_reader();
-    my $sth;
-
-    my $sql;
-
-    # all queries use the visible flag
-    my $vis_flag = '';
-    $vis_flag = 'AND i.visible = 1' unless $LJ::IS_DEV_SERVER;
-
-    if ($FORM{'search'} eq 'sev')
-    {
-        my $what = ">= 1";
-        if ($FORM{'stale'} =~ /^(\d+)(\+?)$/) {
-            $what = ($2 ? ">=" : "=") . $1;
-        }
-        $sql = qq(
-            SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l
-            WHERE l.lnid=$l->{'lnid'} AND l.staleness $what AND l.dmid=i.dmid AND l.itid=i.itid $vis_flag
-            ORDER BY i.dmid, i.itcode
-        );
-    }
-
-    if ($FORM{'search'} eq 'txt')
-    {
-        my $remote = LJ::get_remote();
-        return "This search type is restricted to $l->{'lnname'} translators." unless
-            $remote && ( $remote->has_priv( "translate", $l->{'lncode'} ) ||
-                         $remote->has_priv( "faqedit", "*" ) ); # FAQ admins can search too
-
-        my $qtext = $dbr->quote($FORM{'searchtext'});
-        my $dmid = $FORM{'searchdomain'}+0;
-        my $dmidwhere = $dmid ? "AND i.dmid=$dmid" : "";
-        if ($FORM{'searchwhat'} eq "code") {
-            $sql = qq{
-                SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l
-                WHERE l.lnid=$l->{'lnid'} AND l.dmid=i.dmid AND i.itid=l.itid $vis_flag
-                $dmidwhere AND LOCATE($qtext, i.itcode)
-            };
-        } else {
-            my $lnid = $l->{'lnid'};
-            if ($FORM{'searchwhat'} eq "parent") { $lnid = $l->{'parentlnid'}; }
-            $sql = qq{
-                SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l, ml_text t
-                WHERE l.lnid=$lnid AND l.dmid=i.dmid AND i.itid=l.itid
-                $dmidwhere AND t.dmid=l.dmid AND t.txtid=l.txtid AND LOCATE($qtext, t.text) $vis_flag
-                ORDER BY i.itcode
-            };
-        }
-    }
-
-    if ($FORM{'search'} eq 'flg') {
-        return "This type of search isn't available for this language."
-            unless $l->{'lncode'} eq $LJ::DEFAULT_LANG || !$l->{'parentlnid'};
-
-        my $whereflags = join ' AND ',
-            map { $FORM{"searchflag$_"} eq 'yes' ? "$_ = 1" : "$_ = 0" }
-                grep { $FORM{"searchflag$_"} ne 'whatev' } qw(proofed updated);
-        $whereflags = "AND $whereflags"
-            if $whereflags ne '';
-        $sql = qq(
-            SELECT i.dmid, i.itid, i.itcode FROM ml_items i, ml_latest l
-            WHERE l.lnid=$l->{lnid} AND l.dmid=i.dmid AND l.itid=i.itid $whereflags $vis_flag
-            ORDER BY i.dmid, i.itcode
-        );
-    }
-
-    return "Bogus or unimplemented query type." unless $sql;
-
-    my $ret;
-    $sth = $dbr->prepare($sql);
-    $sth->execute;
-    my $page = 0;
-    my @page = ();
-    my $addlink = sub {
-        return unless @page;
-        $page++;
-        my $link = "editpage?lang=$lang&amp;items=" . LJ::eurl(join(",",map{"$_->[0]:$_->[1]"}@page));
-        $ret .= "<b><a target='main' href='$link'>Page $page</a></b><br /><span style='font-size:8pt'>\n";
-        $ret .= "$page[0]->[2]<br />\n";
-        $ret .= "$page[-1]->[2]<br /></span>\n";
-        @page = ();
-    };
-    while (my ($dmid, $itid, $itcode) = $sth->fetchrow_array) {
-        push @page, [ $dmid, $itid, $itcode ];
-        $addlink->() if @page >= 10;
-    }
-    $addlink->();
-
-    if ($page == 0) { $ret .= "<i>(No matches)</i>"; }
-
-    return $ret;
-
-}
-_code?>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/searchform.bml
--- a/htdocs/translate/searchform.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-<html>
-<head><title>Search Form</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-</head>
-<body marginwidth='0' marginheight='0'>
-
-<form target='res' action='search' method='get'>
-<input type='hidden' name='lang' value='<?_code $FORM{'lang'} _code?>'>
-<input type='hidden' name='search' value='sev'>
-
-[<a href="./" target='_top'>&lt;-- Back</a>]
-<?_code
- my $lang = $FORM{'lang'};
- my $l = LJ::Lang::get_lang($lang);
- BML::finish() unless $l;
- return "<b>" . ($l ? $l->{'lnname'} : "Invalid language") . "</b>";
-_code?>
-
-<p>By Severity: (<a href='help-severity' target='main'>help</a>)<br /><select name='stale'>
-<option value="0">0</option>
-<option value="0+">0+</option>
-<option value="1">1</option>
-<option value="1+" selected='selected'>1+</option>
-<option value="2">2</option>
-<option value="2+">2+</option>
-<option value="3">3</option>
-<option value="3+">3+</option>
-<option value="4">4</option>
-</select><input type='submit' value='Search'/>
-</p>
-</form>
-
-<form target='res' action='search' method='get'>
-<input type='hidden' name='lang' value='<?_code $FORM{'lang'} _code?>'>
-<input type='hidden' name='search' value='txt'>
-
-<p>Search
-<?_code
- my $ret;
- my $l = LJ::Lang::get_lang($FORM{'lang'});
- my $pl = LJ::Lang::get_lang_id($l->{'parentlnid'});
- my @opt = ("src" => $l->{'lnname'});
- if ($pl) { push @opt, "parent", $pl->{'lnname'} };
- push @opt, "code", "Item Code";
- $ret .= LJ::html_select({ 'name' => 'searchwhat' },
-                         @opt);
- $ret .= "<br />Area: ";
- $ret .= LJ::html_select({ 'name' => 'searchdomain' },
-                         0, "(all)",
-                         map { $_->{'dmid'}, $_->{'uniq'} }
-                         sort { $a->{'dmid'} <=> $b->{'dmid'} } LJ::Lang::get_domains());
- return $ret;
-_code?>
-    <br />Text: <input name='searchtext' size='15'><input type='submit' value='Search'>
-</p>
-</form>
-
-<?_code
- my $l = LJ::Lang::get_lang($FORM{'lang'});
- return '' unless $l->{'lncode'} eq $LJ::DEFAULT_LANG || !$l->{'parentlnid'};
-
- my $ret = <<HTML;
-<form target='res' action='search' method='get'>
-<input type='hidden' name='lang' value='$l->{lncode}'>
-<input type='hidden' name='search' value='flg'>
-<p><table><tr><td>Prf:</td>
-<td><input type='radio' name='searchflagproofed' value='whatev'>Both</td>
-<td><input type='radio' name='searchflagproofed' value='yes'>Yes</td>
-<td><input type='radio' name='searchflagproofed' value='no'>No</td></tr>
-<tr><td>Upd:</td>
-<td><input type='radio' name='searchflagupdated' value='whatev'>Both</td>
-<td><input type='radio' name='searchflagupdated' value='yes'>Yes</td>
-<td><input type='radio' name='searchflagupdated' value='no'>No</td></tr></table>
-<input type='submit' value='Search'></p></form>
-HTML
- return $ret;
-_code?>
-
-</body>
-</html>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/teams.bml
--- a/htdocs/translate/teams.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-<?page
-title=><?_ml .title _ml?>
-body<=
-<?_code
-{
-    use strict;
-
-    my $dbr = LJ::get_db_reader();
-    my ($ret, $sth);
-
-    LJ::set_active_crumb('translateteams');
-
-    $ret .= "<?h1 $ML{'.teams.header'} h1?>";
-    $ret .= "<?p $ML{'.teams.text'} p?>";
-
-    # get langs
-    $sth = $dbr->prepare("SELECT lnid, lncode, lnname, lastupdate FROM ml_langs");
-    $sth->execute;
-    my %lang;
-    $lang{$_->{'lnid'}} = $_ while $_ = $sth->fetchrow_hashref;
-
-    # get each lang's community
-    $sth = $dbr->prepare("SELECT l.lnid, t.text ".
-                        "FROM ml_latest l, ml_items i, ml_text t ".
-                        "WHERE l.dmid=1 AND t.dmid=1 AND i.dmid=1 AND i.itcode='thislang.community' ".
-                        "AND l.itid=i.itid AND t.txtid=l.txtid AND t.lnid=l.lnid");
-    $sth->execute;
-    while ($_ = $sth->fetchrow_hashref) {
-        next unless exists $lang{$_->{'lnid'}};
-        $lang{$_->{'lnid'}}->{'community'} = $_->{'text'};
-    }
-
-    # get people with privs
-    $sth = $dbr->prepare("SELECT pm.arg, u.user FROM useridmap u, priv_list pl, priv_map pm ".
-                        "WHERE pm.userid=u.userid AND pm.prlid=pl.prlid AND pl.privcode='translate'");
-    $sth->execute;
-    my %team;
-    while (my ($arg, $user) = $sth->fetchrow_array) {
-        push @{$team{$arg}}, $user;
-    }
-
-    $ret .= "<p><table cellpadding='5' border='1'>";
-    $ret .= "<tr><th>$ML{'.table.language'}</th><th>$ML{'.table.community'}</th><th>$ML{'.table.users'}</th></tr>";
-
-    foreach my $l (sort { $a->{'lnname'} cmp $b->{'lnname'} } values %lang) {
-        $ret .= "<tr valign='top' align='left'><td><b>$l->{'lnname'}</b></td>";
-        $ret .= "<td>";
-        $ret .= "<?ljcomm $l->{'community'} ljcomm?>" if $l->{'community'};
-        $ret .= "</td><td>";
-        if ($team{$l->{'lncode'}}) {
-            $ret .= join(", ", map { LJ::ljuser($_) }
-            sort @{$team{$l->{'lncode'}}});
-        }
-        $ret .= "</td></tr>\n";
-    }
-
-    $ret .= "</table>";
-    return $ret;
-}
-_code?>
-
-<=body
-page?>
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/teams.bml.text
--- a/htdocs/translate/teams.bml.text	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-;; -*- coding: utf-8 -*-
-.table.community=Community
-
-.table.language=Language
-
-.table.users=Users With Privs
-
-.teams.header=Teams
-
-.teams.text=Translation is being done by the following teams:
-
-.title=Translation Teams
-
diff -r 9323f181bcb6 -r 8428f0b6ae2d htdocs/translate/welcome.bml
--- a/htdocs/translate/welcome.bml	Tue Feb 16 15:09:47 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-Welcome to the translation area.
-
-<p>In the top-left frame you search for phrases to translate.
-
-<p>The lower-left frame shows your search result links, paginated.
-
-<p>This large frame is the work area, in which text is edited.
--------------------------------------------------------------------------------