Changeset 24627

Show
Ignore:
Timestamp:
21.09.2011 16:52:59 (8 years ago)
Author:
anna
Message:

tidied up gti.pl

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • main/trunk/greenstone2/bin/script/gti.pl

    r24362 r24627  
    3333} 
    3434 
     35 
    3536use iso639; 
    3637use strict; 
    3738use util; 
    3839 
    39  
    40 #my $anonymous_cvs_root = ":pserver:cvs_anon\@cvs.scms.waikato.ac.nz:2402/usr/local/global-cvs/gsdl-src"; 
    41 #my $anonymous_svn_root = "http://http://svn.greenstone.org/gsdl/trunk/"; 
    4240my $gsdl_root_directory = "$ENV{'GSDLHOME'}"; 
    4341my $gti_log_file = &util::filename_cat($gsdl_root_directory, "etc", "gti.log"); 
     
    4543 
    4644my $gti_translation_files = 
    47     [ # Greenstone macrofiles 
    48       { 'key' => "coredm", 
     45[ # Greenstone macrofiles 
     46{ 'key' => "coredm", 
    4947    'file_type' => "macrofile", 
    5048    'source_file' => "macros/english.dm", 
    5149    'target_file' => "macros/{bn:bengali;fa:farsi;gd:gaelic;id:indo;lv:latvian;pt-br:port-br;pt-pt:port-pt;zh-tr:chinese-trad;iso_639_1_target_language_name}.dm" }, 
    52       { 'key' => "auxdm", 
     50 
     51{ 'key' => "auxdm", 
    5352    'file_type' => "macrofile", 
    5453    'source_file' => "macros/english2.dm", 
    5554    'target_file' => "macros/{bn:bengali;fa:farsi;gd:gaelic;id:indo;lv:latvian;pt-br:port-br;pt-pt:port-pt;zh-tr:chinese-trad;iso_639_1_target_language_name}2.dm" }, 
    5655 
    57       # GLI dictionary 
    58       { 'key' => "glidict", 
     56# GLI dictionary 
     57{ 'key' => "glidict", 
    5958    'file_type' => "resource_bundle", 
    6059    'source_file' => "gli/classes/dictionary.properties", 
    6160    'target_file' => "gli/classes/dictionary_{target_language_code}.properties" }, 
    6261 
    63       # GLI help 
    64       { 'key' => "glihelp", 
     62# GLI help 
     63{ 'key' => "glihelp", 
    6564    'file_type' => "greenstone_xml", 
    6665    'source_file' => "gli/help/en/help.xml", 
    6766    'target_file' => "gli/help/{target_language_code}/help.xml" }, 
    6867 
    69       # Greenstone Perl modules 
    70       { 'key' => "perlmodules", 
     68# Greenstone Perl modules 
     69{ 'key' => "perlmodules", 
    7170    'file_type' => "resource_bundle", 
    7271    'source_file' => "perllib/strings.properties", 
    7372    'target_file' => "perllib/strings_{target_language_code}.properties" }, 
    7473 
    75       # Greenstone tutorial exercises 
    76       # { 'key' => "tutorials", 
    77     # 'file_type' => "greenstone_xml", 
    78     # 'source_file' => "gsdl-documentation/tutorials/xml-source/tutorial_en.xml", 
    79     # 'target_file' => "gsdl-documentation/tutorials/xml-source/tutorial_{target_language_code}.xml" }, 
    80  
    81       # new Greenstone.org 
    82       { 'key' => "greenorg", 
    83         'file_type' => "resource_bundle", 
    84         'source_file' => "greenstoneorg/website/classes/Gsc.properties", 
    85         'target_file' => "greenstoneorg/website/classes/Gsc_{iso_639_1_target_language_name}.properties"  
    86     # 'file_type' => "macrofile", 
    87     # 'source_file' => "greenorg/macros/english.dm", 
    88     # 'target_file' => "greenorg/macros/{iso_639_1_target_language_name}.dm"  
    89       } 
    90  
    91       # { 'key' => "gs3interface", 
    92     #'file_type' => "resource_bundle", 
    93     #'source_file' => "greenstone3", 
    94     #'target_file' => "greenstone3" 
    95       #} 
    96     ]; 
     74# Greenstone tutorial exercises 
     75# { 'key' => "tutorials", 
     76# 'file_type' => "greenstone_xml", 
     77# 'source_file' => "gsdl-documentation/tutorials/xml-source/tutorial_en.xml", 
     78# 'target_file' => "gsdl-documentation/tutorials/xml-source/tutorial_{target_language_code}.xml" }, 
     79 
     80# new Greenstone.org 
     81{ 'key' => "greenorg", 
     82    'file_type' => "resource_bundle", 
     83    'source_file' => "greenstoneorg/website/classes/Gsc.properties", 
     84    'target_file' => "greenstoneorg/website/classes/Gsc_{target_language_code}.properties"  
     85} 
     86 
     87# { 'key' => "gs3interface", 
     88#'file_type' => "resource_bundle", 
     89#'source_file' => "greenstone3", 
     90#'target_file' => "greenstone3" 
     91#} 
     92]; 
    9793 
    9894my @gs3_interface_files = ("AbstractBrowse", "AbstractGS2FieldSearch", "Authentication", "CrossCollectionSearch", "GATEServices", "GS2Construct", "GS2LuceneSearch", "interface_default", "interface_nzdl", "IViaSearch", "LuceneSearch", "MapRetrieve", "MapSearch", "metadata_names", "PhindPhraseBrowse", "QBRWebServicesHelp", "Visualizer"); 
     
    105101    my @gti_command_arguments = @_; 
    106102    my $module = $_[1]; 
    107  
     103     
    108104    # Open the GTI log file for appending, or write to STDERR if that fails 
    109105    if (!open(GTI_LOG, ">>$gti_log_file")) { 
    110     open(GTI_LOG, ">&STDERR"); 
    111     } 
    112  
     106        open(GTI_LOG, ">&STDERR"); 
     107    } 
     108     
    113109    # Log the command that launched this script 
    114110    &log_message("Command: $0 @ARGV"); 
    115  
     111     
    116112    # Check that a command was supplied 
    117113    if (!$gti_command) { 
    118     &throw_fatal_error("Missing command."); 
     114        &throw_fatal_error("Missing command."); 
    119115    }       
    120  
     116     
    121117    # Process the command 
    122118    if ($gti_command =~ /^get-all-chunks$/i) { 
    123     # Check that GS3 interface is the target 
    124     if ($module eq "gs3interface") {        
    125         print &get_all_chunks_for_gs3(@gti_command_arguments); 
    126     } else { 
    127         print &get_all_chunks(@gti_command_arguments); 
    128     } 
    129     } 
    130     if ($gti_command =~ /^get-first-n-chunks-requiring-work$/i) { 
    131     if ($module eq "gs3interface") {        
    132         print &get_first_n_chunks_requiring_work_for_gs3(@gti_command_arguments); 
    133     } else { 
    134         print &get_first_n_chunks_requiring_work(@gti_command_arguments); 
    135     } 
    136     } 
    137     if ($gti_command =~ /^get-language-status$/i) { 
    138     print &get_language_status(@gti_command_arguments);        
    139     } 
    140     if ($gti_command =~ /^search-chunks$/i) { 
    141     print &search_chunks(@gti_command_arguments); 
    142     } 
    143     if ($gti_command =~ /^submit-translations$/i) { 
    144     # This command cannot produce any output since it reads input 
    145     &submit_translations(@gti_command_arguments); 
    146     } 
    147     if ($gti_command =~ /^create-glihelp-zip-file$/i) { 
    148     # This command cannot produce any output since it reads input 
    149     &create_glihelp_zip_file(@gti_command_arguments); 
    150     } 
    151 #    else { 
    152     # The command was not recognized 
    153     #&throw_fatal_error("Unknown command \"$gti_command\"."); 
    154     #} 
     119        # Check that GS3 interface is the target 
     120        if ($module eq "gs3interface") {        
     121            print &get_all_chunks_for_gs3(@gti_command_arguments); 
     122        } else { 
     123            print &get_all_chunks(@gti_command_arguments); 
     124        } 
     125    } 
     126    elsif ($gti_command =~ /^get-first-n-chunks-requiring-work$/i) { 
     127        if ($module eq "gs3interface") {        
     128            print &get_first_n_chunks_requiring_work_for_gs3(@gti_command_arguments); 
     129        } else { 
     130            print &get_first_n_chunks_requiring_work(@gti_command_arguments); 
     131        } 
     132    } 
     133    elsif ($gti_command =~ /^get-language-status$/i) { 
     134        print &get_language_status(@gti_command_arguments);        
     135    } 
     136    elsif ($gti_command =~ /^search-chunks$/i) { 
     137        print &search_chunks(@gti_command_arguments); 
     138    } 
     139    elsif ($gti_command =~ /^submit-translations$/i) { 
     140        # This command cannot produce any output since it reads input 
     141        &submit_translations(@gti_command_arguments); 
     142    } 
     143    elsif ($gti_command =~ /^create-glihelp-zip-file$/i) { 
     144        # This command cannot produce any output since it reads input 
     145        &create_glihelp_zip_file(@gti_command_arguments); 
     146    } 
     147    else { 
     148        # The command was not recognized 
     149        &throw_fatal_error("Unknown command \"$gti_command\"."); 
     150    } 
    155151} 
    156152 
     
    159155{ 
    160156    my $error_message = shift(@_); 
    161  
     157     
    162158    # Write an XML error response 
    163159    print "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; 
     
    165161    print "  <GTIError time=\"" . time() . "\">" . $error_message . "</GTIError>\n"; 
    166162    print "</GTIResponse>\n"; 
    167  
     163     
    168164    # Log the error message, then die 
    169165    &log_message("Error: $error_message"); 
     
    185181    # The key of the file to translate (ensure it is lowercase) 
    186182    my $translation_file_key = lc(shift(@_)); 
    187  
     183     
    188184    # Check that the necessary arguments were supplied 
    189185    if (!$target_language_code || !$translation_file_key) { 
    190     &throw_fatal_error("Missing command argument."); 
    191     } 
    192  
     186        &throw_fatal_error("Missing command argument."); 
     187    } 
     188     
    193189    # Get (and check) the translation configuration 
    194190    my ($source_file, $target_file, $translation_file_type) 
    195191    = &get_translation_configuration($target_language_code, $translation_file_key); 
    196  
     192     
    197193    # Parse the source language and target language files 
    198194    my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
     
    203199    my @target_file_lines = &read_file_lines($target_file_path); 
    204200    my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
    205  
     201     
    206202    # Filter out any automatically translated chunks 
    207203    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    208     if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
    209         delete $source_file_key_to_line_mapping{$chunk_key}; 
    210         delete $target_file_key_to_line_mapping{$chunk_key}; 
    211     } 
    212     } 
    213  
     204        if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
     205            delete $source_file_key_to_line_mapping{$chunk_key}; 
     206            delete $target_file_key_to_line_mapping{$chunk_key}; 
     207        } 
     208    } 
     209     
    214210    my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    215211    my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    216212    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping))); 
    217213    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping))); 
    218  
     214     
    219215    my %source_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($source_file, \@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    220216    my %target_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($target_file, \@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    221  
     217     
    222218    my $xml_response = &create_xml_response_for_all_chunks($translation_file_key, $target_file, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping, \%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping);    
    223219     
     
    234230    # The number of chunks to return (defaults to one if not specified) 
    235231    my $num_chunks_to_return = shift(@_) || "1"; 
    236  
     232     
    237233    # Check that the necessary arguments were supplied 
    238234    if (!$target_language_code || !$translation_file_key) { 
    239     &throw_fatal_error("Missing command argument."); 
    240     } 
    241  
     235        &throw_fatal_error("Missing command argument."); 
     236    } 
     237     
    242238    # Get (and check) the translation configuration 
    243239    my ($source_file, $target_file, $translation_file_type) 
    244240    = &get_translation_configuration($target_language_code, $translation_file_key); 
    245  
     241     
    246242    # Parse the source language and target language files 
    247243    my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
     
    252248    my @target_file_lines = &read_file_lines($target_file_path); 
    253249    my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
    254  
     250     
    255251    # Filter out any automatically translated chunks 
    256252    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    257     if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
    258         delete $source_file_key_to_line_mapping{$chunk_key}; 
    259         delete $target_file_key_to_line_mapping{$chunk_key}; 
    260     } 
    261     } 
    262  
     253        if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
     254            delete $source_file_key_to_line_mapping{$chunk_key}; 
     255            delete $target_file_key_to_line_mapping{$chunk_key}; 
     256        } 
     257    } 
     258     
    263259    my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    264260    my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    265261    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping))); 
    266262    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping))); 
    267  
     263     
    268264    # Determine the target file chunks requiring translation 
    269265    my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping); 
    270266    &log_message("Number of target chunks requiring translation: " . scalar(@target_file_keys_requiring_translation)); 
    271  
     267     
    272268    # Determine the target file chunks requiring updating 
    273269    my %source_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($source_file, \@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
     
    275271    my @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping); 
    276272    &log_message("Number of target chunks requiring updating: " . scalar(@target_file_keys_requiring_updating)); 
    277  
     273     
    278274    my $xml_response = &create_xml_response_for_chunks_requiring_work($translation_file_key, $target_file, scalar(keys(%source_file_key_to_text_mapping)), \@target_file_keys_requiring_translation, \@target_file_keys_requiring_updating, $num_chunks_to_return, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping, \%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping);    
    279275     
     
    286282    # The code of the target language (ensure it is lowercase) 
    287283    my $target_language_code = lc(shift(@_)); 
    288  
     284     
    289285    # Check that the necessary arguments were supplied 
    290286    if (!$target_language_code) { 
    291     &throw_fatal_error("Missing command argument."); 
    292     } 
    293  
     287        &throw_fatal_error("Missing command argument."); 
     288    } 
     289     
    294290    # Form an XML response to the command 
    295291    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; 
    296292    $xml_response .= "<GTIResponse>\n"; 
    297293    $xml_response .= "  <LanguageStatus code=\"$target_language_code\">\n"; 
    298  
     294     
    299295    foreach my $translation_file (@$gti_translation_files) {     
    300     my ($num_source_chunks, $num_target_chunks, $num_chunks_requiring_translation, $num_chunks_requiring_updating) = 0; 
    301     my $target_file_name = ""; 
    302      
    303     if ($translation_file->{'key'} eq "gs3interface") { 
    304         my (%source_file_key_to_text_mapping, %target_file_key_to_text_mapping, %source_file_key_to_last_update_date_mapping, %target_file_key_to_last_update_date_mapping ) = (); 
    305         &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping, \%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping );     
    306          
    307         my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);      
    308         my @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping); 
    309  
    310         $num_source_chunks = scalar(keys(%source_file_key_to_text_mapping)); 
    311         $num_target_chunks = scalar(keys(%target_file_key_to_text_mapping)); 
    312         $num_chunks_requiring_translation = scalar(@target_file_keys_requiring_translation); 
    313         $num_chunks_requiring_updating = scalar(@target_file_keys_requiring_updating); 
    314     } 
    315     else { 
    316         # Get (and check) the translation configuration 
    317         my ($source_file, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file->{'key'}); 
    318         $target_file_name = $target_file; 
    319  
    320         # Parse the source language and target language files 
    321         my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
    322         my @source_file_lines = &read_file_lines($source_file_path); 
    323         my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
    324  
    325         my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
    326         my @target_file_lines = &read_file_lines($target_file_path); 
    327         my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
    328  
    329         # Filter out any automatically translated chunks 
    330         foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    331         if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
    332             delete $source_file_key_to_line_mapping{$chunk_key}; 
    333             delete $target_file_key_to_line_mapping{$chunk_key}; 
    334         } 
    335         } 
    336  
    337         my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    338         my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    339  
    340         # Determine the target file chunks requiring translation 
    341         my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);      
    342  
    343         # Determine the target file chunks requiring updating 
    344         my @target_file_keys_requiring_updating = (); 
    345         if (-e $target_file_path) { 
    346         my %source_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($source_file, \@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    347         my %target_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($target_file, \@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    348         @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping);       
    349         } 
    350  
    351         $num_source_chunks = scalar(keys(%source_file_key_to_text_mapping)); 
    352         $num_target_chunks = scalar(keys(%target_file_key_to_text_mapping)); 
    353         $num_chunks_requiring_translation = scalar(@target_file_keys_requiring_translation); 
    354         $num_chunks_requiring_updating = scalar(@target_file_keys_requiring_updating); 
    355     } 
    356      
    357     &log_message("Status of " . $translation_file->{'key'}); 
    358     &log_message("Number of source chunks: " . $num_source_chunks); 
    359     &log_message("Number of target chunks: " . $num_target_chunks); 
    360     &log_message("Number of target chunks requiring translation: " . $num_chunks_requiring_translation); 
    361     &log_message("Number of target chunks requiring updating: " . $num_chunks_requiring_updating); 
    362  
    363     $xml_response .= "    <TranslationFile" 
     296        my ($num_source_chunks, $num_target_chunks, $num_chunks_requiring_translation, $num_chunks_requiring_updating) = 0; 
     297        my $target_file_name = ""; 
     298         
     299        if ($translation_file->{'key'} eq "gs3interface") { 
     300            my (%source_file_key_to_text_mapping, %target_file_key_to_text_mapping, %source_file_key_to_last_update_date_mapping, %target_file_key_to_last_update_date_mapping ) = (); 
     301            &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping, \%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping );     
     302             
     303            my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);      
     304            my @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping); 
     305             
     306            $num_source_chunks = scalar(keys(%source_file_key_to_text_mapping)); 
     307            $num_target_chunks = scalar(keys(%target_file_key_to_text_mapping)); 
     308            $num_chunks_requiring_translation = scalar(@target_file_keys_requiring_translation); 
     309            $num_chunks_requiring_updating = scalar(@target_file_keys_requiring_updating); 
     310        } 
     311        else { 
     312            # Get (and check) the translation configuration 
     313            my ($source_file, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file->{'key'}); 
     314            $target_file_name = $target_file; 
     315             
     316            # Parse the source language and target language files 
     317            my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
     318            my @source_file_lines = &read_file_lines($source_file_path); 
     319            my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
     320             
     321            my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
     322            my @target_file_lines = &read_file_lines($target_file_path); 
     323            my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
     324             
     325            # Filter out any automatically translated chunks 
     326            foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
     327                if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
     328                    delete $source_file_key_to_line_mapping{$chunk_key}; 
     329                    delete $target_file_key_to_line_mapping{$chunk_key}; 
     330                } 
     331            } 
     332             
     333            my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
     334            my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
     335             
     336            # Determine the target file chunks requiring translation 
     337            my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);      
     338             
     339            # Determine the target file chunks requiring updating 
     340            my @target_file_keys_requiring_updating = (); 
     341            if (-e $target_file_path) { 
     342                my %source_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($source_file, \@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
     343                my %target_file_key_to_last_update_date_mapping = &build_key_to_last_update_date_mapping($target_file, \@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
     344                @target_file_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_file_key_to_last_update_date_mapping, \%target_file_key_to_last_update_date_mapping);       
     345            } 
     346             
     347            $num_source_chunks = scalar(keys(%source_file_key_to_text_mapping)); 
     348            $num_target_chunks = scalar(keys(%target_file_key_to_text_mapping)); 
     349            $num_chunks_requiring_translation = scalar(@target_file_keys_requiring_translation); 
     350            $num_chunks_requiring_updating = scalar(@target_file_keys_requiring_updating); 
     351        } 
     352         
     353        &log_message("Status of " . $translation_file->{'key'}); 
     354        &log_message("Number of source chunks: " . $num_source_chunks); 
     355        &log_message("Number of target chunks: " . $num_target_chunks); 
     356        &log_message("Number of target chunks requiring translation: " . $num_chunks_requiring_translation); 
     357        &log_message("Number of target chunks requiring updating: " . $num_chunks_requiring_updating); 
     358         
     359        $xml_response .= "    <TranslationFile" 
    364360        . " key=\"" . $translation_file->{'key'} . "\"" 
    365361        . " target_file_path=\"" . $target_file_name . "\"" 
     
    368364        . " num_chunks_requiring_updating=\"" . $num_chunks_requiring_updating . "\"\/>\n"; 
    369365    } 
    370  
     366     
    371367    $xml_response .= "  </LanguageStatus>\n"; 
    372  
     368     
    373369    $xml_response .= "</GTIResponse>\n"; 
    374370    return $xml_response; 
     
    384380    # The query string 
    385381    my $query_string = join(' ', @_); 
    386  
     382     
    387383    # Check that the necessary arguments were supplied 
    388384    if (!$target_language_code || !$translation_file_key || !$query_string) { 
    389     &throw_fatal_error("Missing command argument."); 
    390     } 
    391  
     385        &throw_fatal_error("Missing command argument."); 
     386    } 
     387     
    392388    my ($source_file, $target_file, $translation_file_type) = (); 
    393389    my %source_file_key_to_text_mapping = (); 
     
    396392     
    397393    if ($translation_file_key ne "gs3interface") { 
    398     # Get (and check) the translation configuration 
    399     ($source_file, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file_key); 
    400  
    401     # Parse the source language and target language files 
    402     my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
    403     my @source_file_lines = &read_file_lines($source_file_path); 
    404     my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
    405  
    406     my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
    407     my @target_file_lines = &read_file_lines($target_file_path); 
    408     my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
    409  
    410     # Filter out any automatically translated chunks 
    411     foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    412         if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
    413         delete $source_file_key_to_line_mapping{$chunk_key}; 
    414         delete $target_file_key_to_line_mapping{$chunk_key}; 
    415         } 
    416     } 
    417  
    418     %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    419     %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
     394        # Get (and check) the translation configuration 
     395        ($source_file, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file_key); 
     396         
     397        # Parse the source language and target language files 
     398        my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
     399        my @source_file_lines = &read_file_lines($source_file_path); 
     400        my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
     401         
     402        my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
     403        my @target_file_lines = &read_file_lines($target_file_path); 
     404        my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
     405         
     406        # Filter out any automatically translated chunks 
     407        foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
     408            if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
     409                delete $source_file_key_to_line_mapping{$chunk_key}; 
     410                delete $target_file_key_to_line_mapping{$chunk_key}; 
     411            } 
     412        } 
     413         
     414        %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
     415        %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    420416    } 
    421417    else { 
    422     # Not needed in this case 
    423     my (%source_file_key_to_gti_command_mapping, %target_file_key_to_gti_command_mapping) = (); 
    424     &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping, 
    425                  \%source_file_key_to_gti_command_mapping, \%target_file_key_to_gti_command_mapping); 
    426     } 
    427  
     418        # Not needed in this case 
     419        my (%source_file_key_to_gti_command_mapping, %target_file_key_to_gti_command_mapping) = (); 
     420        &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping, 
     421        \%source_file_key_to_gti_command_mapping, \%target_file_key_to_gti_command_mapping); 
     422    } 
     423     
    428424    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping))); 
    429425    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping))); 
    430  
     426     
    431427    # Determine the target file chunks matching the query 
    432428    my @target_file_keys_matching_query = (); 
    433429    foreach my $chunk_key (keys(%target_file_key_to_text_mapping)) { 
    434     my $target_file_text = $target_file_key_to_text_mapping{$chunk_key}; 
    435     if ($target_file_text =~ /$query_string/i) { 
    436         # &log_message("Chunk with key $chunk_key matches query."); 
    437         push(@target_file_keys_matching_query, $chunk_key); 
    438     } 
    439     } 
    440  
     430        my $target_file_text = $target_file_key_to_text_mapping{$chunk_key}; 
     431        if ($target_file_text =~ /$query_string/i) { 
     432            # &log_message("Chunk with key $chunk_key matches query."); 
     433            push(@target_file_keys_matching_query, $chunk_key); 
     434        } 
     435    } 
     436     
    441437    # Form an XML response to the command 
    442438    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; 
    443439    $xml_response .= "<GTIResponse>\n"; 
    444  
     440     
    445441    $xml_response .= "  <ChunksMatchingQuery size=\"" . scalar(@target_file_keys_matching_query) . "\">\n"; 
    446442    foreach my $chunk_key (@target_file_keys_matching_query) { 
    447     my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping{$chunk_key}); 
    448  
    449     $xml_response .= "    <Chunk key=\"$chunk_key\">\n"; 
    450     $xml_response .= "      <TargetFileText>$target_file_chunk_text</TargetFileText>\n"; 
    451     $xml_response .= "    </Chunk>\n"; 
     443        my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping{$chunk_key}); 
     444         
     445        $xml_response .= "    <Chunk key=\"$chunk_key\">\n"; 
     446        $xml_response .= "      <TargetFileText>$target_file_chunk_text</TargetFileText>\n"; 
     447        $xml_response .= "    </Chunk>\n"; 
    452448    } 
    453449    $xml_response .= "  </ChunksMatchingQuery>\n"; 
    454  
     450     
    455451    $xml_response .= "</GTIResponse>\n"; 
    456452    return $xml_response; 
     
    468464    # Whether to submit a target chunk even if it hasn't changed 
    469465    my $force_submission_flag = shift(@_); 
    470  
     466     
    471467    # Check that the necessary arguments were supplied 
    472468    if (!$target_language_code || !$translation_file_key || !$submitter_username) { 
    473     &log_message("Fatal error (but cannot be thrown): Missing command argument."); 
    474     die "\n"; 
     469        &log_message("Fatal error (but cannot be thrown): Missing command argument."); 
     470        die "\n"; 
    475471    } 
    476472     
     
    479475    my %target_file_key_to_text_mapping = (); 
    480476    my %target_file_key_to_gti_comment_mapping = (); 
    481  
     477     
    482478    my (@source_file_lines, @target_file_lines) = (); 
    483479    my ($source_file, $target_file, $translation_file_type); 
    484  
     480     
    485481     
    486482    if ($translation_file_key ne "gs3interface") { 
    487     # Get (and check) the translation configuration 
    488     ($source_file, $target_file, $translation_file_type) 
     483        # Get (and check) the translation configuration 
     484        ($source_file, $target_file, $translation_file_type) 
    489485        = &get_translation_configuration($target_language_code, $translation_file_key); 
    490  
    491     # Parse the source language and target language files 
    492     @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file)); 
    493     my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
    494     %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    495     %source_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);     
    496  
    497     @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file)); 
    498     my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
    499     %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    500     %target_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);     
     486         
     487        # Parse the source language and target language files 
     488        @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file)); 
     489        my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
     490        %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
     491        %source_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);     
     492         
     493        @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file)); 
     494        my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
     495        %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
     496        %target_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);     
    501497    }  
    502498    else { 
    503     &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping,  
    504                  \%source_file_key_to_gti_comment_mapping, \%target_file_key_to_gti_comment_mapping); 
     499        &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping,  
     500        \%source_file_key_to_gti_comment_mapping, \%target_file_key_to_gti_comment_mapping); 
    505501    } 
    506502    &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping))); 
    507503    &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping))); 
    508  
     504     
    509505    # Submission date 
    510506    my $day = (localtime)[3]; 
     
    512508    my $year = (localtime)[5] + 1900; 
    513509    my $submission_date = "$day-$month-$year"; 
    514  
     510     
    515511    open(SUBMISSION, "-"); 
    516512    my @submission_lines = <SUBMISSION>; 
    517513    close(SUBMISSION); 
    518  
     514     
    519515    # Remove any nasty carriage returns 
    520516    # &log_message("Submission:"); 
    521517    foreach my $submission_line (@submission_lines) { 
    522     $submission_line =~ s/\r$//; 
    523     #&log_message("  $submission_line"); 
    524     } 
    525  
     518        $submission_line =~ s/\r$//; 
     519        #&log_message("  $submission_line"); 
     520    } 
     521     
    526522    my %source_file_key_to_submission_mapping = (); 
    527523    my %target_file_key_to_submission_mapping = (); 
    528524    for (my $i = 0; $i < scalar(@submission_lines); $i++) { 
    529     # Read source file part of submission 
    530     if ($submission_lines[$i] =~ /^\<SourceFileText key=\"(.+)\"\>/) { 
    531         my $chunk_key = $1; 
    532  
    533         # Read the source file text 
    534         my $source_file_chunk_text = ""; 
    535         $i++; 
    536         while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/SourceFileText\>/) { 
    537         $source_file_chunk_text .= $submission_lines[$i]; 
    538         $i++; 
    539         } 
    540         $source_file_chunk_text =~ s/\n$//;  # Strip the extra newline character added 
    541         $source_file_chunk_text = &unmake_text_xml_safe($source_file_chunk_text); 
    542  
    543         #&log_message("Source file key: $chunk_key"); 
    544         #&log_message("Source file text: $source_file_chunk_text"); 
    545         $source_file_key_to_submission_mapping{$chunk_key} = $source_file_chunk_text; 
    546     } 
    547  
    548     # Read target file part of submission 
    549     if ($submission_lines[$i] =~ /^\<TargetFileText key=\"(.+)\"\>/) { 
    550         my $chunk_key = $1; 
    551  
    552         # Read the target file text 
    553         my $target_file_chunk_text = ""; 
    554         $i++; 
    555         while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/TargetFileText\>/) { 
    556         $target_file_chunk_text .= $submission_lines[$i]; 
    557         $i++; 
    558         } 
    559         $target_file_chunk_text =~ s/\n$//;  # Strip the extra newline character added 
    560         $target_file_chunk_text = &unmake_text_xml_safe($target_file_chunk_text); 
    561  
    562         #&log_message("Target file key: $chunk_key"); 
    563         #&log_message("Target file text: $target_file_chunk_text"); 
    564         $target_file_key_to_submission_mapping{$chunk_key} = $target_file_chunk_text; 
    565     } 
    566     } 
    567  
     525        # Read source file part of submission 
     526        if ($submission_lines[$i] =~ /^\<SourceFileText key=\"(.+)\"\>/) { 
     527            my $chunk_key = $1; 
     528             
     529            # Read the source file text 
     530            my $source_file_chunk_text = ""; 
     531            $i++; 
     532            while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/SourceFileText\>/) { 
     533                $source_file_chunk_text .= $submission_lines[$i]; 
     534                $i++; 
     535            } 
     536            $source_file_chunk_text =~ s/\n$//;  # Strip the extra newline character added 
     537            $source_file_chunk_text = &unmake_text_xml_safe($source_file_chunk_text); 
     538             
     539            #&log_message("Source file key: $chunk_key"); 
     540            #&log_message("Source file text: $source_file_chunk_text"); 
     541            $source_file_key_to_submission_mapping{$chunk_key} = $source_file_chunk_text; 
     542        } 
     543         
     544        # Read target file part of submission 
     545        if ($submission_lines[$i] =~ /^\<TargetFileText key=\"(.+)\"\>/) { 
     546            my $chunk_key = $1; 
     547             
     548            # Read the target file text 
     549            my $target_file_chunk_text = ""; 
     550            $i++; 
     551            while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/TargetFileText\>/) { 
     552                $target_file_chunk_text .= $submission_lines[$i]; 
     553                $i++; 
     554            } 
     555            $target_file_chunk_text =~ s/\n$//;  # Strip the extra newline character added 
     556            $target_file_chunk_text = &unmake_text_xml_safe($target_file_chunk_text); 
     557             
     558            #&log_message("Target file key: $chunk_key"); 
     559            #&log_message("Target file text: $target_file_chunk_text"); 
     560            $target_file_key_to_submission_mapping{$chunk_key} = $target_file_chunk_text; 
     561        } 
     562    } 
     563     
    568564    # ----------------------------------------- 
    569565    #   Validate the translation submissions 
    570566    # ----------------------------------------- 
    571  
     567     
    572568    # Check that the translations are valid 
    573569    foreach my $chunk_key (keys(%source_file_key_to_submission_mapping)) { 
    574     # Make sure the submitted chunk still exists in the source file 
    575     if (!defined($source_file_key_to_text_mapping{$chunk_key})) { 
    576         &log_message("Warning: Source chunk $chunk_key no longer exists (ignoring submission)."); 
    577         delete $source_file_key_to_submission_mapping{$chunk_key}; 
    578         delete $target_file_key_to_submission_mapping{$chunk_key}; 
    579         next; 
    580     } 
    581  
    582     # Make sure the submitted source chunk matches the source file chunk 
    583     if ($source_file_key_to_submission_mapping{$chunk_key} ne &unmake_text_xml_safe($source_file_key_to_text_mapping{$chunk_key})) { 
    584         &log_message("Warning: Source chunk $chunk_key has changed (ignoring submission)."); 
    585         &log_message("Submission source: $source_file_key_to_submission_mapping{$chunk_key}"); 
    586         &log_message("      Source text: $source_file_key_to_text_mapping{$chunk_key}"); 
    587         delete $source_file_key_to_submission_mapping{$chunk_key}; 
    588         delete $target_file_key_to_submission_mapping{$chunk_key}; 
    589         next; 
    590     } 
    591     } 
    592  
     570        # Make sure the submitted chunk still exists in the source file 
     571        if (!defined($source_file_key_to_text_mapping{$chunk_key})) { 
     572            &log_message("Warning: Source chunk $chunk_key no longer exists (ignoring submission)."); 
     573            delete $source_file_key_to_submission_mapping{$chunk_key}; 
     574            delete $target_file_key_to_submission_mapping{$chunk_key}; 
     575            next; 
     576        } 
     577         
     578        # Make sure the submitted source chunk matches the source file chunk 
     579        if ($source_file_key_to_submission_mapping{$chunk_key} ne &unmake_text_xml_safe($source_file_key_to_text_mapping{$chunk_key})) { 
     580            &log_message("Warning: Source chunk $chunk_key has changed (ignoring submission)."); 
     581            &log_message("Submission source: $source_file_key_to_submission_mapping{$chunk_key}"); 
     582            &log_message("      Source text: $source_file_key_to_text_mapping{$chunk_key}"); 
     583            delete $source_file_key_to_submission_mapping{$chunk_key}; 
     584            delete $target_file_key_to_submission_mapping{$chunk_key}; 
     585            next; 
     586        } 
     587    } 
     588     
    593589    # Apply the submitted translations 
    594590    foreach my $chunk_key (keys(%target_file_key_to_submission_mapping)) { 
    595     # Only apply the submission if it is a change, unless -force_submission has been specified 
    596     if ($force_submission_flag || !defined($target_file_key_to_text_mapping{$chunk_key}) || $target_file_key_to_submission_mapping{$chunk_key} ne $target_file_key_to_text_mapping{$chunk_key}) { 
    597         $target_file_key_to_text_mapping{$chunk_key} = $target_file_key_to_submission_mapping{$chunk_key}; 
    598         $target_file_key_to_gti_comment_mapping{$chunk_key} = "Updated $submission_date by $submitter_username"; 
    599     } 
     591        # Only apply the submission if it is a change, unless -force_submission has been specified 
     592        if ($force_submission_flag || !defined($target_file_key_to_text_mapping{$chunk_key}) || $target_file_key_to_submission_mapping{$chunk_key} ne $target_file_key_to_text_mapping{$chunk_key}) { 
     593            $target_file_key_to_text_mapping{$chunk_key} = $target_file_key_to_submission_mapping{$chunk_key}; 
     594            $target_file_key_to_gti_comment_mapping{$chunk_key} = "Updated $submission_date by $submitter_username"; 
     595        } 
    600596    } 
    601597     
    602598    if ($translation_file_key ne "gs3interface") { 
    603     eval "&write_translated_${translation_file_type}(\$source_file, \\\@source_file_lines, \\\%source_file_key_to_text_mapping, \$target_file, \\\@target_file_lines, \\\%target_file_key_to_text_mapping, \\\%target_file_key_to_gti_comment_mapping, \$target_language_code)"; 
     599        eval "&write_translated_${translation_file_type}(\$source_file, \\\@source_file_lines, \\\%source_file_key_to_text_mapping, \$target_file, \\\@target_file_lines, \\\%target_file_key_to_text_mapping, \\\%target_file_key_to_gti_comment_mapping, \$target_language_code)"; 
    604600    } else { 
    605     eval "&write_translated_gs3interface(\\\%source_file_key_to_text_mapping, \\\%target_file_key_to_text_mapping, \\\%target_file_key_to_gti_comment_mapping, \$target_language_code)"; 
     601        eval "&write_translated_gs3interface(\\\%source_file_key_to_text_mapping, \\\%target_file_key_to_text_mapping, \\\%target_file_key_to_gti_comment_mapping, \$target_language_code)"; 
    606602    } 
    607603} 
     
    614610     
    615611    &log_message("Creating GLI Help zip file for $target_language_code"); 
    616  
     612     
    617613    my ($source_file, $target_file, $translation_file_type) = &get_translation_data_for($target_language_code, $translation_file_key);     
    618614     
    619615    my $classpath = &util::filename_cat($gsdl_root_directory, "gti-lib"); 
    620616    if ( ! -e $classpath) { 
    621     &throw_fatal_error("$classpath doesn't exist! Need the files in this directory (ApplyXLST and its related files) to create the zip file for GLI Help"); 
     617        &throw_fatal_error("$classpath doesn't exist! Need the files in this directory (ApplyXLST and its related files) to create the zip file for GLI Help"); 
    622618    }     
    623619     
     
    627623    my $gen_many_html_xsl_filepath = &util::filename_cat($gli_help_directory, "gen-many-html.xsl"); 
    628624    if ( ! -e $gen_many_html_xsl_filepath) { 
    629     &throw_fatal_error("$gen_many_html_xsl_filepath doesn't exist! Need this file to create the zip file for GLI Help"); 
    630     } 
    631  
     625        &throw_fatal_error("$gen_many_html_xsl_filepath doesn't exist! Need this file to create the zip file for GLI Help"); 
     626    } 
     627     
    632628    my $gen_index_xml_xsl_filepath = &util::filename_cat($gli_help_directory, "gen-index-xml.xsl");    
    633629    my $split_script_filepath = &util::filename_cat($gli_help_directory, "splithelpdocument.pl");    
     
    635631    my $target_file_directory = &util::filename_cat($gli_help_directory, $target_language_code); 
    636632    $target_file_directory = $target_file_directory."/"; 
    637  
     633     
    638634    my $target_filepath = &util::filename_cat($gsdl_root_directory, $target_file); 
    639     my $perl_exec = &util::get_perl_exec(); 
    640     my $java_exec = "java"; 
    641     if(defined($ENV{'JAVA_HOME'}) && $ENV{'JAVA_HOME'} ne ""){ 
    642     $java_exec = &util::filename_cat($ENV{'JAVA_HOME'}, "bin", "java"); 
    643     } 
    644  
     635     
     636    my $perl_exec = &util::get_perl_exec(); 
     637    my $java_exec = "java"; 
     638    if(defined($ENV{'JAVA_HOME'}) && $ENV{'JAVA_HOME'} ne ""){ 
     639        $java_exec = &util::filename_cat($ENV{'JAVA_HOME'}, "bin", "java"); 
     640    } 
     641     
    645642    my $cmd = "$java_exec -cp $classpath:$classpath/xalan.jar ApplyXSLT $target_language_code $gen_many_html_xsl_filepath $target_filepath | \"$perl_exec\" -S $split_script_filepath $target_file_directory"; 
    646643    my $response = `$cmd`; 
    647     &log_message($cmd); 
    648     &log_message($response);     
    649     &log_message("Created HTML operational files"); 
    650      
     644         
    651645    $cmd = "$java_exec -cp $classpath:$classpath/xalan.jar ApplyXSLT $target_language_code $gen_index_xml_xsl_filepath $target_filepath > " . $target_file_directory . "help_index.xml"; # 2>/dev/null"; 
    652646    $response = `$cmd`; 
    653     &log_message($cmd); 
    654     &log_message($response);     
    655     &log_message("Created xml index file"); 
    656  
     647     
    657648    my $zip_file_path = "/greenstone/custom/gti/" . $target_language_code . "_GLIHelp.zip"; 
    658649    $cmd = "zip -rj $zip_file_path $target_file_directory -i \*.htm \*.xml"; 
    659650    $response = `$cmd`; 
    660     &log_message($cmd); 
    661     &log_message($response);     
    662     &log_message("Created the zip file"); 
    663651} 
    664652 
     
    670658    # Get the key of the file to translate 
    671659    my $translation_file_key = shift(@_); 
    672  
     660     
    673661    # Read the translation data from the gti.cfg file 
    674662    my ($source_file, $target_file, $translation_file_type) = 
    675663    &get_translation_data_for($target_language_code, $translation_file_key); 
    676  
     664     
    677665    # Check that the file to translate is defined in the gti.cfg file 
    678666    if (!$source_file || !$target_file || !$translation_file_type) { 
    679     &throw_fatal_error("Missing or incomplete specification for translation file \"$translation_file_key\" in gti.pl."); 
    680     } 
    681  
     667        &throw_fatal_error("Missing or incomplete specification for translation file \"$translation_file_key\" in gti.pl."); 
     668    } 
     669     
    682670    # Check that the source file exists 
    683671    my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file); 
    684672    if (!-e $source_file_path) { 
    685     &throw_fatal_error("Source file $source_file_path does not exist."); 
    686     } 
    687  
     673        &throw_fatal_error("Source file $source_file_path does not exist."); 
     674    } 
     675     
    688676    # Check that the source file is up to date 
    689677    # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist 
    690678    # unless ($translation_file_is_not_in_cvs) { 
    691679    #my $source_file_cvs_status = `cd $gsdl_root_directory; cvs -d $anonymous_cvs_root update $source_file 2>/dev/null`; 
    692         my $source_file_cvs_status = `cd $gsdl_root_directory; svn status $source_file 2>/dev/null`; 
     680    my $source_file_cvs_status = `cd $gsdl_root_directory; svn status $source_file 2>/dev/null`; 
    693681    if ($source_file_cvs_status =~ /^C /) { 
    694682        &throw_fatal_error("Source file $source_file_path conflicts with the repository."); 
     
    698686    } 
    699687    # } 
    700  
     688     
    701689    return ($source_file, $target_file, $translation_file_type); 
    702690} 
     
    706694{ 
    707695    my ($target_language_code, $translation_file_key) = @_; 
    708  
     696     
    709697    foreach my $translation_file (@$gti_translation_files) { 
    710     # If this isn't the correct translation file, move onto the next one 
    711     next if ($translation_file_key ne $translation_file->{'key'}); 
    712  
    713     # Resolve the target language file 
    714     my $target_language_file = $translation_file->{'target_file'}; 
    715     if ($target_language_file =~ /(\{.+\;.+\})/) { 
    716         my $unresolved_target_language_file_part = $1; 
    717  
    718         # Check for a special case for the target language code 
    719         if ($unresolved_target_language_file_part =~ /(\{|\;)$target_language_code:([^\;]+)(\;|\})/) { 
    720         my $resolved_target_language_file_part = $2; 
    721         $target_language_file =~ s/$unresolved_target_language_file_part/$resolved_target_language_file_part/; 
    722         } 
    723         # Otherwise use the last part as the default value 
    724         else { 
    725         my ($default_target_language_file_part) = $unresolved_target_language_file_part =~ /([^\;]+)\}/; 
    726         $target_language_file =~ s/$unresolved_target_language_file_part/\{$default_target_language_file_part\}/;            
     698        # If this isn't the correct translation file, move onto the next one 
     699        next if ($translation_file_key ne $translation_file->{'key'}); 
     700         
     701        # Resolve the target language file 
     702        my $target_language_file = $translation_file->{'target_file'}; 
     703        if ($target_language_file =~ /(\{.+\;.+\})/) { 
     704            my $unresolved_target_language_file_part = $1; 
     705             
     706            # Check for a special case for the target language code 
     707            if ($unresolved_target_language_file_part =~ /(\{|\;)$target_language_code:([^\;]+)(\;|\})/) { 
     708                my $resolved_target_language_file_part = $2; 
     709                $target_language_file =~ s/$unresolved_target_language_file_part/$resolved_target_language_file_part/; 
     710            } 
     711            # Otherwise use the last part as the default value 
     712            else { 
     713                my ($default_target_language_file_part) = $unresolved_target_language_file_part =~ /([^\;]+)\}/; 
     714            $target_language_file =~ s/$unresolved_target_language_file_part/\{$default_target_language_file_part\}/;            
    727715        } 
    728716    } 
    729  
     717     
    730718    # Resolve instances of {iso_639_1_target_language_name} 
    731719    my $iso_639_1_target_language_name = $iso639::fromiso639{$target_language_code}; 
    732720    $iso_639_1_target_language_name =~ tr/A-Z/a-z/ if $iso_639_1_target_language_name; 
    733721    $target_language_file =~ s/\{iso_639_1_target_language_name\}/$iso_639_1_target_language_name/g; 
    734  
     722     
    735723    # Resolve instances of {target_language_code} 
    736724    $target_language_file =~ s/\{target_language_code\}/$target_language_code/g; 
    737  
     725     
    738726    return ($translation_file->{'source_file'}, $target_language_file, $translation_file->{'file_type'}); 
    739     } 
    740  
    741     return (); 
     727} 
     728 
     729return (); 
    742730} 
    743731 
     
    746734{ 
    747735    my ($file_path) = @_; 
    748  
     736     
    749737    if (!open(FILE_IN, "<$file_path")) { 
    750     &log_message("Note: Could not open file $file_path."); 
    751     return (); 
     738        &log_message("Note: Could not open file $file_path."); 
     739        return (); 
    752740    } 
    753741    my @file_lines = <FILE_IN>; 
    754742    close(FILE_IN); 
    755  
     743     
    756744    return @file_lines; 
    757745} 
     
    768756{ 
    769757    my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_; 
    770  
     758     
    771759    my %key_to_text_mapping = (); 
    772760    foreach my $chunk_key (keys(%$key_to_line_mapping)) { 
    773     my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0]; 
    774     my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1]; 
    775  
    776     my $chunk_text = @$file_lines[$chunk_starting_line]; 
    777     for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) { 
    778         $chunk_text .= @$file_lines[$l]; 
    779     } 
    780  
    781     # Map from chunk key to text 
    782     eval "\$key_to_text_mapping{\${chunk_key}} = &import_chunk_from_${translation_file_type}(\$chunk_text)"; 
    783     } 
    784  
     761        my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0]; 
     762        my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1]; 
     763         
     764        my $chunk_text = @$file_lines[$chunk_starting_line]; 
     765        for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) { 
     766            $chunk_text .= @$file_lines[$l]; 
     767        } 
     768         
     769        # Map from chunk key to text 
     770        eval "\$key_to_text_mapping{\${chunk_key}} = &import_chunk_from_${translation_file_type}(\$chunk_text)"; 
     771    } 
     772     
    785773    return %key_to_text_mapping; 
    786774} 
     
    790778{ 
    791779    my ($file, $file_lines, $key_to_line_mapping, $translation_file_type) = @_; 
    792  
     780     
    793781    # If the files aren't in CVS then we can't tell anything about what needs updating 
    794782    # return () if ($translation_file_is_not_in_cvs); 
    795  
     783     
    796784    # Build a mapping from key to CVS date 
    797785    # Need to be careful with this mapping because the chunk keys won't necessarily all be valid 
    798786    my %key_to_cvs_date_mapping = &build_key_to_cvs_date_mapping($file, $translation_file_type); 
    799  
     787     
    800788    # Build a mapping from key to comment date 
    801789    my %key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping($file_lines, $key_to_line_mapping, $translation_file_type); 
    802  
     790     
    803791    # Build a mapping from key to last update date (the latter of the CVS date and comment date) 
    804792    my %key_to_last_update_date_mapping = (); 
    805793    foreach my $chunk_key (keys(%$key_to_line_mapping)) { 
    806     # Use the CVS date as a starting point 
    807     my $chunk_cvs_date = $key_to_cvs_date_mapping{$chunk_key}; 
    808     $key_to_last_update_date_mapping{$chunk_key} = $chunk_cvs_date; 
    809  
    810     # If a comment date exists and it is after the CVS date, use that instead 
     794        # Use the CVS date as a starting point 
     795        my $chunk_cvs_date = $key_to_cvs_date_mapping{$chunk_key}; 
     796        $key_to_last_update_date_mapping{$chunk_key} = $chunk_cvs_date; 
     797         
     798        # If a comment date exists and it is after the CVS date, use that instead 
    811799        # need to convert the comment date format to SVN format 
    812     my $chunk_gti_comment = $key_to_gti_comment_mapping{$chunk_key}; 
    813     if (defined($chunk_gti_comment) && $chunk_gti_comment =~ /(\d?\d-\D\D\D-\d\d\d\d)/) { 
    814         my $chunk_comment_date = $1;             
    815         # if the changes were made on 2009 Jan 27, ie. tidying up the GTI commands following each fragment,  
    816         # then should use the GTI comment date instead 
    817         # if ((!defined($chunk_cvs_date) || &is_date_after($chunk_comment_date, $chunk_cvs_date))) { 
    818         if ((!defined($chunk_cvs_date) || &is_date_after($chunk_comment_date, $chunk_cvs_date)  
    819          || (&is_date_after($chunk_cvs_date,$chunk_comment_date) && ($chunk_cvs_date eq "2009-01-27" || $chunk_cvs_date eq "2009-01-28")))) { 
    820         $key_to_last_update_date_mapping{$chunk_key} = $chunk_comment_date; 
    821          
    822         # &log_message("cvs date: $chunk_cvs_date, comment date: $chunk_comment_date"); 
    823         # die; 
    824         } 
    825     } 
    826     } 
    827  
     800        my $chunk_gti_comment = $key_to_gti_comment_mapping{$chunk_key}; 
     801        if (defined($chunk_gti_comment) && $chunk_gti_comment =~ /(\d?\d-\D\D\D-\d\d\d\d)/) { 
     802            my $chunk_comment_date = $1;            
     803            if ((!defined($chunk_cvs_date) || &is_date_after($chunk_comment_date, $chunk_cvs_date))) { 
     804                $key_to_last_update_date_mapping{$chunk_key} = $chunk_comment_date;          
     805            } 
     806        } 
     807    } 
     808     
    828809    return %key_to_last_update_date_mapping; 
    829810} 
     
    833814{ 
    834815    my ($filename, $translation_file_type) = @_; 
    835  
    836     # Use CVS to annotate each line of the file with the date it was last edited 
     816     
     817    # Use SVN to annotate each line of the file with the date it was last edited 
    837818    # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist 
    838     # my $cvs_annotated_file = `cd $gsdl_root_directory; cvs -d $anonymous_cvs_root annotate -F $filename 2>/dev/null`;     
    839     # my $cvs_annotated_file = `cd $gsdl_root_directory; export PATH=.:/research/lh92/programs/subversion/bin; svn annotate -v --force $filename`; 
    840     my $cvs_annotated_file = `cd $gsdl_root_directory; svn annotate -v $filename`; 
     819    my $cvs_annotated_file = `cd $gsdl_root_directory; svn annotate -v --force $filename 2>/dev/null`; 
    841820     
    842821    my @cvs_annotated_file_lines = split(/\n/, $cvs_annotated_file); 
    843  
     822     
    844823    my @cvs_annotated_file_lines_date = (); 
    845824    foreach my $cvs_annotated_file_line (@cvs_annotated_file_lines) { 
    846     # Extract the date from the CVS annotation at the front 
    847         # cvs format : 07-Jun-02 
    848         # svn format : 2007-07-16 
    849     # $cvs_annotated_file_line =~ s/^\S+\s+\(\S+\s+(\S+)\):\s//; 
     825        # Extract the date from the SVN annotation at the front 
     826        # svn format : 2007-07-16 
    850827        $cvs_annotated_file_line =~ s/^\s+\S+\s+\S+\s(\S+)//;  
    851828         
     
    859836    # Build a key to line mapping for the CVS annotated file, for matching the chunk key to the CVS date 
    860837    my %key_to_line_mapping = &build_key_to_line_mapping(\@cvs_annotated_file_lines, $translation_file_type); 
    861          
     838     
    862839    my %key_to_cvs_date_mapping = (); 
    863840    foreach my $chunk_key (keys(%key_to_line_mapping)) { 
    864     my $chunk_starting_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[0]; 
    865     my $chunk_finishing_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[1]; 
    866                  
    867     # Find the date this chunk was last edited, from the CVS annotation 
    868     my $chunk_date = $cvs_annotated_file_lines_date[$chunk_starting_line];         
    869     for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) { 
    870         if (&is_date_after($cvs_annotated_file_lines_date[$l], $chunk_date)) { 
    871         # This part of the chunk has been updated more recently 
    872         $chunk_date = $cvs_annotated_file_lines_date[$l]; 
    873          
    874         } 
    875     } 
    876  
    877     # Map from chunk key to CVS date 
    878     $key_to_cvs_date_mapping{$chunk_key} = $chunk_date; 
    879     } 
    880  
     841        my $chunk_starting_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[0]; 
     842        my $chunk_finishing_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[1]; 
     843         
     844        # Find the date this chunk was last edited, from the CVS annotation 
     845        my $chunk_date = $cvs_annotated_file_lines_date[$chunk_starting_line];         
     846        for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) { 
     847            if (&is_date_after($cvs_annotated_file_lines_date[$l], $chunk_date)) { 
     848                # This part of the chunk has been updated more recently 
     849                $chunk_date = $cvs_annotated_file_lines_date[$l]; 
     850                 
     851            } 
     852        } 
     853         
     854        # Map from chunk key to CVS date 
     855        $key_to_cvs_date_mapping{$chunk_key} = $chunk_date; 
     856    } 
     857     
    881858    return %key_to_cvs_date_mapping; 
    882859} 
     
    886863{ 
    887864    my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_; 
    888  
     865     
    889866    my %key_to_gti_comment_mapping = (); 
    890867    foreach my $chunk_key (keys(%$key_to_line_mapping)) { 
    891     my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0]; 
    892     my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1]; 
    893  
    894     my $chunk_text = @$file_lines[$chunk_starting_line]; 
    895     for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) { 
    896         $chunk_text .= @$file_lines[$l]; 
    897     } 
    898  
    899     # Map from chunk key to GTI comment 
    900     my $chunk_gti_comment; 
    901     eval "\$chunk_gti_comment = &get_${translation_file_type}_chunk_gti_comment(\$chunk_text)"; 
    902     $key_to_gti_comment_mapping{$chunk_key} = $chunk_gti_comment if (defined($chunk_gti_comment)); 
    903     } 
    904  
     868        my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0]; 
     869        my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1]; 
     870         
     871        my $chunk_text = @$file_lines[$chunk_starting_line]; 
     872        for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) { 
     873            $chunk_text .= @$file_lines[$l]; 
     874        } 
     875         
     876        # Map from chunk key to GTI comment 
     877        my $chunk_gti_comment; 
     878        eval "\$chunk_gti_comment = &get_${translation_file_type}_chunk_gti_comment(\$chunk_text)"; 
     879        $key_to_gti_comment_mapping{$chunk_key} = $chunk_gti_comment if (defined($chunk_gti_comment)); 
     880    } 
     881     
    905882    return %key_to_gti_comment_mapping; 
    906883} 
     
    911888    my $source_file_key_to_text_mapping = shift(@_); 
    912889    my $target_file_key_to_text_mapping = shift(@_); 
    913  
     890     
    914891    # Chunks needing translation are those in the source file with no translation in the target file 
    915892    my @target_file_keys_requiring_translation = (); 
    916893    foreach my $chunk_key (keys(%$source_file_key_to_text_mapping)) { 
    917     if ($source_file_key_to_text_mapping->{$chunk_key} && !$target_file_key_to_text_mapping->{$chunk_key}) { 
    918         # &log_message("Chunk with key $chunk_key needs translating."); 
    919         push(@target_file_keys_requiring_translation, $chunk_key); 
    920     } 
    921     } 
    922  
     894        if ($source_file_key_to_text_mapping->{$chunk_key} && !$target_file_key_to_text_mapping->{$chunk_key}) { 
     895            # &log_message("Chunk with key $chunk_key needs translating."); 
     896            push(@target_file_keys_requiring_translation, $chunk_key); 
     897        } 
     898    } 
     899     
    923900    return @target_file_keys_requiring_translation; 
    924901} 
     
    929906    my $source_file_key_to_last_update_date_mapping = shift(@_); 
    930907    my $target_file_key_to_last_update_date_mapping = shift(@_); 
    931  
     908     
    932909    # Chunks needing updating are those in the target file that have been more recently edited in the source file 
    933910    my @target_file_keys_requiring_updating = (); 
    934911    foreach my $chunk_key (keys(%$source_file_key_to_last_update_date_mapping)) { 
    935     my $source_chunk_last_update_date = $source_file_key_to_last_update_date_mapping->{$chunk_key}; 
    936     my $target_chunk_last_update_date = $target_file_key_to_last_update_date_mapping->{$chunk_key}; 
     912        my $source_chunk_last_update_date = $source_file_key_to_last_update_date_mapping->{$chunk_key}; 
     913        my $target_chunk_last_update_date = $target_file_key_to_last_update_date_mapping->{$chunk_key}; 
    937914         
    938915        # print "key: $chunk_key\nsource date : $source_chunk_last_update_date\ntarget date : $target_chunk_last_update_date\nafter? ". &is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date) . "\n\n";         
    939                      
     916         
    940917        if (defined($target_chunk_last_update_date) && &is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) { 
    941         # &log_message("Chunk with key $chunk_key needs updating."); 
    942         push(@target_file_keys_requiring_updating, $chunk_key); 
    943     } 
    944     } 
    945  
     918            # &log_message("Chunk with key $chunk_key needs updating."); 
     919            push(@target_file_keys_requiring_updating, $chunk_key); 
     920        } 
     921    } 
     922     
    946923    return @target_file_keys_requiring_updating; 
    947924} 
     
    984961    my ($date1, $date2) = @_; 
    985962    my %months = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr",  4, "May",  5, "Jun",  6, 
    986           "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12); 
    987  
     963    "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12); 
     964     
    988965    if(!defined $date1) { 
    989966        return 1; 
    990967    } 
    991  
     968     
    992969    my @date1parts = split(/-/, $date1); 
    993970    my @date2parts = split(/-/, $date2); 
    994  
     971     
    995972    # Compare year - nasty because we have rolled over into a new century 
    996973    my $year1 = $date1parts[2]; 
     
    1002979        $year2 += 2000; 
    1003980    } 
    1004  
     981     
    1005982    # Compare year 
    1006983    if ($year1 > $year2) { 
    1007     return 1; 
     984        return 1; 
    1008985    } 
    1009986    elsif ($year1 == $year2) { 
    1010     # Year is the same, so compare month 
    1011     if ($months{$date1parts[1]} > $months{$date2parts[1]}) { 
    1012         return 1; 
    1013     } 
    1014     elsif ($months{$date1parts[1]} == $months{$date2parts[1]}) { 
    1015         # Month is the same, so compare day 
    1016         if ($date1parts[0] > $date2parts[0]) { 
     987        # Year is the same, so compare month 
     988        if ($months{$date1parts[1]} > $months{$date2parts[1]}) { 
     989            return 1; 
     990        } 
     991        elsif ($months{$date1parts[1]} == $months{$date2parts[1]}) { 
     992            # Month is the same, so compare day 
     993            if ($date1parts[0] > $date2parts[0]) { 
     994                return 1; 
     995            } 
     996        } 
     997    } 
     998     
     999    return 0; 
     1000} 
     1001 
     1002sub is_date_after 
     1003{ 
     1004    my ($date1, $date2) = @_; 
     1005     
     1006    if(!defined $date1) { 
    10171007        return 1; 
    1018         } 
    1019     } 
    1020     } 
    1021  
    1022     return 0; 
    1023 } 
    1024  
    1025 sub is_date_after 
    1026 { 
    1027     my ($date1, $date2) = @_; 
    1028      
    1029     if(!defined $date1) { 
    1030       return 1; 
    10311008    } 
    10321009    if(!defined $date2) { 
    1033       return 0; 
     1010        return 0; 
    10341011    } 
    10351012     
    10361013    # 16-Aug-2006 
    10371014    if($date1=~ /(\d+?)-(\S\S\S)-(\d\d\d\d)/){ 
    1038        my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr",  "04", "May",  "05", "Jun",  "06", 
    1039           "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12"); 
    1040        $date1=$3 . "-" . $months{$2} . "-" . $1; 
    1041        # print "** converted date1: $date1\n"; 
     1015        my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr",  "04", "May",  "05", "Jun",  "06", 
     1016        "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12"); 
     1017        $date1=$3 . "-" . $months{$2} . "-" . $1; 
     1018        # print "** converted date1: $date1\n"; 
    10421019    } 
    10431020    if($date2=~ /(\d+?)-(\S\S\S)-(\d\d\d\d)/){ 
    1044        my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr",  "04", "May",  "05", "Jun",  "06", 
    1045           "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12"); 
    1046        $date2=$3 . "-" . $months{$2} . "-" . $1; 
    1047        # print "** converted date2: $date2\n"; 
     1021        my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr",  "04", "May",  "05", "Jun",  "06", 
     1022        "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12"); 
     1023        $date2=$3 . "-" . $months{$2} . "-" . $1; 
     1024        # print "** converted date2: $date2\n"; 
    10481025    } 
    10491026     
     
    10551032    # Compare year 
    10561033    if ($date1parts[0] > $date2parts[0]) { 
    1057     return 1; 
     1034        return 1; 
    10581035    } 
    10591036    elsif ($date1parts[0] == $date2parts[0]) { 
    1060     # Year is the same, so compare month 
    1061     if ($date1parts[1] > $date2parts[1]) { 
    1062         return 1; 
    1063     } 
    1064     elsif ($date1parts[1] == $date2parts[1]) { 
    1065         # Month is the same, so compare day 
    1066         if ($date1parts[2] > $date2parts[2]) { 
    1067         return 1; 
    1068         } 
    1069     } 
     1037        # Year is the same, so compare month 
     1038        if ($date1parts[1] > $date2parts[1]) { 
     1039            return 1; 
     1040        } 
     1041        elsif ($date1parts[1] == $date2parts[1]) { 
     1042            # Month is the same, so compare day 
     1043            if ($date1parts[2] > $date2parts[2]) { 
     1044                return 1; 
     1045            } 
     1046        } 
    10701047    }     
    10711048     
     
    10771054{ 
    10781055    my ($translation_file_key, $target_file, $total_num_chunks, $target_files_keys_requiring_translation, $target_files_keys_requiring_updating, $num_chunks_to_return, $source_files_key_to_text_mapping, $target_files_key_to_text_mapping, $source_files_key_to_last_update_date_mapping, $target_files_key_to_last_update_date_mapping) = @_; 
    1079  
     1056     
    10801057    # Form an XML response to the command 
    10811058    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; 
     
    10871064    . " num_chunks_requiring_translation=\"" . scalar(@$target_files_keys_requiring_translation) . "\"" 
    10881065    . " num_chunks_requiring_updating=\"" . scalar(@$target_files_keys_requiring_updating) . "\"\/>\n"; 
    1089  
     1066     
    10901067    # Do chunks requiring translation first 
    10911068    if ($num_chunks_to_return > scalar(@$target_files_keys_requiring_translation)) { 
    1092     $xml_response .= "  <ChunksRequiringTranslation size=\"" . scalar(@$target_files_keys_requiring_translation) . "\">\n"; 
     1069        $xml_response .= "  <ChunksRequiringTranslation size=\"" . scalar(@$target_files_keys_requiring_translation) . "\">\n"; 
    10931070    } 
    10941071    else { 
    1095     $xml_response .= "  <ChunksRequiringTranslation size=\"" . $num_chunks_to_return . "\">\n"; 
    1096     } 
    1097  
     1072        $xml_response .= "  <ChunksRequiringTranslation size=\"" . $num_chunks_to_return . "\">\n"; 
     1073    } 
     1074     
    10981075    my @sorted_chunk_keys = sort (@$target_files_keys_requiring_translation); 
    10991076    foreach my $chunk_key (@sorted_chunk_keys) { 
    1100     last if ($num_chunks_to_return == 0); 
    1101  
    1102     my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || ""; 
    1103     my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});   
    1104      
    1105     $xml_response .= "    <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n"; 
    1106     $xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";    
    1107     $xml_response .= "      <TargetFileText></TargetFileText>\n"; 
    1108     $xml_response .= "    </Chunk>\n"; 
    1109  
    1110     $num_chunks_to_return--; 
    1111     } 
    1112  
     1077        last if ($num_chunks_to_return == 0); 
     1078         
     1079        my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || ""; 
     1080        my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});   
     1081         
     1082        $xml_response .= "    <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n"; 
     1083        $xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";    
     1084        $xml_response .= "      <TargetFileText></TargetFileText>\n"; 
     1085        $xml_response .= "    </Chunk>\n"; 
     1086         
     1087        $num_chunks_to_return--; 
     1088    } 
     1089     
    11131090    $xml_response .= "  </ChunksRequiringTranslation>\n"; 
    1114  
     1091     
    11151092    # Then do chunks requiring updating 
    11161093    if ($num_chunks_to_return > scalar(@$target_files_keys_requiring_updating)) { 
    1117     $xml_response .= "  <ChunksRequiringUpdating size=\"" . scalar(@$target_files_keys_requiring_updating) . "\">\n"; 
     1094        $xml_response .= "  <ChunksRequiringUpdating size=\"" . scalar(@$target_files_keys_requiring_updating) . "\">\n"; 
    11181095    } 
    11191096    else { 
    1120     $xml_response .= "  <ChunksRequiringUpdating size=\"" . $num_chunks_to_return . "\">\n"; 
    1121     } 
    1122          
     1097        $xml_response .= "  <ChunksRequiringUpdating size=\"" . $num_chunks_to_return . "\">\n"; 
     1098    } 
     1099     
    11231100    # foreach my $chunk_key (@target_file_keys_requiring_updating) { 
    11241101    @sorted_chunk_keys = sort (@$target_files_keys_requiring_updating); 
    11251102    foreach my $chunk_key (@sorted_chunk_keys) { 
    1126     last if ($num_chunks_to_return == 0); 
    1127  
    1128     my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || ""; 
    1129     my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key}); 
    1130     my $target_file_chunk_date = $target_files_key_to_last_update_date_mapping->{$chunk_key} || ""; 
    1131     my $target_file_chunk_text = &make_text_xml_safe($target_files_key_to_text_mapping->{$chunk_key}); 
    1132  
    1133     $xml_response .= "    <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";    
    1134     $xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n"; 
    1135     $xml_response .= "      <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n"; 
    1136     $xml_response .= "    </Chunk>\n"; 
    1137  
    1138     $num_chunks_to_return--; 
    1139     } 
    1140  
     1103        last if ($num_chunks_to_return == 0); 
     1104         
     1105        my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || ""; 
     1106        my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key}); 
     1107        my $target_file_chunk_date = $target_files_key_to_last_update_date_mapping->{$chunk_key} || ""; 
     1108        my $target_file_chunk_text = &make_text_xml_safe($target_files_key_to_text_mapping->{$chunk_key}); 
     1109         
     1110        $xml_response .= "    <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";    
     1111        $xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n"; 
     1112        $xml_response .= "      <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n"; 
     1113        $xml_response .= "    </Chunk>\n"; 
     1114         
     1115        $num_chunks_to_return--; 
     1116    } 
     1117     
    11411118    $xml_response .= "  </ChunksRequiringUpdating>\n"; 
    1142  
     1119     
    11431120    $xml_response .= "</GTIResponse>\n"; 
    1144  
     1121     
    11451122    return $xml_response; 
    11461123} 
     
    11501127{ 
    11511128    my ($translation_file_key, $target_file, $source_file_key_to_text_mapping, $target_file_key_to_text_mapping, $source_file_key_to_last_update_date_mapping, $target_file_key_to_last_update_date_mapping) = @_; 
    1152  
     1129     
    11531130    # Form an XML response to the command 
    11541131    my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"; 
     
    11601137    # Do all the chunks 
    11611138    $xml_response .= "  <Chunks size=\"" . scalar(keys(%$source_file_key_to_text_mapping)) . "\">\n"; 
    1162  
     1139     
    11631140    my @sorted_chunk_keys = sort (keys(%$source_file_key_to_text_mapping)); 
    11641141    foreach my $chunk_key (@sorted_chunk_keys) { 
    1165     my $source_file_chunk_date = $source_file_key_to_last_update_date_mapping->{$chunk_key} || ""; 
    1166     my $source_file_chunk_text = &make_text_xml_safe($source_file_key_to_text_mapping->{$chunk_key}); 
    1167  
    1168     $xml_response .= "    <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n"; 
    1169     $xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n"; 
    1170     if (defined($target_file_key_to_text_mapping->{$chunk_key})) { 
    1171         my $target_file_chunk_date = $target_file_key_to_last_update_date_mapping->{$chunk_key} || ""; 
    1172         my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping->{$chunk_key}); 
    1173         $xml_response .= "      <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n"; 
    1174     } 
    1175     else { 
    1176         $xml_response .= "      <TargetFileText></TargetFileText>\n"; 
    1177     } 
    1178  
    1179     $xml_response .= "    </Chunk>\n"; 
     1142        my $source_file_chunk_date = $source_file_key_to_last_update_date_mapping->{$chunk_key} || ""; 
     1143        my $source_file_chunk_text = &make_text_xml_safe($source_file_key_to_text_mapping->{$chunk_key}); 
     1144         
     1145        $xml_response .= "    <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n"; 
     1146        $xml_response .= "      <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n"; 
     1147        if (defined($target_file_key_to_text_mapping->{$chunk_key})) { 
     1148            my $target_file_chunk_date = $target_file_key_to_last_update_date_mapping->{$chunk_key} || ""; 
     1149            my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping->{$chunk_key}); 
     1150            $xml_response .= "      <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n"; 
     1151        } 
     1152        else { 
     1153            $xml_response .= "      <TargetFileText></TargetFileText>\n"; 
     1154        } 
     1155         
     1156        $xml_response .= "    </Chunk>\n"; 
    11801157    } 
    11811158    $xml_response .= "  </Chunks>\n"; 
     
    11931170{ 
    11941171    my (@file_lines) = @_; 
    1195  
     1172     
    11961173    my $macro_package; 
    11971174    my %chunk_key_to_line_mapping = (); 
    11981175    # Process the contents of the file, line by line 
    11991176    for (my $i = 0; $i < scalar(@file_lines); $i++) { 
    1200     my $line = $file_lines[$i]; 
    1201     $line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
    1202  
    1203     # Check if a new package is being defined 
    1204     if ($line =~ m/^package\s+(.+)/) { 
    1205         $macro_package = $1; 
    1206     } 
    1207  
    1208     # Line contains a macro name 
    1209     elsif ($line =~ m/^(_\w+_)/) { 
    1210         my $macro_key = $1; 
    1211         $line =~ s/\s*([^\\]\#[^\}]+)?$//;  # Remove any comments and nasty whitespace 
    1212  
    1213         # While there is still text of the macro to go... 
    1214         my $startline = $i; 
    1215         while ($line !~ /\}$/) { 
    1216         $i++; 
    1217         if ($i == scalar(@file_lines)) { 
    1218             &throw_fatal_error("Could not find end of macro $macro_key."); 
    1219         } 
    1220         $line = $file_lines[$i]; 
    1221         $line =~ s/\s*([^\\]\#[^\}]+)?$//;  # Remove any comments and nasty whitespace 
    1222         } 
    1223  
     1177        my $line = $file_lines[$i]; 
     1178        $line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
     1179         
     1180        # Check if a new package is being defined 
     1181        if ($line =~ m/^package\s+(.+)/) { 
     1182            $macro_package = $1; 
     1183        } 
     1184         
     1185        # Line contains a macro name 
     1186        elsif ($line =~ m/^(_\w+_)/) { 
     1187            my $macro_key = $1; 
     1188            $line =~ s/\s*([^\\]\#[^\}]+)?$//;  # Remove any comments and nasty whitespace 
     1189             
     1190            # While there is still text of the macro to go... 
     1191            my $startline = $i; 
     1192            while ($line !~ /\}$/) { 
     1193                $i++; 
     1194                if ($i == scalar(@file_lines)) { 
     1195                    &throw_fatal_error("Could not find end of macro $macro_key."); 
     1196                } 
     1197                $line = $file_lines[$i]; 
     1198                $line =~ s/\s*([^\\]\#[^\}]+)?$//;  # Remove any comments and nasty whitespace 
     1199            } 
     1200         
    12241201        # The chunk key consists of the package name and the macro key 
    12251202        my $chunk_key = $macro_package . "." . $macro_key; 
     
    12271204        $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i; 
    12281205    } 
    1229  
     1206     
    12301207    # Icon: line in format ## "image text" ## image_type ## macro_name ## 
    12311208    elsif ($line =~ m/^\#\# .* \#\# .* \#\# (.*) \#\#/) { 
    1232         # The chunk key consists of package name and macro key 
    1233         my $chunk_key = $macro_package . "." . $1; 
    1234         # Map from chunk key to line 
    1235         $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i; 
    1236     } 
    1237     } 
    1238  
    1239     return %chunk_key_to_line_mapping; 
     1209    # The chunk key consists of package name and macro key 
     1210    my $chunk_key = $macro_package . "." . $1; 
     1211    # Map from chunk key to line 
     1212    $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i; 
     1213} 
     1214} 
     1215 
     1216return %chunk_key_to_line_mapping; 
    12401217} 
    12411218 
     
    12441221{ 
    12451222    my ($chunk_text) = @_; 
    1246  
     1223     
    12471224    # Is this an icon macro?? 
    12481225    if ($chunk_text =~ /^\#\# (.*)/) { 
    1249     # Extract image macro text 
    1250     $chunk_text =~ /^\#\#\s+([^\#]+)\s+\#\#/; 
    1251     $chunk_text = $1; 
    1252  
     1226        # Extract image macro text 
     1227        $chunk_text =~ /^\#\#\s+([^\#]+)\s+\#\#/; 
     1228        $chunk_text = $1; 
     1229     
    12531230    # Remove enclosing quotes 
    12541231    $chunk_text =~ s/^\"//; 
    12551232    $chunk_text =~ s/\"$//; 
    1256     } 
    1257  
    1258     # No, so it must be a text macro 
    1259     else { 
     1233} 
     1234 
     1235# No, so it must be a text macro 
     1236else { 
    12601237    # Remove macro key 
    12611238    $chunk_text =~ s/^_([^_]+)_(\s*)//; 
    1262  
     1239     
    12631240    # Remove language specifier 
    12641241    $chunk_text =~ s/^\[l=.*\](\s*)//; 
    1265  
     1242     
    12661243    # Remove braces enclosing text 
    12671244    $chunk_text =~ s/^{(\s*)((.|\n)*)}(\s*)(\#.+\s*)?/$2/; 
    1268     } 
    1269  
    1270     return $chunk_text; 
     1245} 
     1246 
     1247return $chunk_text; 
    12711248} 
    12721249 
     
    12751252{ 
    12761253    my ($chunk_text) = @_; 
    1277  
     1254     
    12781255    # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk 
    12791256    if ($chunk_text =~ /\#\s+(Updated\s+\d?\d-\D\D\D-\d\d\d\d.*)\s*$/i) { 
    1280     return $1; 
    1281     } 
    1282  
    1283     return undef; 
     1257        return $1; 
     1258} 
     1259 
     1260return undef; 
    12841261} 
    12851262 
     
    12881265{ 
    12891266    my ($chunk_key) = @_; 
    1290  
     1267     
    12911268    # The _httpiconX_, _widthX_ and _heightX_ image macros are automatically translated 
    12921269    if ($chunk_key =~ /\._(httpicon|width|height)/) { 
    1293     return 1; 
    1294     } 
    1295  
     1270        return 1; 
     1271    } 
     1272     
    12961273    return 0; 
    12971274} 
     
    13091286    my $target_file_key_to_gti_comment_mapping = shift(@_); 
    13101287    my $target_language_code = shift(@_); 
    1311  
     1288     
    13121289    # Build a mapping from source file line to chunk key 
    13131290    my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@source_file_lines); 
    13141291    my %source_file_line_to_key_mapping = (); 
    13151292    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    1316     $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
     1293        $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
    13171294    } 
    13181295    my @source_file_line_keys = (sort sort_by_line (keys(%source_file_line_to_key_mapping))); 
    13191296    my $source_file_line_number = 0; 
    1320  
     1297     
    13211298    # Build a mapping from target file line to chunk key 
    13221299    my %target_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@target_file_lines); 
    13231300    my %target_file_line_to_key_mapping = (); 
    13241301    foreach my $chunk_key (keys(%target_file_key_to_line_mapping)) { 
    1325     $target_file_line_to_key_mapping{$target_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
     1302        $target_file_line_to_key_mapping{$target_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
    13261303    } 
    13271304    my @target_file_line_keys = (sort sort_by_line (keys(%target_file_line_to_key_mapping))); 
    1328  
     1305     
    13291306    # Write the new target file 
    13301307    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
    13311308    if (!open(TARGET_FILE, ">$target_file_path")) { 
    1332     &throw_fatal_error("Could not write target file $target_file_path."); 
    1333     } 
    1334  
     1309        &throw_fatal_error("Could not write target file $target_file_path."); 
     1310    } 
     1311     
    13351312    # Use the header from the target file, to keep language and author information 
    13361313    if (scalar(@target_file_line_keys) > 0) { 
    1337     my $target_file_line_number = 0; 
    1338     my $target_file_chunk_starting_line_number = (split(/-/, $target_file_line_keys[0]))[0]; 
    1339     while ($target_file_line_number < $target_file_chunk_starting_line_number) { 
    1340         my $target_file_line = $target_file_lines[$target_file_line_number]; 
    1341         last if ($target_file_line =~ /^\# -- Missing translation: /);  # We don't want to get into the macros 
    1342         print TARGET_FILE $target_file_line; 
    1343         $target_file_line_number++; 
    1344     } 
    1345  
    1346     $source_file_line_number = (split(/-/, $source_file_line_keys[0]))[0]; 
    1347     } 
    1348  
     1314        my $target_file_line_number = 0; 
     1315        my $target_file_chunk_starting_line_number = (split(/-/, $target_file_line_keys[0]))[0]; 
     1316        while ($target_file_line_number < $target_file_chunk_starting_line_number) { 
     1317            my $target_file_line = $target_file_lines[$target_file_line_number]; 
     1318            last if ($target_file_line =~ /^\# -- Missing translation: /);  # We don't want to get into the macros 
     1319                print TARGET_FILE $target_file_line; 
     1320            $target_file_line_number++; 
     1321        } 
     1322         
     1323        $source_file_line_number = (split(/-/, $source_file_line_keys[0]))[0]; 
     1324    } 
     1325     
    13491326    # Model the new target file on the source file, with the target file translations 
    13501327    foreach my $line_key (@source_file_line_keys) { 
    1351     # Fill in the gaps before this chunk starts 
    1352     my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
    1353     my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
    1354     while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
    1355         print TARGET_FILE $source_file_lines[$source_file_line_number]; 
    1356         $source_file_line_number++; 
    1357     } 
    1358     $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
    1359  
    1360     my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
    1361     my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key}; 
    1362     my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || ""; 
    1363  
    1364     my $macrofile_key = $chunk_key; 
    1365     $macrofile_key =~ s/^(.+?)\.//; 
    1366  
    1367     # If no translation exists for this chunk, show this, and move on 
    1368     if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
    1369         print TARGET_FILE "# -- Missing translation: $macrofile_key\n"; 
    1370         next; 
    1371     } 
    1372  
    1373     # Grab the source chunk text 
    1374     my $source_file_chunk = $source_file_lines[$source_file_chunk_starting_line_number]; 
    1375     for (my $l = ($source_file_chunk_starting_line_number + 1); $l <= $source_file_chunk_finishing_line_number; $l++) { 
    1376         $source_file_chunk .= $source_file_lines[$l]; 
    1377     } 
    1378  
    1379     # Is this an icon macro?? 
    1380     if ($source_file_chunk =~ /^\#\# (.*)/) { 
    1381         # Escape any newline and question mark characters so the source text is replaced correctly 
    1382         $source_file_chunk_text =~ s/\\/\\\\/g; 
     1328        # Fill in the gaps before this chunk starts 
     1329        my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
     1330        my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
     1331        while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
     1332            print TARGET_FILE $source_file_lines[$source_file_line_number]; 
     1333            $source_file_line_number++; 
     1334        } 
     1335        $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
     1336         
     1337        my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
     1338        my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key}; 
     1339        my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || ""; 
     1340         
     1341        my $macrofile_key = $chunk_key; 
     1342        $macrofile_key =~ s/^(.+?)\.//; 
     1343         
     1344        # If no translation exists for this chunk, show this, and move on 
     1345        if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
     1346            print TARGET_FILE "# -- Missing translation: $macrofile_key\n"; 
     1347            next; 
     1348        } 
     1349         
     1350        # Grab the source chunk text 
     1351        my $source_file_chunk = $source_file_lines[$source_file_chunk_starting_line_number]; 
     1352        for (my $l = ($source_file_chunk_starting_line_number + 1); $l <= $source_file_chunk_finishing_line_number; $l++) { 
     1353            $source_file_chunk .= $source_file_lines[$l]; 
     1354        } 
     1355         
     1356        # Is this an icon macro?? 
     1357        if ($source_file_chunk =~ /^\#\# (.*)/) { 
     1358            # Escape any newline and question mark characters so the source text is replaced correctly 
     1359            $source_file_chunk_text =~ s/\\/\\\\/g; 
    13831360        $source_file_chunk_text =~ s/\?/\\\?/g; 
    1384  
     1361         
    13851362        # Build the new target chunk from the source chunk 
    13861363        my $target_file_chunk = $source_file_chunk; 
     
    13891366        print TARGET_FILE "$target_file_chunk"; 
    13901367    } 
    1391  
     1368     
    13921369    # No, it is just a normal text macro 
    13931370    else { 
    13941371        print TARGET_FILE "$macrofile_key [l=$target_language_code] {$target_file_chunk_text}"; 
    13951372    } 
    1396  
     1373     
    13971374    # Add the "updated" comment, if one exists 
    13981375    if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) { 
     
    14001377    } 
    14011378    print TARGET_FILE "\n"; 
    1402     } 
    1403  
    1404     close(TARGET_FILE); 
     1379} 
     1380 
     1381close(TARGET_FILE); 
    14051382} 
    14061383 
     
    14181395{ 
    14191396    my (@file_lines) = @_; 
    1420  
     1397     
    14211398    my %chunk_key_to_line_mapping = (); 
    14221399    for (my $i = 0; $i < scalar(@file_lines); $i++) { 
    1423     my $line = $file_lines[$i]; 
    1424     $line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
    1425  
    1426     # Line contains a dictionary string 
    1427     if ($line =~ /^(\S+?)[:|=](.*)$/) { 
    1428         my $chunk_key = $1; 
    1429  
    1430         # Map from chunk key to line 
    1431         $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i; 
    1432     } 
    1433     } 
    1434  
     1400        my $line = $file_lines[$i]; 
     1401        $line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
     1402         
     1403        # Line contains a dictionary string 
     1404        if ($line =~ /^(\S+?)[:|=](.*)$/) { 
     1405            my $chunk_key = $1; 
     1406             
     1407            # Map from chunk key to line 
     1408            $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i; 
     1409        } 
     1410    } 
     1411     
    14351412    return %chunk_key_to_line_mapping; 
    14361413} 
     
    14401417{ 
    14411418    my ($chunk_text) = @_; 
    1442  
     1419     
    14431420    # Simple: just remove string key 
    14441421    $chunk_text =~ s/^(\S+?)[:|=](\s*)//; 
    14451422    $chunk_text =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
    14461423    $chunk_text =~ s/(\s*)\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d.*)\s*$//i; 
    1447  
     1424     
    14481425    return $chunk_text; 
    14491426} 
     
    14531430{ 
    14541431    my ($chunk_text) = @_; 
    1455  
     1432     
    14561433    # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk 
    14571434    if ($chunk_text =~ /\#\s+(Updated\s+\d?\d-\D\D\D-\d\d\d\d.*)\s*$/i) { 
    1458     return $1; 
    1459     } 
    1460  
    1461     return undef; 
     1435        return $1; 
     1436} 
     1437 
     1438return undef; 
    14621439} 
    14631440 
     
    14801457    my $target_file_key_to_gti_comment_mapping = shift(@_); 
    14811458    my $target_language_code = shift(@_);  # Not used 
    1482  
     1459     
    14831460    # Build a mapping from chunk key to source file line, and from source file line to chunk key 
    14841461    my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines); 
    14851462    my %source_file_line_to_key_mapping = (); 
    14861463    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    1487     $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
    1488     } 
    1489  
     1464        $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
     1465    } 
     1466     
    14901467    # Write the new target file 
    14911468    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
    14921469    if (!open(TARGET_FILE, ">$target_file_path")) { 
    1493     &throw_fatal_error("Could not write target file $target_file_path."); 
    1494     } 
    1495  
     1470        &throw_fatal_error("Could not write target file $target_file_path."); 
     1471    } 
     1472     
    14961473    # Model the new target file on the source file, with the target file translations 
    14971474    my $source_file_line_number = 0; 
    14981475    foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) { 
    1499     # Fill in the gaps before this chunk starts 
    1500     my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
    1501     my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
    1502     while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
    1503         print TARGET_FILE $source_file_lines[$source_file_line_number]; 
    1504         $source_file_line_number++; 
    1505     } 
    1506     $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
    1507  
    1508     my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
    1509     my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key}; 
    1510     my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || ""; 
    1511  
    1512     # If no translation exists for this chunk, show this, and move on 
    1513     if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
    1514         print TARGET_FILE "# -- Missing translation: $chunk_key\n"; 
    1515         next; 
    1516     } 
    1517  
    1518     print TARGET_FILE "$chunk_key:$target_file_chunk_text"; 
    1519     if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) { 
    1520         print TARGET_FILE "  # " . $target_file_key_to_gti_comment_mapping->{$chunk_key}; 
    1521     } 
    1522     print TARGET_FILE "\n"; 
    1523     } 
    1524  
     1476        # Fill in the gaps before this chunk starts 
     1477        my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
     1478        my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
     1479        while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
     1480            print TARGET_FILE $source_file_lines[$source_file_line_number]; 
     1481            $source_file_line_number++; 
     1482        } 
     1483        $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
     1484         
     1485        my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
     1486        my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key}; 
     1487        my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || ""; 
     1488         
     1489        # If no translation exists for this chunk, show this, and move on 
     1490        if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
     1491            print TARGET_FILE "# -- Missing translation: $chunk_key\n"; 
     1492            next; 
     1493        } 
     1494         
     1495        print TARGET_FILE "$chunk_key:$target_file_chunk_text"; 
     1496        if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) { 
     1497            print TARGET_FILE "  # " . $target_file_key_to_gti_comment_mapping->{$chunk_key}; 
     1498        } 
     1499        print TARGET_FILE "\n"; 
     1500    } 
     1501     
    15251502    close(TARGET_FILE); 
    15261503} 
     
    15331510{ 
    15341511    my (@file_lines) = @_; 
    1535  
     1512     
    15361513    my %chunk_key_to_line_mapping = (); 
    15371514    for (my $i = 0; $i < scalar(@file_lines); $i++) { 
    1538     my $line = $file_lines[$i]; 
    1539     $line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
    1540  
    1541     # Line contains a string to translate 
    1542     if ($line =~ /^\s*<Text id=\"(.*?)\">/) { 
    1543         my $chunk_key = $1; 
    1544         $line =~ s/\s*$//;  # Remove any nasty whitespace 
    1545         $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//; 
    1546  
    1547         # While there is still text of the string to go... 
    1548         my $startline = $i; 
    1549         while ($line !~ /<\/Text>$/) { 
    1550         $i++; 
    1551         if ($i == scalar(@file_lines)) { 
    1552             &throw_fatal_error("Could not find end of string $chunk_key."); 
    1553         } 
    1554         $line = $file_lines[$i]; 
    1555         $line =~ s/\s*$//;  # Remove any nasty whitespace 
    1556         $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//; 
    1557         } 
    1558  
    1559         # Map from chunk key to line 
    1560         if (!defined($chunk_key_to_line_mapping{$chunk_key})) { 
    1561         $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i; 
    1562         } 
    1563         else { 
    1564         &throw_fatal_error("Duplicate key $chunk_key."); 
    1565         } 
    1566     } 
    1567     } 
    1568  
     1515        my $line = $file_lines[$i]; 
     1516        $line =~ s/(\s*)$//;  # Remove any nasty whitespace, carriage returns etc. 
     1517         
     1518        # Line contains a string to translate 
     1519        if ($line =~ /^\s*<Text id=\"(.*?)\">/) { 
     1520            my $chunk_key = $1; 
     1521            $line =~ s/\s*$//;  # Remove any nasty whitespace 
     1522            $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//; 
     1523             
     1524            # While there is still text of the string to go... 
     1525            my $startline = $i; 
     1526            while ($line !~ /<\/Text>$/) { 
     1527                $i++; 
     1528                if ($i == scalar(@file_lines)) { 
     1529                    &throw_fatal_error("Could not find end of string $chunk_key."); 
     1530                } 
     1531                $line = $file_lines[$i]; 
     1532                $line =~ s/\s*$//;  # Remove any nasty whitespace 
     1533                $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//; 
     1534            } 
     1535             
     1536            # Map from chunk key to line 
     1537            if (!defined($chunk_key_to_line_mapping{$chunk_key})) { 
     1538                $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i; 
     1539            } 
     1540            else { 
     1541                &throw_fatal_error("Duplicate key $chunk_key."); 
     1542            } 
     1543        } 
     1544    } 
     1545     
    15691546    return %chunk_key_to_line_mapping; 
    15701547} 
     
    15741551{ 
    15751552    my ($chunk_text) = @_; 
    1576  
     1553     
    15771554    # Simple: just remove the Text tags 
    15781555    $chunk_text =~ s/^\s*<Text id=\"(.*?)\">(\s*)//; 
    15791556    $chunk_text =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//; 
    15801557    $chunk_text =~ s/<\/Text>$//; 
    1581  
     1558     
    15821559    return $chunk_text; 
    15831560} 
     
    15871564{ 
    15881565    my ($chunk_text) = @_; 
    1589  
     1566     
    15901567    # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk 
    15911568    if ($chunk_text =~ /<Updated date=\"(\d?\d-\D\D\D-\d\d\d\d.*)\"\/>$/i) { 
    1592     return $1; 
    1593     } 
    1594  
     1569        return $1; 
     1570    } 
     1571     
    15951572    return undef; 
    15961573} 
     
    16141591    my $target_file_key_to_gti_comment_mapping = shift(@_); 
    16151592    my $target_language_code = shift(@_);  # Not used 
    1616  
     1593     
    16171594    # Build a mapping from chunk key to source file line, and from source file line to chunk key 
    16181595    my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_greenstone_xml(@source_file_lines); 
    16191596    my %source_file_line_to_key_mapping = (); 
    16201597    foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    1621     $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
    1622     } 
    1623  
     1598        $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
     1599    } 
     1600     
    16241601    # Write the new target file 
    16251602    my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
    16261603    if (!open(TARGET_FILE, ">$target_file_path")) { 
    1627     &throw_fatal_error("Could not write target file $target_file_path."); 
    1628     } 
    1629  
     1604        &throw_fatal_error("Could not write target file $target_file_path."); 
     1605    } 
     1606     
    16301607    # Model the new target file on the source file, with the target file translations 
    16311608    my $source_file_line_number = 0; 
    16321609    foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) { 
    1633     # Fill in the gaps before this chunk starts 
    1634     my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
    1635     my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
    1636     while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
    1637         print TARGET_FILE $source_file_lines[$source_file_line_number]; 
    1638         $source_file_line_number++; 
    1639     } 
    1640     $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
    1641  
    1642     my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
    1643     my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key}; 
    1644     my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || ""; 
    1645     $target_file_chunk_text =~ s/(\n)*$//g; 
    1646  
    1647     # If no translation exists for this chunk, show this, and move on 
    1648     if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
    1649         print TARGET_FILE "<!-- Missing translation: $chunk_key -->\n"; 
    1650         next; 
    1651     } 
    1652  
    1653     print TARGET_FILE "<Text id=\"$chunk_key\">$target_file_chunk_text</Text>"; 
    1654     if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) { 
    1655         my $chunk_gti_comment = $target_file_key_to_gti_comment_mapping->{$chunk_key}; 
    1656         $chunk_gti_comment =~ s/^Updated //; 
    1657         print TARGET_FILE "<Updated date=\"" . $chunk_gti_comment . "\"\/>"; 
    1658     } 
    1659     print TARGET_FILE "\n"; 
    1660     } 
    1661  
     1610        # Fill in the gaps before this chunk starts 
     1611        my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
     1612        my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
     1613        while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
     1614            print TARGET_FILE $source_file_lines[$source_file_line_number]; 
     1615            $source_file_line_number++; 
     1616        } 
     1617        $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
     1618         
     1619        my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
     1620        my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key}; 
     1621        my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || ""; 
     1622        $target_file_chunk_text =~ s/(\n)*$//g; 
     1623         
     1624        # If no translation exists for this chunk, show this, and move on 
     1625        if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
     1626            print TARGET_FILE "<!-- Missing translation: $chunk_key -->\n"; 
     1627            next; 
     1628        } 
     1629         
     1630        print TARGET_FILE "<Text id=\"$chunk_key\">$target_file_chunk_text</Text>"; 
     1631        if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) { 
     1632            my $chunk_gti_comment = $target_file_key_to_gti_comment_mapping->{$chunk_key}; 
     1633            $chunk_gti_comment =~ s/^Updated //; 
     1634            print TARGET_FILE "<Updated date=\"" . $chunk_gti_comment . "\"\/>"; 
     1635        } 
     1636        print TARGET_FILE "\n"; 
     1637    } 
     1638     
    16621639    # Fill in the end of the file 
    16631640    while ($source_file_line_number < scalar(@source_file_lines)) { 
    1664     print TARGET_FILE $source_file_lines[$source_file_line_number]; 
    1665     $source_file_line_number++; 
    1666     } 
    1667  
     1641        print TARGET_FILE $source_file_lines[$source_file_line_number]; 
     1642        $source_file_line_number++; 
     1643    } 
     1644     
    16681645    close(TARGET_FILE); 
    16691646} 
     
    16781655    my $target_language_code = lc(shift(@_)); 
    16791656    my $translation_file_key = lc(shift(@_)); 
    1680  
     1657     
    16811658    # Check that the necessary arguments were supplied 
    16821659    if (!$target_language_code) { 
    1683     &throw_fatal_error("Missing command argument."); 
    1684     } 
    1685  
     1660        &throw_fatal_error("Missing command argument."); 
     1661    } 
     1662     
    16861663    # Get (and check) the translation configuration 
    16871664    # my ($source_file_dir, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file_key); 
     
    16911668    my %source_files_key_to_last_update_date_mapping = (); 
    16921669    my %target_files_key_to_last_update_date_mapping = (); 
    1693  
     1670     
    16941671    &build_gs3_configuration($target_language_code, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping, \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping); 
    1695  
     1672     
    16961673    &log_message("Total number of source chunks: " . scalar(keys(%source_files_key_to_text_mapping))); 
    16971674    &log_message("Total number of target chunks: " . scalar(keys(%target_files_key_to_text_mapping))); 
    1698  
     1675     
    16991676    my $xml_response = &create_xml_response_for_all_chunks($translation_file_key, "", \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping, \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);    
    17001677    return $xml_response; 
     
    17131690    # Check that the necessary arguments were supplied 
    17141691    if (!$target_language_code || !$translation_file_key) { 
    1715     &throw_fatal_error("Missing command argument."); 
     1692        &throw_fatal_error("Missing command argument."); 
    17161693    } 
    17171694     
     
    17201697    my %source_files_key_to_last_update_date_mapping = (); 
    17211698    my %target_files_key_to_last_update_date_mapping = (); 
    1722  
     1699     
    17231700    &build_gs3_configuration($target_language_code, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,  
    1724                  \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping); 
     1701    \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping); 
    17251702     
    17261703    # Determine the target file chunks requiring translation 
     
    17301707    &log_message("Total number of target chunks requiring translation: " . scalar(@target_files_keys_requiring_translation)); 
    17311708    &log_message("Total number of target chunks requiring updating: " . scalar(@target_files_keys_requiring_updating)); 
    1732  
     1709     
    17331710    my $xml_response = &create_xml_response_for_chunks_requiring_work($translation_file_key, "", scalar(keys(%source_files_key_to_text_mapping)), 
    1734                                       \@target_files_keys_requiring_translation, \@target_files_keys_requiring_updating, 
    1735                                       $num_chunks_to_return, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping, 
    1736                                       \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping); 
    1737     
     1711    \@target_files_keys_requiring_translation, \@target_files_keys_requiring_updating, 
     1712    $num_chunks_to_return, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping, 
     1713    \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping); 
     1714     
    17381715    return $xml_response; 
    17391716} 
     
    17481725    my $source_file_directory = "greenstone3"; 
    17491726    my $translation_file_type = "resource_bundle"; 
    1750  
     1727     
    17511728    foreach my $interface_file_key (@gs3_interface_files) { 
    1752  
    1753     &log_message("Greenstone 3 interface file: " . $interface_file_key); 
    1754  
    1755     # Parse the source language and target language files 
    1756     my $source_file = &util::filename_cat($source_file_directory, $interface_file_key.".properties"); 
    1757     my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file)); 
    1758     my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
    1759     my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
    1760     my %source_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);  
    1761      
    1762     my $target_file = &util::filename_cat($source_file_directory, $interface_file_key."_".$target_language_code.".properties"); 
    1763     my @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file)); 
    1764     my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
    1765     my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    1766     my %target_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
    1767  
    1768  
    1769     # Filter out any automatically translated chunks 
    1770     foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    1771         if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
    1772         delete $source_file_key_to_line_mapping{$chunk_key}; 
    1773         delete $target_file_key_to_line_mapping{$chunk_key}; 
    1774         } 
    1775     } 
    1776  
    1777     &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping))); 
    1778     &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping))); 
    1779  
    1780     foreach my $chunk_key (keys(%source_file_key_to_text_mapping)) { 
    1781         my $global_chunk_key = "$interface_file_key.$chunk_key"; 
    1782         $source_files_key_to_text_mapping->{$global_chunk_key} = $source_file_key_to_text_mapping{$chunk_key}; 
    1783         $source_files_key_to_gti_comment_mapping->{$global_chunk_key} = $source_file_key_to_gti_comment_mapping{$chunk_key}; 
    1784  
    1785         if (defined $target_file_key_to_text_mapping{$chunk_key}) { 
    1786         $target_files_key_to_text_mapping->{$global_chunk_key} = $target_file_key_to_text_mapping{$chunk_key}; 
    1787         $target_files_key_to_gti_comment_mapping->{$global_chunk_key} = $target_file_key_to_gti_comment_mapping{$chunk_key}; 
    1788         } 
    1789     }    
     1729         
     1730        &log_message("Greenstone 3 interface file: " . $interface_file_key); 
     1731         
     1732        # Parse the source language and target language files 
     1733        my $source_file = &util::filename_cat($source_file_directory, $interface_file_key.".properties"); 
     1734        my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file)); 
     1735        my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type); 
     1736        my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type); 
     1737        my %source_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);  
     1738         
     1739        my $target_file = &util::filename_cat($source_file_directory, $interface_file_key."_".$target_language_code.".properties"); 
     1740        my @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file)); 
     1741        my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type); 
     1742        my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
     1743        my %target_file_key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type); 
     1744         
     1745         
     1746        # Filter out any automatically translated chunks 
     1747        foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
     1748            if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) { 
     1749                delete $source_file_key_to_line_mapping{$chunk_key}; 
     1750                delete $target_file_key_to_line_mapping{$chunk_key}; 
     1751            } 
     1752        } 
     1753         
     1754        &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping))); 
     1755        &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping))); 
     1756         
     1757        foreach my $chunk_key (keys(%source_file_key_to_text_mapping)) { 
     1758            my $global_chunk_key = "$interface_file_key.$chunk_key"; 
     1759            $source_files_key_to_text_mapping->{$global_chunk_key} = $source_file_key_to_text_mapping{$chunk_key}; 
     1760            $source_files_key_to_gti_comment_mapping->{$global_chunk_key} = $source_file_key_to_gti_comment_mapping{$chunk_key}; 
     1761             
     1762            if (defined $target_file_key_to_text_mapping{$chunk_key}) { 
     1763                $target_files_key_to_text_mapping->{$global_chunk_key} = $target_file_key_to_text_mapping{$chunk_key}; 
     1764                $target_files_key_to_gti_comment_mapping->{$global_chunk_key} = $target_file_key_to_gti_comment_mapping{$chunk_key}; 
     1765            } 
     1766        }    
    17901767    } 
    17911768} 
     
    18001777     
    18011778    my @sorted_chunk_keys = sort (keys(%$source_file_key_to_text_mapping)); 
    1802  
     1779     
    18031780    my %translated_interface_file_keys = (); 
    18041781    foreach my $chunk_key (keys(%$target_file_key_to_text_mapping)) { 
    1805     $chunk_key =~ /^([^\.]+)?\.(.*)$/; 
    1806     if (!defined $translated_interface_file_keys{$1}) { 
    1807         &log_message("Updated interface file: " . $1);   
    1808         $translated_interface_file_keys{$1}=""; 
    1809     } 
     1782        $chunk_key =~ /^([^\.]+)?\.(.*)$/; 
     1783        if (!defined $translated_interface_file_keys{$1}) { 
     1784            &log_message("Updated interface file: " . $1);   
     1785            $translated_interface_file_keys{$1}=""; 
     1786        } 
    18101787    } 
    18111788    &log_message("Updated interface files: " . scalar(keys(%translated_interface_file_keys))); 
     
    18141791     
    18151792    foreach my $interface_file_key (keys(%translated_interface_file_keys)) { 
    1816      
    1817     # Build a mapping from chunk key to source file line, and from source file line to chunk key 
    1818     my $source_file = &util::filename_cat($source_file_directory, "$interface_file_key.properties"); 
    1819     my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file)); 
    1820     my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines); 
    1821     my %source_file_line_to_key_mapping = (); 
    1822     foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
    1823         $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
    1824     } 
    1825      
    1826     # Write the new target file 
    1827     my $target_file = &util::filename_cat($source_file_directory, $interface_file_key . "_" . $target_language_code . ".properties"); 
    1828     my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
    1829     if (!open(TARGET_FILE, ">$target_file_path")) { 
    1830         &throw_fatal_error("Could not write target file $target_file_path."); 
    1831     } 
    1832  
    1833     # Model the new target file on the source file, with the target file translations 
    1834     my $source_file_line_number = 0; 
    1835     foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) { 
    1836         # Fill in the gaps before this chunk starts 
    1837         my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
    1838         my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
    1839         while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
    1840         print TARGET_FILE $source_file_lines[$source_file_line_number]; 
    1841         $source_file_line_number++; 
    1842         } 
    1843         $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
    1844  
    1845         my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
    1846         my $global_chunk_key = "$interface_file_key.$chunk_key"; 
    1847         my $source_file_chunk_text = $source_file_key_to_text_mapping->{$global_chunk_key}; 
    1848         my $target_file_chunk_text = $target_file_key_to_text_mapping->{$global_chunk_key} || ""; 
    1849  
    1850         # If no translation exists for this chunk, show this, and move on 
    1851         if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
    1852         print TARGET_FILE "# -- Missing translation: $chunk_key\n"; 
    1853         next; 
    1854         } 
    1855  
    1856         print TARGET_FILE "$chunk_key:$target_file_chunk_text"; 
    1857         if ($target_file_key_to_gti_comment_mapping->{$global_chunk_key}) { 
    1858         print TARGET_FILE "  # " . $target_file_key_to_gti_comment_mapping->{$global_chunk_key}; 
    1859         } 
    1860         print TARGET_FILE "\n"; 
    1861     } 
    1862  
    1863     close(TARGET_FILE);  
     1793         
     1794        # Build a mapping from chunk key to source file line, and from source file line to chunk key 
     1795        my $source_file = &util::filename_cat($source_file_directory, "$interface_file_key.properties"); 
     1796        my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file)); 
     1797        my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines); 
     1798        my %source_file_line_to_key_mapping = (); 
     1799        foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) { 
     1800            $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key; 
     1801        } 
     1802         
     1803        # Write the new target file 
     1804        my $target_file = &util::filename_cat($source_file_directory, $interface_file_key . "_" . $target_language_code . ".properties"); 
     1805        my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file); 
     1806        if (!open(TARGET_FILE, ">$target_file_path")) { 
     1807            &throw_fatal_error("Could not write target file $target_file_path."); 
     1808        } 
     1809         
     1810        # Model the new target file on the source file, with the target file translations 
     1811        my $source_file_line_number = 0; 
     1812        foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) { 
     1813            # Fill in the gaps before this chunk starts 
     1814            my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0]; 
     1815            my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1]; 
     1816            while ($source_file_line_number < $source_file_chunk_starting_line_number) { 
     1817                print TARGET_FILE $source_file_lines[$source_file_line_number]; 
     1818                $source_file_line_number++; 
     1819            } 
     1820            $source_file_line_number = $source_file_chunk_finishing_line_number + 1; 
     1821             
     1822            my $chunk_key = $source_file_line_to_key_mapping{$line_key}; 
     1823            my $global_chunk_key = "$interface_file_key.$chunk_key"; 
     1824            my $source_file_chunk_text = $source_file_key_to_text_mapping->{$global_chunk_key}; 
     1825            my $target_file_chunk_text = $target_file_key_to_text_mapping->{$global_chunk_key} || ""; 
     1826             
     1827            # If no translation exists for this chunk, show this, and move on 
     1828            if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") { 
     1829                print TARGET_FILE "# -- Missing translation: $chunk_key\n"; 
     1830                next; 
     1831            } 
     1832             
     1833            print TARGET_FILE "$chunk_key:$target_file_chunk_text"; 
     1834            if ($target_file_key_to_gti_comment_mapping->{$global_chunk_key}) { 
     1835                print TARGET_FILE "  # " . $target_file_key_to_gti_comment_mapping->{$global_chunk_key}; 
     1836            } 
     1837            print TARGET_FILE "\n"; 
     1838        } 
     1839         
     1840        close(TARGET_FILE);  
    18641841    }            
    18651842}