Index: /trunk/gsdl/bin/script/picklanguage.pl
===================================================================
--- /trunk/gsdl/bin/script/picklanguage.pl	(revision 3632)
+++ /trunk/gsdl/bin/script/picklanguage.pl	(revision 3632)
@@ -0,0 +1,96 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# translator.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use Cwd;
+use File::Basename;
+use GDBM_File;
+use CGI;
+
+
+sub main
+{
+    my $query = new CGI;
+    my @languages;
+
+    # directory in which to put the generated html pages
+    my $dir = "$ENV{'GSDLHOME'}/tmp/lang/package_forms";
+    # creates directory if it doesn't already exist
+    if (!-e $dir) {
+	my $store_umask = umask(0000);
+	if (! mkdir($dir, 0777)) {
+	    umask($store_umask);
+	    die "Couldn't create directory $dir\n";
+	}
+	umask($store_umask);
+    }
+ 
+    open(LANGFILE, "<$dir/languages.log") or die "MURGH\n";
+
+    while (<LANGFILE>) {
+	$lang = $_;
+	chomp($lang);
+	push(@languages,$lang);
+	<LANGFILE>;
+    }
+    
+    close LANGFILE;
+
+    open(HTMLFILE, ">$dir/picklanguage.lang") or die "MURGH\n";
+    
+    print HTMLFILE ("<center><strong><br>\n",
+		    "Welcome to the Greenstone Language Translation Facility</strong><p>\n",
+		    "<table border=\"2\" cellpadding=\"8\"><tr><td><center>",
+		    "Please select a base language from which to translate: <p>\n",
+		    $query->popup_menu(-name=>"baselanguage",
+				       -values=>\@languages,
+				       -default=>'english'),
+		    "<p></center></td><td><center>\n",
+		    "Please select the language you are translating into: <p>\n",
+		    $query->popup_menu(-name=>"language",
+				       -values=>\@languages),
+		    "<p>\n",
+		    "Or enter the name of a new language: <p>\n",
+		    $query->textfield(-name=>"ownchoice",
+				      -default=>"",
+				      -size=>50),
+		    "<p></center></td></tr></table>\n",
+		    $query->submit("submitlanguage","CONTINUE >>"),
+		    "</center><br>\n");
+    
+    close HTMLFILE;
+}
+
+&main();
Index: /trunk/gsdl/bin/script/submit_translation.pl
===================================================================
--- /trunk/gsdl/bin/script/submit_translation.pl	(revision 3632)
+++ /trunk/gsdl/bin/script/submit_translation.pl	(revision 3632)
@@ -0,0 +1,356 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+# submit_translation.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+#SYNOPSIS OF CODE:
+#Processes translation when user clicks the 'SUBMIT TRANSLATION >>' button on
+#greenstone site. Takes the cgiargsclass and the language being translated
+#into, extracts the macronames and macrotext from the cgi data and hashes
+#them, then links this hash to a database and updates database appropriately
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use Cwd;
+use File::Basename;
+use GDBM_File;
+
+sub main
+{
+    #gets the name of the args file with the cgiargsclass data in it
+    my $filename = shift(@_);
+    #gets the name of the language currently being translated from base language
+    my $language = shift(@_);
+
+    my $baselanguage = shift(@_);
+
+    #stores a hash of macronames with numbers still appended and their values
+    my %distinctkeys = ();
+    #stores an hash of macronames without numbers appended and the value
+    #being the full text of the macro
+    my %macronames = ();
+    
+    my $macrotext = "";
+    $number = 0;
+    
+    $langcode = &getlangcode($language);
+
+    $language = "port" if ($language =~ m/portuguese/);
+    $language = "indo" if ($language =~ m/indonesian/);
+    
+    my ($macronumbered) = &parsebasefile($baselanguage);
+    my ($macronumbered2) = &parsebasefile($baselanguage . "2");
+    ($macronumbered) = &combine_hashes($macronumbered, $macronumbered2);
+ 
+    my ($foreign) = &parseforeignfile($language);
+    my ($foreign2) = &parseforeignfile($language . "2");
+    ($foreign) = &combine_hashes($foreign, $foreign2);
+
+    my ($macronames) = &parseusersubmission($filename);
+
+    foreach $key (keys %macronames) {
+	if ($key =~ m/(_\w+_)/) {
+	    $macronames{$key} = " [l=$langcode] {" . $macronames{$key} . "}\n";
+	    $macro = $key;
+	    $macro =~ s/.*:://;
+	    if ($macronumbered{$macro}) {
+		$number = $macronumbered{$macro};
+		$foreign{$number} = $macro . $macronames{$key};
+	    }
+	}
+	else {
+	    $macronames{$key} =~ s/\&lt;br\&gt;/\n/g;
+	    $macro = $key;
+	    $macro =~ s/.*:://;
+	    if ($macronumbered{$macro}) {
+		$number = $macronumbered{$macro};
+		$foreign{$number} = $macronames{$key};
+	    }
+	}
+    }
+
+    $language2 = $language . "2";
+
+    open MACROOUT, ">$ENV{'GSDLHOME'}/macros/$language.dm" or die "MURGH\n";
+
+    foreach $ky (sort {$a <=> $b} keys %foreign) {
+	if ($foreign{$ky} =~ m/package\s*home/) {
+	    close MACROOUT;
+	    open MACROOUT, ">$ENV{'GSDLHOME'}/macros/$language2.dm" or die "MURGH\n";
+	}
+	print MACROOUT "$foreign{$ky}\n";
+	
+    }
+
+    close MACROOUT;
+
+    return 0;
+
+}
+
+&main(@ARGV);
+
+sub getlangcode {
+
+    $language = shift (@_);
+
+    open(LANGFILE, "<$ENV{'GSDLHOME'}/tmp/lang/package_forms/languages.log") or die "MURGH\n";
+
+    while (<LANGFILE>) {
+	$lang = $_;
+	chomp($lang);
+	$langcode = <LANGFILE>;
+	chomp($langcode);
+	$langHASH{$lang} = $langcode;
+    }
+    
+    close LANGFILE;
+ 
+    $langcode = $langHASH{$language};
+    
+    return ($langcode);
+}
+
+sub parsebasefile {
+
+    $file = shift(@_);
+
+    open (BASEIN, "<$ENV{'GSDLHOME'}/macros/$file.dm") or die("MURGH\n");
+    
+    while (<BASEIN>) {
+	
+	$line = $_;
+	chomp($line);
+	$number++;
+
+	if ($line =~ m/\Apackage /) {
+	    $currpackage = $line;
+	    $currpackage =~ s/package //;
+	    $key = $currpackage . "::package";
+	    $macronumbered{$key} = $number;
+	}
+	elsif ($line =~ m/\A\#\# .*/) {
+	    
+	    my @icon = split(/\s*\#\#\s*/, $line);
+	    
+	    $macro = $icon[(scalar @icon) - 1];
+	    
+	    $macronumbered{$macro} = $number;
+	    
+	    while ($line =~ m/\s+/) {
+		$line = <BASEIN>;
+		chomp($line);
+	    }
+	}
+	elsif ($line =~ m/\A(_\w+_)/) {
+	    $line = $&;
+	    $macronumbered{$line} = $number;
+	}
+	elsif ($line =~ m/\A(\#\stext\smacros)/) {
+	    $key = $currpackage . "::textmacro";
+	    $macronumbered{$key} = $number;
+	}
+	elsif ($line =~ m/\A(\#\sicons)/) {
+	    $key = $currpackage . "::icons";
+	    $macronumbered{$key} = $number;
+	}
+    }
+   
+    close BASEIN;
+    
+    return (\%macronumbered);
+
+}
+
+sub parseforeignfile {
+
+    $file = shift(@_);
+
+    open (MACROIN, "<$ENV{'GSDLHOME'}/macros/$file.dm") or die("MURGH\n");
+    
+    
+    while (<MACROIN>) {
+
+	$number = 0;
+
+	if ($_ =~ m/\A(_\w+_)/) {
+   
+	    $macro = $&;
+	    $number = $macronumbered{$macro} if($macronumbered{$macro});
+	    $line = $_;
+
+	    # while there is still text of the macro to go...
+	    while ($_ !~ /.*\}/) {
+		# ... adds it to the macrotext variable
+		$_ = <MACROIN>;
+		$line .= $_;
+	    }
+	    if ($number != 0) {
+		$foreign{$number} = $line;
+	    }
+	}
+	elsif ($_ =~ m/\A\#\# .*/) {
+	    $line = $_;
+	    
+	    $line .= <MACROIN> unless ($line =~ m/^\#\# .*\#\#/);
+
+	    my @icon = split(/\s*\#\#\s*/, $line);
+	    
+	    $macro = $icon[(scalar @icon) - 1];
+	    
+	    $number = $macronumbered{$macro} if($macronumbered{$macro});
+	    $currline = $line;
+	    
+	    while ($currline =~ m/\S+/) {
+		$currline = <MACROIN>;
+		$line .= $currline;
+	    }
+	    if ($number != 0) {
+		$foreign{$number} = $line;
+	    }
+	}
+	else {
+	    if ($_ =~ m/\S+/) {
+		$line = $_;
+		if ($line =~ m/\Apackage /) {
+		    $currpackage = $line;
+		    chomp($currpackage);
+		    $currpackage =~ s/package //;
+		    $key = $currpackage . "::package";
+		    $number = $macronumbered{$key} if($macronumbered{$key});
+		    $line = "###################################################################\n" . $line;
+		    $line .= "###################################################################\n";
+		    $foreign{$number} = $line;
+		}
+		elsif ($line =~ m/\A(\#\stext\smacros)/) {
+		    $key = $currpackage . "::textmacro";
+		    $number = $macronumbered{$key} if($macronumbered{$key});
+		    $line = "#-------------------------------------------------------------------\n" . $line;
+		    $line .= "#-------------------------------------------------------------------\n";
+		    $foreign{$number} = $line;
+		}
+		elsif ($line =~ m/\A(\#\sicons)/) {
+		    $key = $currpackage . "::icons";
+		    $number = $macronumbered{$key} if($macronumbered{$key});
+		    $line = "#-------------------------------------------------------------------\n" . $line;
+		    $line .= "#-------------------------------------------------------------------\n";
+		    $foreign{$number} = $line;
+		}
+	    }
+	}
+    }
+    close MACROIN;
+
+    return (\%foreign);
+
+}
+
+
+sub parseusersubmission {
+
+    $filename = shift(@_);
+    
+    #opens the args file or kills program
+    open(ARGUMENTS, "<$filename") or die("Did not open $filename\n");
+    #while there are still lines left to read
+    while (<ARGUMENTS>) {
+	#gets the line
+	$line = $_;
+	#chomps off the final newline character
+	chomp($line);
+	
+        #if the line contains :: (browser converts to %3A%3A) then it has a macroname
+	if ($line =~ m/%3A%3A/) {
+	    $macro = $line;
+	    #changes the codes back to ::
+	    $macro =~ s/%3A%3A/::/;
+	    #removes value of macro leaving just the name
+	    $macro =~ s/=.*//;
+	    #saves the value
+	    $value = $&;
+	    #removes all " and = from value
+	    $value =~ s/=//g;
+	    $value =~ s/\A\"//;
+	    $value =~ s/\"\Z//;
+	    $value =~ s/<br>/\n/g;
+	    #removes all " from macro
+	    $macro =~ s/\"//g;
+	    #removes any whitespace from macro
+	    $macro =~ s/\s+//g;
+	    #hashes the macro and it's value
+	    if ($value =~ m/\S+/) {
+		$distinctkeys{$macro} = $value;
+	    }
+	}
+    }
+
+    foreach $distinctkey (sort keys %distinctkeys) {
+
+	$key = $distinctkey;
+	$key =~ s/\d+//;
+	$number = $&;
+	
+	$orderingHASH{$key}{$number} = $distinctkeys{$distinctkey};
+    }
+
+    for $key (sort keys %orderingHASH) {
+	
+	for $number (sort {$a <=> $b} keys %{$orderingHASH{$key}}) {
+	    $macrotext .= $orderingHASH{$key}{$number};
+	    
+	}
+	
+	$macronames{$key} = $macrotext;
+	$macrotext = "";
+    }
+
+    close ARGUMENTS;
+
+    return (\%macronames);
+}
+
+sub combine_hashes {
+    
+    my ($hash1, $hash2) = @_;
+    my %combined = ();
+
+    foreach $key (keys %$hash1) {
+	$combined{$key} = $hash1->{$key};
+    }
+    foreach $key (keys %$hash2) {
+	$combined{$key} = $hash2->{$key};
+    }
+
+    return (\%combined);
+
+}
+
+
+
Index: /trunk/gsdl/bin/script/translator.pl
===================================================================
--- /trunk/gsdl/bin/script/translator.pl	(revision 3632)
+++ /trunk/gsdl/bin/script/translator.pl	(revision 3632)
@@ -0,0 +1,624 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# translator.pl
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+}
+
+use parsargv;
+use util;
+use Cwd;
+use File::Basename;
+use GDBM_File;
+use CGI;
+
+sub main
+{
+    #gets the name of the language that is being translated from base language
+    my $file = shift(@_);
+    
+    my $baselanguage = shift(@_);
+
+    #checks that argument was supplied
+    if (!$file) {
+	die "You didn't supply the name of the language file! Aborting...\n";
+    }
+    $file = "port" if ($file =~ m/portuguese/);
+    $file = "indo" if ($file =~ m/indonesian/);
+
+    #saves the directory path to the database files
+    my $gdbmdir  = "$ENV{'GSDLHOME'}/tmp/lang/gdbmfiles/";
+    #creates the directory if it doesn't exist
+    if (!-e $gdbmdir) {
+	my $store_umask = umask(0000);
+	if (! mkdir($gdbmdir, 0777)) {
+	    umask($store_umask);
+	    die "Couldn't create directory $gdbmdir\n";
+	}
+	umask($store_umask);
+    }
+    #saves the directory path to the macro files
+    my $macrodir = "$ENV{'GSDLHOME'}/macros/";
+    
+     # always do this update because english.dm changes often
+    #hashes the macro file into form of macroname{macrotext}
+    my ($englhash) = &parse_macrofile($macrodir.$baselanguage.".dm");
+    my ($engl2hash) =  &parse_macrofile($macrodir.$baselanguage."2.dm");
+    $englhash = &combine_hashes($englhash,$engl2hash);
+
+    &file_to_db($baselanguage, $englhash);
+    
+    my ($base) = &dateannotation($baselanguage);
+    my ($base2) = &dateannotation($baselanguage."2");
+    $base = &combine_hashes($base,$base2);
+
+    # language macro-filename and database-filename
+    my $macrofile = $macrodir.$file.".dm";
+    my $dbfile = $gdbmdir.$file.".db";
+    
+    if (! -e $macrofile) {
+	
+	@packages = ("Global", "about", "document", "query", "preferences", "browse", "help",
+		     "home", "homehelp", "extlink", "authen", "collector", "docs", "usersedituser",
+		     "usersdeleteuser", "bsummary", "status", "users", "gsdl", "userschangepasswd",
+		     "userschangepasswdok");
+
+	open MCROFILE, ">$macrofile" or die "MURGH\n";
+	
+	foreach $packg (@packages) {
+	    print MCROFILE "package $packg\n";
+	    print MCROFILE "# text macros\n";
+	    print MCROFILE "# icons\n";
+	}
+
+	close MCROFILE;
+
+	$code = $& if($file =~ m/\w\w/);
+
+	open LANGFILE, "<$ENV{'GSDLHOME'}/tmp/lang/package_forms/languages.log" or die "MURGH\n";
+
+	while (<LANGFILE>) {
+	    if ($_ eq $code){ 
+		$code = $& if($file =~ m/.\w\w/);
+		$code =~ s/\A.//;
+	    }
+	}
+
+	close LANGFILE;
+	
+	open LANGFILE, ">>$ENV{'GSDLHOME'}/tmp/lang/package_forms/languages.log" or die "MURGH\n";
+	print LANGFILE "\n$file";
+	$code = $& if($file =~ m/\w\w/);
+	print LANGFILE "\n$code";
+	close LANGFILE;
+    }
+   
+    # if it doesn't have a database file then create one afresh
+    my ($langhash) = &parse_macrofile($macrofile);
+    $macrofile = $macrodir.$file."2.dm";
+    my ($langhash2) = &parse_macrofile($macrofile);
+    $langhash = &combine_hashes($langhash, $langhash2);
+
+    &file_to_db($file, $langhash);
+    
+    my $foreign = &dateannotation($file);
+    my $foreign2 = &dateannotation($file . "2");
+    $foreign = &combine_hashes($foreign, $foreign2);
+
+    #finds the differences between the english database (base language)
+    #and the supplied languages database and hashes these differences
+    #in the form macroname{macrotext}
+    my $diffhash = &db_db_diffs($gdbmdir.$baselanguage.".db", $dbfile, $base, $foreign, $baselanguage);
+    #generates HTML code to display user interface on webpage with what needs translation
+    #returns an array of CGI data
+   
+    $file = "indonesian" if ($file =~ m/indo/);
+    $file = "portuguese" if ($file =~ m/port/);
+
+    my @queries = &generate_pages($diffhash, $file, $baselanguage);
+
+}
+
+sub combine_hashes {
+    
+    my ($hash1, $hash2) = @_;
+    my %combined = ();
+
+    foreach $key (keys %$hash1) {
+	$combined{$key} = $hash1->{$key};
+    }
+    foreach $key (keys %$hash2) {
+	$combined{$key} = $hash2->{$key};
+    }
+
+    return (\%combined);
+
+}
+
+sub parse_macrofile
+{
+    #saves the path of the macro file
+    my $filename = shift(@_);
+    #initialises some local variables
+    my $currpackage;
+    my %macros = ();
+    my @date = localtime(time);
+    
+    #opens macro file or kills program
+    open(IN, "<$filename") or return;
+    #reads in contents of macro file, line by line
+    while (<IN>) {
+	# find out the current package that macros belong to
+	if (s/^package //) {
+	    $currpackage = $_;
+	    chomp($currpackage);
+	}
+	#if line contains a macro name
+	elsif (/^(_\w+_)/) {
+	    # gets the name of the macro ($1 contains text matched by corresponding
+	    #set of parentheses in the last matched pattern within the dynamic scope
+	    #which here matches (_\w+_) )
+	    my $macroname = $1;
+	    #saves the day/month/year
+	    my $macrotext = $date[3]. "/" . $date[4] . "/" . $date[5] ."\n";
+	    # key to the hash and the database
+	    my $key = $currpackage . "::" . $macroname;
+	    # get the first line of the macro
+	    $_ =~ s/^_\w+_ *//;
+	    # while there is still text of the macro to go...
+	    while ($_ !~ /.*\}/) {
+		# ... adds it to the macrotext variable
+		$macrotext .= $_;
+		$_ = <IN>;
+	    }
+	    $macrotext .= $_;
+	    #hashes the macroname and the macrotext
+	    $macros{$key} = $macrotext;
+	}
+	#line in format ## "sometext" ## macro ## macroname ##
+	elsif (/^\#\# .*/) {
+	    my $macroname = $_;
+	    #saves the day/month/year
+	    my $macrotext = $date[3]. "/" . $date[4] . "/" . $date[5] ."\n";
+	    	   
+	    unless ($macroname =~ m/^\#\# .*\#\#/) {
+		
+		$macroname = $_;
+		chomp($macroname);
+		$_ = <IN>;
+		$macroname .= $_;
+		
+	    }
+
+	    my @names = split(/\s*\#\#\s*/, $macroname);
+	    
+	    $macrotext .= $macroname;
+	    $_ = <IN>;
+
+	    $macroname = $names[(scalar @names) - 1];
+	    
+	    my $key = $currpackage . "::" . $macroname; # key to the hash and the database
+
+	    while ($_ !~ /^\s+/) {
+		$macrotext .= $_;
+		$_ = <IN>;
+	    }
+
+	    $macros{$key} = $macrotext;
+	}
+	
+    }    
+    close IN;
+    
+    return (\%macros);
+}
+
+sub dateannotation {
+    
+    $language = shift(@_);
+    my %macrodated = ();
+
+    $file = qx/cd $ENV{'GSDLHOME'}\/macros;cvs annotate $language.dm/;
+    @file = split(/\n/,$file);
+   
+    for ($p = 0; $p < scalar(@file); $p++) {
+	
+	$line = $file[$p];
+	chomp($line);
+	$line =~ s/.*\(.*\):\s//;
+	$date = $&;
+	
+	$date = $& if($date =~ m/\d\d-\w\w\w-\d\d/);
+	
+	if ($line =~ m/\#\# .*/) {
+	    	   
+	    unless ($line =~ m/\A\#\# .*\#\#/) {
+		$line = $file[++$p];
+		chomp($line);
+		$line =~ s/.*\(.*\):\s//;
+	    }
+	    my @icon = split(/\s*\#\#\s*/, $line);
+	    
+	    $macro = $icon[(scalar @icon) - 1];
+	    
+	    $macrodated{$macro} = $date;
+	    
+	    while ($line =~ m/\s+/) {
+		$line = $file[++$p];
+		chomp($line);
+		$line =~ s/.*\(.*\):\s//;
+	    }
+	}
+	elsif ($line =~ m/\A(_\w+_)/) {
+	    $line = $&;
+	    $macrodated{$line} = $date;
+	}
+    }
+    
+    return (\%macrodated);
+}
+
+
+#######################
+# DATABASE OPERATIONS #
+#######################
+
+# At the moment this routine is used to update english.db
+# file when there are change in english.dm macro file; it
+# has been made generic so that other database files can be
+# updated if the need arises in the future.
+sub file_to_db
+{
+    my ($filename, $filehash) = @_;
+
+    my $database = "$ENV{'GSDLHOME'}/tmp/lang/gdbmfiles/$filename.db";
+    my %dbhash = ();
+
+    
+    if (-e $database) {
+	
+	tie(%dbhash, 'GDBM_File', $database, 1, 0640) or die "$!";
+
+	foreach $filekey (sort(keys(%$filehash))) {
+	    if (!($dbhash{$filekey})) {
+		$dbhash{$filekey} = $filehash->{$filekey};
+	    }
+	    else {
+		# strip off the dates from both entries...
+		my $filemacro = ($filehash->{$filekey});
+		my $dbmacro = ($dbhash{$filekey});
+		$filemacro =~ s/^.*//;
+		$dbmacro =~ s/^.*//;
+
+		if ($dbmacro ne $filemacro) {
+		    #update the database to reflect the change...
+		    $dbhash{$filekey} = $filehash->{$filekey};
+		}
+	    }
+	}
+    }
+    else { # create the database file for the particular language file...
+	# tie the hash to the database
+	tie(%dbhash, "GDBM_File", $database, GDBM_WRCREAT, 0640);
+	
+	%dbhash = %$filehash;
+    }
+
+    untie %dbhash;
+}
+
+# db_db_diffs => Takes two paramaters which are two database filenames, works out
+#                the differences between the two, and returns them in %diffhash
+#
+# ARGUMENTS: $db_one is the database which contains all the values, e.g. english
+#            $db_two is the database which is possibly missing some values
+#
+# PRE:  $db_one and $db_two assumed to exist
+# POST: %differences holds entries that are in $db_one but not in $db_two
+sub db_db_diffs
+{
+    my ($db_one, $db_two, $basedates, $foreigndates, $baselanguage) = @_;
+
+    my %db1hash = ();
+    my %db2hash = ();
+    my %months = ("Jan",1,"Feb",2,"Mar",3,"Apr",4,"May",5,"Jun",6,
+		  "Jul",7,"Aug",8,"Sep",9,"Oct",10,"Nov",11,"Dec",12);
+    
+    # this hash holds the database entries that are in 
+    # english.db but not in $filename.db
+    my %diffhash = ();
+
+    #ties the hash to database so when you read from hash it fetches from external
+    #database and when you set hash it writes to external database
+    tie(%db1hash, "GDBM_File", $db_one, GDBM_READER, 0640);
+    tie(%db2hash, "GDBM_File", $db_two, GDBM_READER, 0640);
+
+    #the key is the name of the macro
+    foreach $key (sort(keys(%db1hash))) {
+	#if the macro isn't there at all, then it's different
+	if (!$db2hash{$key}) {
+	    $diffhash{$key} = [$db1hash{$key},"",""];
+	}
+	#else if the macro is in both, want to compare date stamps of date hashes HERE
+	#and if foreign date is older than base date want to add to diffhash aswell
+	else {
+	    $macro = $key;
+	    $macro =~ s/\A.*:://;
+	    $bdate = $basedates->{$macro};
+	    $fdate = $foreigndates->{$macro};
+	    @bdate = split(/-/,$bdate);
+	    @fdate = split(/-/,$fdate);
+	    if ($bdate[2] >= $fdate[2]) {
+		if ($months{$bdate[1]} >= $months{$fdate[1]}) {
+		    if ($bdate[0] > $fdate[0]) {
+			$foreigntext = $db2hash{$key};
+			$foreigntext =~ s/^.*\n//;
+			$foreigntext =~ s/.*\{//;
+			$foreigntext =~ s/\}\Z//;
+
+			$file = qx/cd $ENV{'GSDLHOME'}\/macros;cvs diff -D $fdate $baselanguage.dm/;
+			$file .= qx/cd $ENV{'GSDLHOME'}\/macros;cvs diff -D $fdate $baselanguage"2.dm"/;
+			@file = split(/\n/,$file);
+
+			$found = 1;
+			foreach $key (@file) {
+			    if ($key =~ m/$macro/) {
+				if ($key =~ m/\A</) {
+				    $key =~ s/\A<\s*(_\w+_)\s*\{//;
+				    $key =~ s/\}\Z//;
+				    print STDERR "KEY>>>>>||||| $key\n";
+				}
+				$found = 0;
+			    }
+			}
+			print STDERR "NOTFOUND $macro\n" if ($found);
+		    
+			$diffhash{$key} = [$db1hash{$key}, $foreigntext,""];
+		    }
+		}
+	    }
+	}
+    }
+
+    untie %db1hash;
+    untie %db2hash;
+
+    return \%diffhash;    
+}
+
+
+#############################################
+# WEB-FORM GENERATION AND ARGUMENT FETCHING #
+#############################################
+
+# generates web-form using the datahash you pass in;
+# it will be broken down into pages, 15 macros per page
+sub generate_pages
+{
+
+    my ($datahash) = shift(@_);
+    my $lang = shift(@_);
+    my $baselanguage = shift(@_);
+    my %pagehash = ();
+    my @query_pages = ();
+
+    # directory in which to put the generated html pages
+    my $dir = "$ENV{'GSDLHOME'}/tmp/lang/package_forms";
+   
+    # creates directory if it doesn't already exist
+    if (!-e $dir) {
+	my $store_umask = umask(0000);
+	if (! mkdir($dir, 0777)) {
+	    umask($store_umask);
+	    die "Couldn't create directory $dir\n";
+	}
+	umask($store_umask);
+    }
+    
+    @pageno = ();
+    $pageno = 1;
+    $keysperpage = 0;
+    $limit = 15;
+
+    # goes through hash of differences between base language and translation
+    foreach $key (sort(keys(%$datahash))) {
+	#in the hash of HTML pages, add this key to the current page and initialise it
+	#with it's value in the datahash
+	$pagehash->{$pageno}->{$key} = $datahash->{$key};
+	$keysperpage++;
+	
+	$limit = 7 if($key =~ m/collector::_text.*/);
+	$limit = 7 if(!($key =~ m/_.*\_/g));
+	$limit = 7 if($key =~ m/help::_text.*/);
+	$limit = 3 if($key =~ m/home::.*/);
+	$limit = 3 if($key =~ m/gsdl::.*/);
+	$limit = 1 if($key =~ m/help::_(.*)texthelp.*/);
+	$limit = $keysperpage if ($limit <= $keysperpage);
+
+	#if have enough keys to generate a page with
+	if ($keysperpage == $limit) {
+	    #resets key counting variable
+	    $keysperpage = 0;
+	    $limit = 15;
+	    #opens a file to write the HTML code to for current page
+	    open HTMLFILE, ">$dir/$pageno.lang";
+
+	    #passes hash of keys for current page and filehandle, returns CGI data
+	    my $query = &generate_form($pagehash->{$pageno}, \*HTMLFILE, $lang, $baselanguage);
+	    close HTMLFILE;
+
+	    #push the page number onto the array of pages
+	    push(@pageno, $pageno);
+	    #increment the current page
+	    $pageno++;
+	}
+    }
+    
+    #if you exit the loop with keys still to write
+    if ($keysperpage != 0) {
+	
+	#writes out the remaining keys, same format as above
+	open HTMLFILE, ">$dir/$pageno.lang";
+	my $query = &generate_form($pagehash->{$pageno}, \*HTMLFILE, $lang, $baselanguage);
+	close HTMLFILE;
+	push(@pageno, $pageno);
+    }
+
+    #writes each page number to a file
+    open PAGELOG, ">$ENV{'GSDLHOME'}/tmp/lang/package_forms/pageno.log" or die("MURGH\n");
+    foreach $page (@pageno) {
+	print PAGELOG $page, "\n";
+    }
+    close PAGELOG;
+
+    #write thankyou page for language translator once translation is complete
+    open THANKYOU, ">$ENV{'GSDLHOME'}/tmp/lang/package_forms/thankyou.lang" or die("MURGH\n");
+    print THANKYOU "<center>Thankyou for completing the $lang translation<p></center>\n";
+    close THANKYOU;
+
+    #returns CGI data
+    return @queries;
+}
+
+sub generate_form
+{
+    my $formhash = shift(@_);
+    my $fh = shift(@_);
+    my $language = shift(@_);
+    my $baselanguage = shift(@_);
+    # common gateway interface for writing the stuff to the web
+    my $query = new CGI;
+    my $keynamecount = 1;
+
+    print $fh ("<center>\n",
+	       "If an<font color=\"FF0000\"> UPDATED! </font>tag is present a translation already exists,<br>\n",
+	       "however it's macro has since been updated.<br>\n",
+	       "Please ensure that the current translation provided in the input field is correct.<br>\n",
+	       $query->hidden(-name=>"hiddenlanguage",-default=>"$language"),
+	       $query->hidden(-name=>"baselanguage",-default=>"$baselanguage"),
+	       "<p><table border=\"5\" cellpadding=\"10\">\n",
+	       "<tr><td><strong>BASE LANGUAGE FILE<br>",
+	       "________________________________</strong></td>\n",
+	       "<td><strong>TRANSLATED LANGUAGE<br>",
+	       "________________________________</strong></td></tr>\n");
+    
+    
+    foreach $key (sort(keys(%$formhash))) {
+
+	my $text = $formhash->{$key}[0];
+	
+	# whole lot of formatting on strings
+	# escape all the '_' with '\' so that Greenstone doesn't substitute
+	# the macro names for the contents of the macro itself
+	my $keyname = $key;
+	  
+	$keyname  =~ s/_/\\_/g;
+	# strip off the date
+	$text =~ s/.*//;
+	$text =~ s/(\[l=.*\])//;
+	# tells you the date the english file was last updated...
+	#$date = $&;
+	
+	print STDERR "$text\n";
+
+	
+	# must take care of image macros single and multiple line ones
+	$text =~ s/(\<br\>\#\#.*\#\#\s*\<br\>).*/$1/g;
+	
+	# format the text for displaying in the browser
+	$text =~ s/[\{\}]//g unless($text =~ m/\#\# /);
+	$text =~ s/(\A\n)//;
+	$text =~ s/(\n\Z)//;
+	$text =~ s/\n/\<br\>/g;
+	
+	$text =~ s/</\&lt;/g;
+	$text =~ s/>/\&gt;/g;
+	$text =~ s/\b_([A-Za-z0-9:]+)_\b/ \b\\_$1\\_ \b/g;
+	
+	$keynamecount = 1;
+	
+	my $default = $formhash->{$key}[1];
+	my $updated = "";
+	$updated = "<font color=\"FF0000\"> UPDATED! </font><br>" if ($default =~ m/\S+/);
+
+        # so that when it is an image only get the text to translate not coding stuff aswell
+	if ($text =~ m/\#\# (^|.)*/) {
+	    if ($& =~ m/".*"/) {
+		print $fh ("<tr><td> $updated $&</td><td>",
+			   $query->hidden(-name=>"$keyname" . "$keynamecount",-default=>"$`"));
+		$keynamecount++;
+		print $fh ($query->textfield(-name=>"$keyname" . "$keynamecount",
+					     -default=>"$default",
+					     -size=>50));
+		$keynamecount++;
+		print $fh ($query->hidden(-name=>"$keyname" . "$keynamecount",-default=>"$'"),
+			   "</td></tr>\n");
+	    }
+	}
+	elsif ($text =~ m/\S+/) {
+		$text =~ s/\s+/ /g;
+		$text =~ s/\&lt;br\&gt;/\&lt;br\&gt;\n/g;
+
+		my @words = split(/ /, $text);
+		my $words = scalar(@words);
+		my $rows = sprintf("%.0f", $words/5);
+		print $fh ("<tr><td> $updated $text </td><td>\n");
+		if ($rows > 1) {
+		    print $fh ($query->textarea(-name=>"$keyname" . "$keynamecount",
+						-rows=>$rows * 2,
+						-default=>"$default",
+						-columns=>50), 
+			       "<br></td></tr>\n");  
+		}
+		else {
+		    print $fh ($query->textfield(-name=>"$keyname" . "$keynamecount",
+						 -default=>"$default",
+						 -size=>50),
+			       "<br></td></tr>\n");
+		}
+	    }
+    }
+    #finishes table and adds a SUBMIT CHANGES option on the end
+    print $fh ("</table>\n", "<br>",
+	       "Please ensure your $language translation is correct before proceeding.<br>\n",
+	       "Input fields may be left empty if necessary and only those field which<br>\n",
+	       "contain a translation will be submitted to the macro file.<br>\n",
+	       "Submitting this page will result in the next page being loaded automatically.<br><strong>\n",
+	       $query->submit($pageno, 'SUBMIT TRANSLATION >>'),
+	       "</strong>","</center>\n");
+
+    # adds the CGI area just written to the array of CGI areas
+    push (@queries, $query);
+    
+    return $query;
+}
+
+&main(@ARGV);
+
Index: /trunk/gsdl/etc/main.cfg
===================================================================
--- /trunk/gsdl/etc/main.cfg	(revision 3631)
+++ /trunk/gsdl/etc/main.cfg	(revision 3632)
@@ -74,5 +74,6 @@
                 spanish.dm spanish2.dm dutch.dm port.dm russian.dm russian2.dm \
                 italian.dm italian2.dm turkish.dm turkish2.dm \
-		home.dm collect.dm docs.dm hebrew.dm indo.dm bsummary.dm
+		home.dm collect.dm docs.dm hebrew.dm indo.dm bsummary.dm \
+                translang.dm
 
 # Define the interface languages and encodings supported by this receptionist
Index: /trunk/gsdl/src/recpt/Makefile.in
===================================================================
--- /trunk/gsdl/src/recpt/Makefile.in	(revision 3631)
+++ /trunk/gsdl/src/recpt/Makefile.in	(revision 3632)
@@ -39,6 +39,4 @@
 endif
 
-
-
 AR = ar
 CC = @CC@
@@ -51,12 +49,20 @@
 YAZDIR=../../packages/yaz
 
+USE_LANGACTION = @USE_LANGACTION@
+ifneq ($(USE_LANGACTION), 1)
+LANGACTION_DEFS=
+else
+LANGACTION_DEFS=-DUSE_LANGACTION
+endif
+
+
 USE_FASTCGI = @USE_FASTCGI@
 ifneq ($(USE_FASTCGI), 1)
-DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM @DEFS@
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM @DEFS@ $(LANGACTION_DEFS)
 INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
 	   -I../../packages/mg/lib -I../../packages/mg/src/text \
 	   -I../mgpp/lib -I../mgpp/text -I../..
 else 
-DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DUSE_FASTCGI @DEFS@
+DEFS = -DNZDL -DQUIET -DSHORT_SUFFIX -DPARADOCNUM -DUSE_FASTCGI @DEFS@ $(LANGACTION_DEFS)
 INCLUDES = -I../../lib -I. -I../colservr -I../../packages/mg \
 	   -I../../packages/mg/lib -I../../packages/mg/src/text \
@@ -128,4 +134,10 @@
 .mpp.o:
 	$(MCOMPILE) $< -o $@
+
+ifeq ($(USE_LANGACTION), 1)
+LANG_HEADERS=langaction.h langdb.h
+else
+LANG_HEADERS=
+endif
 
 COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
@@ -138,5 +150,5 @@
 		datelistbrowserclass.h invbrowserclass.h pagedbrowserclass.h \
 		htmlbrowserclass.h phindbrowserclass.h historydb.h collectoraction.h \
-		phindaction.h summarise.h highlighttext.h
+		phindaction.h summarise.h highlighttext.h $(LANG_HEADERS)
 
 RECEPTHEADERS = 
@@ -150,4 +162,9 @@
 HEADERS = $(COMMONHEADERS) $(RECPTHEADERS) $(LIBRARYHEADERS)
 
+ifeq ($(USE_LANGACTION), 1)
+LANG_SOURCES= langaction.cpp langdb.cpp
+else
+LANG_SOURCES=
+endif
 
 COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
@@ -161,5 +178,5 @@
 		phindbrowserclass.cpp  historydb.cpp collectoraction.cpp argdb.cpp \
 		browseactiontools.h formattools.cpp phindaction.cpp summarise.cpp \
-		highlighttext.cpp
+		highlighttext.cpp $(LANG_SOURCES)
 
 
@@ -174,5 +191,5 @@
 LIBRARYSOURCES = nullproto.cpp librarymain.cpp $(Z_LIBSOURCES)
 
-SOURCES = $(COMMONSOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
+SOURCES = $(COMMONSOURCES) $(LANG_SOURCES) $(RECPTSOURCES) $(LIBRARYSOURCES)
 
 
@@ -181,4 +198,10 @@
 else
 Z_COMOBJS=
+endif
+
+ifeq ($(USE_LANGACTION), 1)
+LANG_OBJECTS= langaction.o langdb.o
+else
+LANG_OBJECTS=
 endif
 
@@ -193,5 +216,5 @@
 		pagedbrowserclass.o htmlbrowserclass.o phindbrowserclass.o \
 		historydb.o $(Z_COMOBJS) collectoraction.o phindaction.o \
-		summarise.o highlighttext.o
+		summarise.o highlighttext.o $(LANG_OBJECTS)
 
 RECPTOBJECTS = recptmain.o
Index: /trunk/gsdl/src/recpt/langaction.cpp
===================================================================
--- /trunk/gsdl/src/recpt/langaction.cpp	(revision 3632)
+++ /trunk/gsdl/src/recpt/langaction.cpp	(revision 3632)
@@ -0,0 +1,389 @@
+ /**********************************************************************
+ *
+ * langaction.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include <stdio.h>
+#include <fstream.h>
+#include "langaction.h"
+#include "fileutil.h"
+#include "gsdltools.h"
+#include "gsdlunicode.h"
+#include "langdb.h"
+#include "errno.h"
+#include <sys/utsname.h>
+
+ 
+/*====================*
+ * GLOBAL DEFINITIONS *
+ *====================*/
+
+// text file reading buffer
+const int BUFFSIZE = 1024;
+char temp[BUFFSIZE];
+
+
+
+/*========================*
+ * LOCAL UTILITY ROUTINES *
+ *========================*/
+
+// gets the list of packages/files that contain the content of the web-forms
+text_tarray get_pagenos(text_t dir, ostream &logout)
+{
+  text_tarray pagenos;
+
+  // file 'logfile' contains all the page numbers, one number per line
+  text_t logfile = filename_cat(dir, "package_forms", "pageno.log");
+  
+  //open the file as a read only file
+  ifstream readfile(logfile.getcstr(), ios::in);
+  
+  // if file isn't opened, print error and return
+  if (!readfile) {
+    logout << "File " << logfile.getcstr() << " could not be found.\n";
+    return pagenos;
+  }
+  
+  // go through file, pushing each page number on to the end of a text_tarray
+  while (readfile.getline(temp, BUFFSIZE-1)) {
+    text_t t_temp = temp;
+    pagenos.push_back(temp);
+  }
+  readfile.close();
+    
+  //returns the array of page numbers
+  return pagenos;
+}
+
+bool text_t_substring (text_t &text, text_t &substr)
+{
+  int SIZE = substr.size();
+
+  if (text.size() >= SIZE) {
+    if (substr <= text) {
+      if (text[0] == substr[0]) {
+	text_t temp = "";
+	// copy first SIZE elements of 'text' into 'temp'
+	for (int size = 0; size < SIZE; size++) {
+	  temp.push_back(text[size]);
+	}
+	if (temp == substr)
+	  return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+bool langaction::init (ostream & /*logout*/) {
+
+  // set up GSDLOS, GSDLHOME and PATH environment variables
+  text_t gsdlos, path;
+  unsigned int path_separator = ':';
+#if defined (__WIN32__)
+  gsdlos = "windows";
+  path_separator = ';';
+
+  path = filename_cat (gsdlhome, "bin", "windows", "perl", "bin;");
+
+#else
+  struct utsname *buf = new struct utsname();
+  int i = uname (buf);
+  if (i == -1) gsdlos = "linux"; // uname failed
+  else gsdlos.setcstr (buf->sysname);
+  delete buf;
+  lc (gsdlos);
+#endif
+
+  pathc = getenv ("PATH");
+  path += filename_cat (gsdlhome, "bin", gsdlos);
+  path.push_back (path_separator);
+  path += filename_cat (gsdlhome, "bin", "script");
+  if (pathc != NULL) {
+    path.push_back (path_separator);
+    path += pathc;
+  }
+  path = "PATH=" + path;
+
+  gsdlos = "GSDLOS=" + gsdlos;
+  text_t setgsdlhome = "GSDLHOME=" + gsdlhome;
+
+  // these will be cleaned up in the destructor
+  gsdlosc = gsdlos.getcstr();
+  gsdlhomec = setgsdlhome.getcstr();
+  pathc = path.getcstr();
+  
+  putenv (gsdlosc);
+  putenv (gsdlhomec);
+  putenv (pathc);
+
+  return true;
+}
+/*====================*
+ * CLASS DEFINITIONS  *
+ *====================*/
+
+langaction::langaction () {
+
+  package = "";
+
+  // this action uses cgi variables "a", and "p"
+  cgiarginfo arg_ainfo;
+
+  arg_ainfo.shortname = "l";
+  arg_ainfo.longname = "language";
+  arg_ainfo.multiplechar = true;
+  arg_ainfo.defaultstatus = cgiarginfo::weak;
+  arg_ainfo.argdefault = "en";
+  arg_ainfo.savedarginfo = cgiarginfo::must;
+  argsinfo.addarginfo (NULL, arg_ainfo);
+}
+
+langaction::~langaction () {
+}
+
+bool langaction::check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+				ostream &logout) {
+  // authenticate the user before allowing modifications
+  //  args["uan"] = 1;
+  //  args["ug"] = "langadmin";
+
+  return true;
+}
+
+void langaction::get_cgihead_info (cgiargsclass &/*args*/, recptprotolistclass * /*protos*/,
+				   response_t &response,text_t &response_data, 
+				   ostream &/*logout*/) {
+  response = content;
+  response_data = "text/html";
+}
+
+void langaction::define_internal_macros (displayclass &disp, cgiargsclass &args, 
+					 recptprotolistclass *protos, ostream &logout) {
+  text_t text = "";
+  text_t cmd = "";
+  text_t &arg_p = args["p"];
+  text_tarray pagenos;
+  text_t dir = filename_cat(gsdlhome, "tmp", "lang");
+  text_t pageno ="";
+  text_t lang = "";
+
+  // argument for page is of the form 'macrofile_pageno' so
+  // we need to split the argument to get the proper page content
+  text_tarray splitarray;
+  splitchar(arg_p.begin(), arg_p.end(), '_', splitarray);
+  
+  arg_p = splitarray[0];
+  if (splitarray.size() > 1)
+    pageno = splitarray[splitarray.size()-1];
+  
+  if (pageno == "picklanguage")
+    pageno = "1";
+  
+  if (pageno.empty())
+    pageno = "picklanguage";
+
+  //produce the picklanguage webpage
+  if (pageno == "picklanguage") {
+    cmd = "perl " + filename_cat(gsdlhome, "bin", "script", "picklanguage.pl");
+    if(gsdl_system(cmd,true,logout) != 0)
+      return;
+    define_webpage(disp, protos, logout, pageno, lang, dir, pagenos, text);
+    return;
+  }
+ 
+  //creates output stream to argsfile (dir is gsdlhome/tmp/lang)
+  text_t argsfile = filename_cat(dir, "arguments.arg");
+  ofstream argsout(argsfile.getcstr(), ios::out);
+  
+  //informs user and returns if output stream not opened
+  if(!argsout) {
+    logout << "File " << argsfile.getcstr() << " could not be opened\n";
+      return;
+  }
+  
+  //ensures access permissions make the file world writable
+  text_t changemode = "chmod a+w ";
+  changemode += argsfile;
+  gsdl_system(changemode, false, logout);
+  
+  //write out the cgiargsclass passes as a parameter to the subroutine to the argsout file
+  argsout << args;
+  
+  //close the argsout output stream
+  argsout.close();
+  
+  //sets the current foreign language
+  if (args["ownchoice"] != "") {
+    lang = args["ownchoice"];
+  }
+  else if (args["hiddenlanguage"] != "") {
+    lang = args["hiddenlanguage"];
+  }
+  else {
+    lang = args["language"];
+  }
+  text_t baselanguage = "";
+
+  //sets current base language
+  if (args["baselanguage"] != "") {
+    baselanguage = args["baselanguage"];
+  }
+  
+  
+  //calls the translator file to create HTML files
+  cmd = "perl " + filename_cat(gsdlhome, "bin", "script", "translator.pl") + " " + lang + " " + baselanguage;
+
+  if ((gsdl_system(cmd, true, logout)) != 0) {
+    logout << "Process " << cmd.getcstr() << " did not execute.../;-D\n";
+    return;
+  }
+  
+  //if no more pages will set pageno to thankyou script
+  pagenos = get_pagenos(dir,logout);
+  if (pagenos.empty())
+    pageno = "thankyou";
+  
+
+  text_t &submitargs = args[pageno];
+  text_t submit = "SUBMIT TRANSLATION >>";
+  
+  //if the SUBMIT TRANSLATION >> button has been pushed
+  if (text_t_substring(submitargs,submit)) {
+    
+    //create the command line for submitting the translation
+    cmd = "perl " + filename_cat(gsdlhome, "bin", "script", "submit_translation.pl") + " ";
+    cmd += (argsfile + " " + lang + " " + baselanguage);
+    
+    //give command to system to execute submission of translation
+    if((gsdl_system(cmd, true, logout)) != 0)
+      logout << "Process " << cmd.getcstr() << " did not execute\n";
+    
+    //increments which page is displayed when translation is submitted
+    for (text_tarray::iterator page_itr = pagenos.begin(); 
+	 page_itr != pagenos.end(); 
+	 page_itr++) {
+      
+      if (*page_itr == pageno) {
+	page_itr++;
+	if (page_itr != pagenos.end())
+	  pageno = *page_itr;
+	else
+	  pageno = "thankyou";
+	
+	break;	
+      }
+    }
+  }
+  //want it to automatically load the next page here instead of reloading page
+  //that has just been translated with everything empty again.
+  
+  define_webpage(disp, protos, logout, pageno, lang, dir, pagenos, text);
+}
+
+void langaction::define_webpage (displayclass &disp, 
+				 recptprotolistclass *protos, ostream &logout,
+				 text_t &pageno, text_t &lang, text_t &dir, 
+				 text_tarray &pagenos, text_t &text) {
+  
+  // produces HTML page with the current pages contents
+  // formfile is the file that contains web-form for the
+  // current package whose name is stored in 'package'
+
+  text_t formfile = filename_cat(dir, "package_forms");
+  formfile += ("/" + pageno + ".lang");
+    
+  ifstream readfile(formfile.getcstr(), ios::in);
+  if (!readfile) {
+    logout << "File " << formfile.getcstr() << " could not be found.\n";
+    return;
+  }
+  
+  
+  /* ============================ START WEB-FORM HTML CODE ============================ */
+  text += "\n<input type=hidden name=\"a\" value=\"lang\">";
+  text += "\n<input type=hidden name=\"p\" value=\"translang_";
+  text += pageno;
+  text += "\">\n";
+  
+  //if not a special case page display translation info
+  if ((pageno != "thankyou") && (pageno !="picklanguage")) {
+    text += "<center><strong>You are currently translating page ";
+    text += pageno;
+    text += " of ";
+    text += pagenos.size();
+    text += " in to ";
+    text += lang;
+    text += "</strong></center><p><p>\n"; 
+  }
+  
+  //read in HTML from file
+  while(readfile.getline(temp, BUFFSIZE-1)) {
+    text_t t_temp = temp;
+    text += t_temp;
+    text += "\n";
+  }
+  readfile.close();
+  
+  //if not a special case page display translation info
+  if ((pageno != "thankyou") && (pageno != "picklanguage")) {
+    text += "<center><strong>You are currently translating page ";
+    text += pageno;
+    text += " of ";
+    text += pagenos.size();
+    text += " in to ";
+    text += lang;
+    text += "</strong></center><br>\n";
+  } 
+  
+  
+  /* ============================ END WEB-FORM HTML CODE ============================ */
+  
+  // THE FOLLOWING MACROS ARE DEFINED IN translang.dm MACRO FILE
+  // set the formcontent  as the content of the form-page
+  disp.setmacro("formcontent", "translang", text);
+  
+  // set the action for the form
+  //  disp.setmacro("formaction", "translang", "/cgi-bin/dg5/library");
+  disp.setmacro("formaction", "translang", "_gwcgi_");
+
+}
+
+bool langaction::do_action (cgiargsclass &args, recptprotolistclass * /*protos*/, 
+			    browsermapclass * /*browsers*/, displayclass &disp, 
+			    outconvertclass &outconvert, ostream &textout, 
+			    ostream &logout) {
+  text_t &arg_p = args["p"];
+  
+  textout << outconvert << disp << ("_" + arg_p + ":header_\n")
+	  << ("_" + arg_p + ":content_\n")
+	  << ("_" + arg_p + ":footer_\n");
+
+  return true;
+}
+
+
+
+
Index: /trunk/gsdl/src/recpt/langaction.h
===================================================================
--- /trunk/gsdl/src/recpt/langaction.h	(revision 3632)
+++ /trunk/gsdl/src/recpt/langaction.h	(revision 3632)
@@ -0,0 +1,74 @@
+/**********************************************************************
+ *
+ * langaction.h -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef LANGACTION_H
+#define LANGACTION_H
+
+
+#include "action.h"
+
+class langaction : public action {
+
+protected:
+  // package whose contents will be displayed in the form space
+  text_t package;
+  char *gsdlosc;
+  char *gsdlhomec;
+  char *pathc;
+
+public:
+  langaction ();
+  virtual ~langaction ();
+
+  text_t get_action_name () {return "lang";}
+
+  bool check_cgiargs (cgiargsinfoclass &/*argsinfo*/, cgiargsclass &args, 
+		      ostream &logout);
+
+  void define_internal_macros (displayclass &disp, cgiargsclass &args, 
+			       recptprotolistclass *protos, ostream &logout);
+
+  void get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
+			 response_t &response,text_t &response_data, 
+			 ostream &logout);
+
+  bool do_action (cgiargsclass &args, recptprotolistclass *protos, 
+		  browsermapclass *browsers, displayclass &disp, 
+		  outconvertclass &outconvert, ostream &textout, 
+		  ostream &logout);
+
+  bool init (ostream & /*logout*/);
+  
+  void define_webpage (displayclass &disp, 
+		       recptprotolistclass *protos, ostream &logout,
+		       text_t &pageno, text_t &lang, text_t &dir,
+		       text_tarray &pagenos, text_t &text);
+    
+
+};
+
+
+#endif
Index: /trunk/gsdl/src/recpt/langdb.cpp
===================================================================
--- /trunk/gsdl/src/recpt/langdb.cpp	(revision 3632)
+++ /trunk/gsdl/src/recpt/langdb.cpp	(revision 3632)
@@ -0,0 +1,111 @@
+/**********************************************************************
+ *
+ * userdb.cpp -- functions to handle a language macro database
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+#include "gsdlconf.h"
+#include "langdb.h"
+#include "gsdltimes.h"
+#include "fileutil.h"
+#include <stdlib.h>
+
+
+////////////////
+// macroinfo_t
+////////////////
+
+void macroinfo_t::clear () {
+  macroname.clear();
+  macrotext.clear();
+}
+
+macroinfo_t &macroinfo_t::operator=(const macroinfo_t &x) {
+  macroname = x.macroname;
+  macrotext = x.macrotext;
+  
+  return *this;
+}
+
+
+// functions dealing with language macro databases
+
+// returns true on success (in which case macroinfo will contain
+// the information for this macro)
+bool get_macro_info (gdbmclass &langdb, const text_t &macroname,
+		    macroinfo_t &macroinfo) {
+  macroinfo.clear();
+  
+  infodbclass info;
+  if (langdb.getinfo (macroname, info)) {
+    macroinfo.macroname = info["macroname"];
+    macroinfo.macrotext = info["macrotext"];
+    return true;
+  }
+
+  return false;
+}
+
+bool get_macro_info (const text_t &langdbfile, const text_t &macroname, 
+		     macroinfo_t &macroinfo) {
+  // THIS IS GOING TO READ FROM THE MACRO FILE FIRST TIME...
+
+  gdbmclass langdb;
+  if (!langdb.opendatabase(langdbfile, GDBM_READER, 1000, true)) {
+/*    if (!langdbfile.empty() && !file_exists (langdbfile) &&
+	macroname == "admin") {*/
+    if (!langdbfile.empty()) {
+      // no database -- create a database with an initial account
+      macroinfo.clear();
+      macroinfo.macroname = "language";
+      macroinfo.macrotext = "language"; // this needs to be extracted from langdbfile
+      return set_macro_info (langdbfile, macroname, macroinfo);
+    }
+    return false;
+  }
+
+  bool success = get_macro_info (langdb, macroname, macroinfo);
+  langdb.closedatabase();
+
+  return success;
+}
+
+// returns true on success
+bool set_macro_info (gdbmclass &langdb, const text_t &macroname,
+		    const macroinfo_t &macroinfo) {
+  infodbclass info;
+  info["macroname"] = macroinfo.macroname;
+  info["macrotext"] = macroinfo.macrotext;
+
+  return langdb.setinfo (macroname, info);
+}
+
+bool set_macro_info (const text_t &langdbfile, const text_t &macroname,
+		    const macroinfo_t &macroinfo) {
+  gdbmclass langdb;
+  if (!langdb.opendatabase(langdbfile, GDBM_WRCREAT, 1000, true)) return false;
+  
+  bool success = set_macro_info (langdb, macroname, macroinfo);
+  langdb.closedatabase();
+  
+  return success;
+}
Index: /trunk/gsdl/src/recpt/langdb.h
===================================================================
--- /trunk/gsdl/src/recpt/langdb.h	(revision 3632)
+++ /trunk/gsdl/src/recpt/langdb.h	(revision 3632)
@@ -0,0 +1,70 @@
+/**********************************************************************
+ *
+ * userdb.h -- functions to handle a language macro database
+ * Copyright (C) 1999  DigiLib Systems Limited, New Zealand
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *********************************************************************/
+
+
+#ifndef LANGDB_H
+#define LANGDB_H
+
+#include "infodbclass.h"
+
+
+// these functions deal with language macro databases that are already open
+// they should have been opened with gdbmclass::opendatabase
+// as soon as the databases are finished with they should be closed with
+// gdbmclass::closedatabase so that another process can access the database
+//
+// some of the functions need the databases opened with write access, an
+// appropriate call would be something like:
+//
+//   success = keydb.opendatabase (keyfile, GDBM_WRCREAT, 1000);
+
+
+// information about a single macro from a 'language'.dm file
+struct macroinfo_t {
+  void clear ();
+  macroinfo_t () {clear();}
+  macroinfo_t &operator=(const macroinfo_t &x);
+  
+  text_t macroname;
+  text_t macrotext;
+};
+
+// functions dealing with language macro databases
+
+// returns true on success (in which case userinfo will contain
+// the information for this user)
+bool get_macro_info (gdbmclass &langdb, const text_t &macroname,
+		     macroinfo_t &macroinfo);
+bool get_macro_info (const text_t &langdbfile, const text_t &macroname,
+		     macroinfo_t &macroinfo);
+
+// returns true on success
+bool set_macro_info (gdbmclass &langdb, const text_t &macroname,
+		     const macroinfo_t &macroinfo);
+bool set_macro_info (const text_t &langdbfile, const text_t &macroname,
+		     const macroinfo_t &macroinfo);
+
+
+#endif
Index: /trunk/gsdl/src/recpt/librarymain.cpp
===================================================================
--- /trunk/gsdl/src/recpt/librarymain.cpp	(revision 3631)
+++ /trunk/gsdl/src/recpt/librarymain.cpp	(revision 3632)
@@ -57,4 +57,7 @@
 #include "browseaction.h"
 #include "phindaction.h"
+#if defined(USE_LANGACTION)
+#include "langaction.h"
+#endif
 
 #include "browserclass.h"
@@ -155,4 +158,9 @@
   recpt.add_action(&aphindaction);
 
+#if defined(USE_LANGACTION)
+  langaction alangaction;
+  recpt.add_action(&alangaction);
+#endif
+
   // list of browsers
   vlistbrowserclass avlistbrowserclass;
