source: main/trunk/greenstone2/bin/script/gti.pl@ 28977

Last change on this file since 28977 was 28977, checked in by ak19, 10 years ago
  1. gti.pl expected an svn checked-out folder containing scripts in gsdlhome/gti-lib, which can exist as gli/shared when generate-html.sh is run. 2. Removed hardcoded reference of full path to the custom/gti folder on puka, as this is simply gsdlhome.
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 85.4 KB
Line 
1#!/usr/bin/perl -w
2
3###########################################################################
4#
5# gti.pl
6#
7# A component of the Greenstone digital library software
8# from the New Zealand Digital Library Project at the
9# University of Waikato, New Zealand.
10#
11# Copyright (C) 2005 New Zealand Digital Library Project
12#
13# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License as published by
15# the Free Software Foundation; either version 2 of the License, or
16# (at your option) any later version.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26#
27###########################################################################
28
29
30BEGIN {
31 die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
32 unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
33}
34
35
36use iso639;
37use strict;
38use util;
39
40my $gsdl_root_directory = "$ENV{'GSDLHOME'}";
41my $gti_log_file = &util::filename_cat($gsdl_root_directory, "etc", "gti.log");
42my $source_language_code = "en"; # This is non-negotiable
43
44my $gti_translation_files =
45[ # Greenstone macrofiles
46{ 'key' => "coredm",
47 'file_type' => "macrofile",
48 'source_file' => "macros/english.dm",
49 '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" },
50
51{ 'key' => "auxdm",
52 'file_type' => "macrofile",
53 'source_file' => "macros/english2.dm",
54 '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" },
55
56{ 'key' => "paperspastdm",
57 'file_type' => "macrofile",
58 'source_file' => "macros/paperspast-english.dm",
59 'target_file' => "macros/paperspast-{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" },
60
61# GLI dictionary
62{ 'key' => "glidict",
63 'file_type' => "resource_bundle",
64 'source_file' => "gli/classes/dictionary.properties",
65 'target_file' => "gli/classes/dictionary_{target_language_code}.properties" },
66
67# GLI help
68{ 'key' => "glihelp",
69 'file_type' => "greenstone_xml",
70 'source_file' => "gli/help/en/help.xml",
71 'target_file' => "gli/help/{target_language_code}/help.xml" },
72
73# Greenstone Perl modules
74{ 'key' => "perlmodules",
75 'file_type' => "resource_bundle",
76 'source_file' => "perllib/strings.properties",
77 'target_file' => "perllib/strings_{target_language_code}.properties" },
78
79# Greenstone Installer interface
80{ 'key' => "gsinstaller",
81 'file_type' => "resource_bundle",
82 'source_file' => "gsinstaller/LanguagePack.properties",
83 'target_file' => "gsinstaller/LanguagePack_{target_language_code}.properties" },
84
85# Greenstone tutorial exercises
86# { 'key' => "tutorials",
87# 'file_type' => "greenstone_xml",
88# 'source_file' => "gsdl-documentation/tutorials/xml-source/tutorial_en.xml",
89# 'target_file' => "gsdl-documentation/tutorials/xml-source/tutorial_{target_language_code}.xml" },
90
91# new Greenstone.org
92{ 'key' => "greenorg",
93 'file_type' => "resource_bundle",
94 'source_file' => "greenstoneorg/website/classes/Gsc.properties",
95 'target_file' => "greenstoneorg/website/classes/Gsc_{target_language_code}.properties"
96}
97
98# { 'key' => "gs3interface",
99#'file_type' => "resource_bundle",
100#'source_file' => "greenstone3",
101#'target_file' => "greenstone3"
102#}
103];
104
105my @gs3_interface_files = ("AbstractBrowse", "AbstractGS2FieldSearch", "AbstractSearch", "Authentication", "CrossCollectionSearch", "GS2Construct", "GS2LuceneSearch", "interface_default", "interface_default2", "IViaSearch", "LuceneSearch", "MapRetrieve", "MapSearch", "metadata_names", "PhindPhraseBrowse", "SharedSoleneGS2FieldSearch");
106
107# Auxilliary GS3 interface files. This list is not used at present
108# Combine with above list if generating translation spreadsheet for all interface files
109my @gs3_aux_interface_files = ("GATEServices", "interface_basic", "interface_basic2", "interface_nzdl", "interface_gs2", "QBRWebServicesHelp", "Visualizer");
110
111# Not: i18n, log4j
112
113sub main
114{
115 # Get the command to process, and any arguments
116 my $gti_command = shift(@_);
117 my @gti_command_arguments = @_;
118 my $module = $_[1];
119
120 # for GS3, set gsdl_root_dir to GSDL3HOME
121 if($module && $module eq "gs3interface"){ # module is empty when the gti-command is create-glihelp-zip-file
122 if($ENV{'GSDL3SRCHOME'}) {
123 $gsdl_root_directory = (defined $ENV{'GSDL3HOME'}) ? $ENV{'GSDL3HOME'} : &util::filename_cat($ENV{'GSDL3SRCHOME'}, "web");
124 $gti_log_file = &util::filename_cat($gsdl_root_directory, "logs", "gti.log");
125 }
126 }
127
128 # Open the GTI log file for appending, or write to STDERR if that fails
129 if (!open(GTI_LOG, ">>$gti_log_file")) {
130 open(GTI_LOG, ">&STDERR");
131 }
132
133 # Log the command that launched this script
134 &log_message("Command: $0 @ARGV");
135
136 # Check that a command was supplied
137 if (!$gti_command) {
138 &throw_fatal_error("Missing command.");
139 }
140
141 # Process the command
142 if ($gti_command =~ /^get-all-chunks$/i) {
143 # Check that GS3 interface is the target
144 if ($module eq "gs3interface") {
145 print &get_all_chunks_for_gs3(@gti_command_arguments);
146 } else {
147 print &get_all_chunks(@gti_command_arguments);
148 }
149 }
150 elsif ($gti_command =~ /^get-first-n-chunks-requiring-work$/i) {
151 if ($module eq "gs3interface") {
152 print &get_first_n_chunks_requiring_work_for_gs3(@gti_command_arguments);
153 } else {
154 print &get_first_n_chunks_requiring_work(@gti_command_arguments);
155 }
156 }
157 elsif ($gti_command =~ /^get-uptodate-chunks$/i) {
158 if ($module eq "gs3interface") {
159 print &get_uptodate_chunks_for_gs3(@gti_command_arguments);
160 } else {
161 print &get_uptodate_chunks(@gti_command_arguments);
162 }
163 }
164 elsif ($gti_command =~ /^get-language-status$/i) {
165 print &get_language_status(@gti_command_arguments);
166 }
167 elsif ($gti_command =~ /^search-chunks$/i) {
168 print &search_chunks(@gti_command_arguments);
169 }
170 elsif ($gti_command =~ /^submit-translations$/i) {
171 # This command cannot produce any output since it reads input
172 &submit_translations(@gti_command_arguments);
173 }
174 elsif ($gti_command =~ /^create-glihelp-zip-file$/i) {
175 # This command cannot produce any output since it reads input
176 &create_glihelp_zip_file(@gti_command_arguments);
177 }
178 else {
179 # The command was not recognized
180 &throw_fatal_error("Unknown command \"$gti_command\".");
181 }
182}
183
184
185sub throw_fatal_error
186{
187 my $error_message = shift(@_);
188
189 # Write an XML error response
190 print "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
191 print "<GTIResponse>\n";
192 print " <GTIError time=\"" . time() . "\">" . $error_message . "</GTIError>\n";
193 print "</GTIResponse>\n";
194
195 # Log the error message, then die
196 &log_message("Error: $error_message");
197 die "\n";
198}
199
200
201sub log_message
202{
203 my $log_message = shift(@_);
204 print GTI_LOG time() . " -- " . $log_message . "\n";
205}
206
207
208sub get_all_chunks
209{
210 # The code of the target language (ensure it is lowercase)
211 my $target_language_code = lc(shift(@_));
212 # The key of the file to translate (ensure it is lowercase)
213 my $translation_file_key = lc(shift(@_));
214
215 # Check that the necessary arguments were supplied
216 if (!$target_language_code || !$translation_file_key) {
217 &throw_fatal_error("Missing command argument.");
218 }
219
220 # Get (and check) the translation configuration
221 my ($source_file, $target_file, $translation_file_type)
222 = &get_translation_configuration($target_language_code, $translation_file_key);
223
224 # Parse the source language and target language files
225 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
226 my @source_file_lines = &read_file_lines($source_file_path);
227 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
228
229 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
230 my @target_file_lines = &read_file_lines($target_file_path);
231 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
232
233 # Filter out any automatically translated chunks
234 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
235 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
236 delete $source_file_key_to_line_mapping{$chunk_key};
237 delete $target_file_key_to_line_mapping{$chunk_key};
238 }
239 }
240
241 my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
242 my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
243 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
244 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
245
246 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);
247 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);
248
249 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);
250
251 return $xml_response;
252}
253
254
255sub get_uptodate_chunks
256{
257 # The code of the target language (ensure it is lowercase)
258 my $target_language_code = lc(shift(@_));
259 # The key of the file to translate (ensure it is lowercase)
260 my $translation_file_key = lc(shift(@_));
261
262 # Check that the necessary arguments were supplied
263 if (!$target_language_code || !$translation_file_key) {
264 &throw_fatal_error("Missing command argument.");
265 }
266
267 # Get (and check) the translation configuration
268 my ($source_file, $target_file, $translation_file_type)
269 = &get_translation_configuration($target_language_code, $translation_file_key);
270
271 # Parse the source language and target language files
272 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
273 my @source_file_lines = &read_file_lines($source_file_path);
274 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
275
276 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
277 my @target_file_lines = &read_file_lines($target_file_path);
278 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
279
280 # Filter out any automatically translated chunks
281 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
282 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
283 delete $source_file_key_to_line_mapping{$chunk_key};
284 delete $target_file_key_to_line_mapping{$chunk_key};
285 }
286 }
287
288 my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
289 my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
290 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
291 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
292
293 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);
294 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);
295
296
297 # Chunks needing updating are those in the target file that have been more recently edited in the source file
298 # All others are uptodate (which implies that they have certainly been translated at some point and would not be empty)
299 my @uptodate_target_file_keys = ();
300 foreach my $chunk_key (keys(%source_file_key_to_last_update_date_mapping)) {
301 my $source_chunk_last_update_date = $source_file_key_to_last_update_date_mapping{$chunk_key};
302 my $target_chunk_last_update_date = $target_file_key_to_last_update_date_mapping{$chunk_key};
303
304 # 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";
305
306 if (defined($target_chunk_last_update_date) && !&is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) {
307 # &log_message("Chunk with key $chunk_key needs updating.");
308 push(@uptodate_target_file_keys, $chunk_key);
309 }
310 }
311
312 my $xml_response = &create_xml_response_for_uptodate_chunks($translation_file_key, $target_file, \@uptodate_target_file_keys, \%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);
313
314 return $xml_response;
315}
316
317
318sub get_first_n_chunks_requiring_work
319{
320 # The code of the target language (ensure it is lowercase)
321 my $target_language_code = lc(shift(@_));
322 # The key of the file to translate (ensure it is lowercase)
323 my $translation_file_key = lc(shift(@_));
324 # The number of chunks to return (defaults to one if not specified)
325 my $num_chunks_to_return = shift(@_) || "1";
326
327 # Check that the necessary arguments were supplied
328 if (!$target_language_code || !$translation_file_key) {
329 &throw_fatal_error("Missing command argument.");
330 }
331
332 # Get (and check) the translation configuration
333 my ($source_file, $target_file, $translation_file_type)
334 = &get_translation_configuration($target_language_code, $translation_file_key);
335
336 # Parse the source language and target language files
337 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
338 my @source_file_lines = &read_file_lines($source_file_path);
339 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
340
341 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
342 my @target_file_lines = &read_file_lines($target_file_path);
343 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
344
345 # Filter out any automatically translated chunks
346 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
347 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
348 delete $source_file_key_to_line_mapping{$chunk_key};
349 delete $target_file_key_to_line_mapping{$chunk_key};
350 }
351 }
352
353 my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
354 my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
355 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
356 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
357
358 # Determine the target file chunks requiring translation
359 my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);
360 &log_message("Number of target chunks requiring translation: " . scalar(@target_file_keys_requiring_translation));
361
362 # Determine the target file chunks requiring updating
363 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);
364 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);
365 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);
366 &log_message("Number of target chunks requiring updating: " . scalar(@target_file_keys_requiring_updating));
367
368 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);
369
370 return $xml_response;
371}
372
373
374sub get_language_status
375{
376 # The code of the target language (ensure it is lowercase)
377 my $target_language_code = lc(shift(@_));
378
379 # Check that the necessary arguments were supplied
380 if (!$target_language_code) {
381 &throw_fatal_error("Missing command argument.");
382 }
383
384 # Form an XML response to the command
385 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
386 $xml_response .= "<GTIResponse>\n";
387 $xml_response .= " <LanguageStatus code=\"$target_language_code\">\n";
388
389 foreach my $translation_file (@$gti_translation_files) {
390 my ($num_source_chunks, $num_target_chunks, $num_chunks_requiring_translation, $num_chunks_requiring_updating) = 0;
391 my $target_file_name = "";
392
393 if ($translation_file->{'key'} eq "gs3interface") {
394 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 ) = ();
395 &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 );
396
397 my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);
398 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);
399
400 $num_source_chunks = scalar(keys(%source_file_key_to_text_mapping));
401 $num_target_chunks = scalar(keys(%target_file_key_to_text_mapping));
402 $num_chunks_requiring_translation = scalar(@target_file_keys_requiring_translation);
403 $num_chunks_requiring_updating = scalar(@target_file_keys_requiring_updating);
404 }
405 else {
406 # Get (and check) the translation configuration
407 my ($source_file, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file->{'key'});
408 $target_file_name = $target_file;
409
410 # Parse the source language and target language files
411 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
412 my @source_file_lines = &read_file_lines($source_file_path);
413 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
414
415 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
416 my @target_file_lines = &read_file_lines($target_file_path);
417 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
418
419 # Filter out any automatically translated chunks
420 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
421 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
422 delete $source_file_key_to_line_mapping{$chunk_key};
423 delete $target_file_key_to_line_mapping{$chunk_key};
424 }
425 }
426
427 my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
428 my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
429
430 # Determine the target file chunks requiring translation
431 my @target_file_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping);
432
433 # Determine the target file chunks requiring updating
434 my @target_file_keys_requiring_updating = ();
435 if (-e $target_file_path) {
436 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);
437 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);
438 @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);
439 }
440
441 $num_source_chunks = scalar(keys(%source_file_key_to_text_mapping));
442 $num_target_chunks = scalar(keys(%target_file_key_to_text_mapping));
443 $num_chunks_requiring_translation = scalar(@target_file_keys_requiring_translation);
444 $num_chunks_requiring_updating = scalar(@target_file_keys_requiring_updating);
445 }
446
447 &log_message("Status of " . $translation_file->{'key'});
448 &log_message("Number of source chunks: " . $num_source_chunks);
449 &log_message("Number of target chunks: " . $num_target_chunks);
450 &log_message("Number of target chunks requiring translation: " . $num_chunks_requiring_translation);
451 &log_message("Number of target chunks requiring updating: " . $num_chunks_requiring_updating);
452
453 $xml_response .= " <TranslationFile"
454 . " key=\"" . $translation_file->{'key'} . "\""
455 . " target_file_path=\"" . $target_file_name . "\""
456 . " num_chunks_translated=\"" . ($num_source_chunks - $num_chunks_requiring_translation) . "\""
457 . " num_chunks_requiring_translation=\"" . $num_chunks_requiring_translation . "\""
458 . " num_chunks_requiring_updating=\"" . $num_chunks_requiring_updating . "\"\/>\n";
459 }
460
461 $xml_response .= " </LanguageStatus>\n";
462
463 $xml_response .= "</GTIResponse>\n";
464 return $xml_response;
465}
466
467
468sub search_chunks
469{
470 # The code of the target language (ensure it is lowercase)
471 my $target_language_code = lc(shift(@_));
472 # The key of the file to translate (ensure it is lowercase)
473 my $translation_file_key = lc(shift(@_));
474 # The query string
475 my $query_string = join(' ', @_);
476
477 # Check that the necessary arguments were supplied
478 if (!$target_language_code || !$translation_file_key || !$query_string) {
479 &throw_fatal_error("Missing command argument.");
480 }
481
482 my ($source_file, $target_file, $translation_file_type) = ();
483 my %source_file_key_to_text_mapping = ();
484 my %target_file_key_to_text_mapping = ();
485
486
487 if ($translation_file_key ne "gs3interface") {
488 # Get (and check) the translation configuration
489 ($source_file, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file_key);
490
491 # Parse the source language and target language files
492 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
493 my @source_file_lines = &read_file_lines($source_file_path);
494 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
495
496 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
497 my @target_file_lines = &read_file_lines($target_file_path);
498 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
499
500 # Filter out any automatically translated chunks
501 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
502 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
503 delete $source_file_key_to_line_mapping{$chunk_key};
504 delete $target_file_key_to_line_mapping{$chunk_key};
505 }
506 }
507
508 %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
509 %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
510 }
511 else {
512 # Not needed in this case
513 my (%source_file_key_to_gti_command_mapping, %target_file_key_to_gti_command_mapping) = ();
514 &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping,
515 \%source_file_key_to_gti_command_mapping, \%target_file_key_to_gti_command_mapping);
516 }
517
518 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
519 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
520
521 # Determine the target file chunks matching the query
522 my @target_file_keys_matching_query = ();
523 foreach my $chunk_key (keys(%target_file_key_to_text_mapping)) {
524 my $target_file_text = $target_file_key_to_text_mapping{$chunk_key};
525 if ($target_file_text =~ /$query_string/i) {
526 # &log_message("Chunk with key $chunk_key matches query.");
527 push(@target_file_keys_matching_query, $chunk_key);
528 }
529 }
530
531 # Form an XML response to the command
532 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
533 $xml_response .= "<GTIResponse>\n";
534
535 $xml_response .= " <ChunksMatchingQuery size=\"" . scalar(@target_file_keys_matching_query) . "\">\n";
536 foreach my $chunk_key (@target_file_keys_matching_query) {
537 my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping{$chunk_key});
538
539 $xml_response .= " <Chunk key=\"$chunk_key\">\n";
540 $xml_response .= " <TargetFileText>$target_file_chunk_text</TargetFileText>\n";
541 $xml_response .= " </Chunk>\n";
542 }
543 $xml_response .= " </ChunksMatchingQuery>\n";
544
545 $xml_response .= "</GTIResponse>\n";
546 return $xml_response;
547}
548
549
550sub submit_translations
551{
552 # The code of the target language (ensure it is lowercase)
553 my $target_language_code = lc(shift(@_));
554 # The key of the file to translate (ensure it is lowercase)
555 my $translation_file_key = lc(shift(@_));
556 # The username of the translation submitter
557 my $submitter_username = shift(@_);
558 # Whether to submit a target chunk even if it hasn't changed
559 my $force_submission_flag = shift(@_);
560
561 # Check that the necessary arguments were supplied
562 if (!$target_language_code || !$translation_file_key || !$submitter_username) {
563 &log_message("Fatal error (but cannot be thrown): Missing command argument.");
564 die "\n";
565 }
566
567 my %source_file_key_to_text_mapping = ();
568 my %source_file_key_to_gti_comment_mapping = ();
569 my %target_file_key_to_text_mapping = ();
570 my %target_file_key_to_gti_comment_mapping = ();
571
572 my (@source_file_lines, @target_file_lines) = ();
573 my ($source_file, $target_file, $translation_file_type);
574
575
576 if ($translation_file_key ne "gs3interface") {
577 # Get (and check) the translation configuration
578 ($source_file, $target_file, $translation_file_type)
579 = &get_translation_configuration($target_language_code, $translation_file_key);
580
581 # Parse the source language and target language files
582 @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file));
583 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
584 %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
585 %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);
586
587 @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file));
588 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
589 %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
590 %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);
591 }
592 else {
593 &build_gs3_configuration($target_language_code, \%source_file_key_to_text_mapping, \%target_file_key_to_text_mapping,
594 \%source_file_key_to_gti_comment_mapping, \%target_file_key_to_gti_comment_mapping);
595 }
596 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
597 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
598
599 # Submission date
600 my $day = (localtime)[3];
601 my $month = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")[(localtime)[4]];
602 my $year = (localtime)[5] + 1900;
603 my $submission_date = "$day-$month-$year";
604
605 open(SUBMISSION, "-");
606 my @submission_lines = <SUBMISSION>;
607 close(SUBMISSION);
608
609 # Remove any nasty carriage returns
610 # &log_message("Submission:");
611 foreach my $submission_line (@submission_lines) {
612 $submission_line =~ s/\r$//;
613 #&log_message(" $submission_line");
614 }
615
616 my %source_file_key_to_submission_mapping = ();
617 my %target_file_key_to_submission_mapping = ();
618 for (my $i = 0; $i < scalar(@submission_lines); $i++) {
619 # Read source file part of submission
620 if ($submission_lines[$i] =~ /^\<SourceFileText key=\"(.+)\"\>/) {
621 my $chunk_key = $1;
622
623 # Read the source file text
624 my $source_file_chunk_text = "";
625 $i++;
626 while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/SourceFileText\>/) {
627 $source_file_chunk_text .= $submission_lines[$i];
628 $i++;
629 }
630 $source_file_chunk_text =~ s/\n$//; # Strip the extra newline character added
631 $source_file_chunk_text = &unmake_text_xml_safe($source_file_chunk_text);
632
633 #&log_message("Source file key: $chunk_key");
634 #&log_message("Source file text: $source_file_chunk_text");
635 $source_file_key_to_submission_mapping{$chunk_key} = $source_file_chunk_text;
636 }
637
638 # Read target file part of submission
639 if ($submission_lines[$i] =~ /^\<TargetFileText key=\"(.+)\"\>/) {
640 my $chunk_key = $1;
641
642 # Read the target file text
643 my $target_file_chunk_text = "";
644 $i++;
645 while ($i < scalar(@submission_lines) && $submission_lines[$i] !~ /^\<\/TargetFileText\>/) {
646 $target_file_chunk_text .= $submission_lines[$i];
647 $i++;
648 }
649 $target_file_chunk_text =~ s/\n$//; # Strip the extra newline character added
650 $target_file_chunk_text = &unmake_text_xml_safe($target_file_chunk_text);
651
652 #&log_message("Target file key: $chunk_key");
653 #&log_message("Target file text: $target_file_chunk_text");
654 $target_file_key_to_submission_mapping{$chunk_key} = $target_file_chunk_text;
655 }
656 }
657
658 # -----------------------------------------
659 # Validate the translation submissions
660 # -----------------------------------------
661
662 # Check that the translations are valid
663 foreach my $chunk_key (keys(%source_file_key_to_submission_mapping)) {
664 # Make sure the submitted chunk still exists in the source file
665 if (!defined($source_file_key_to_text_mapping{$chunk_key})) {
666 &log_message("Warning: Source chunk $chunk_key no longer exists (ignoring submission).");
667 delete $source_file_key_to_submission_mapping{$chunk_key};
668 delete $target_file_key_to_submission_mapping{$chunk_key};
669 next;
670 }
671
672 # Make sure the submitted source chunk matches the source file chunk
673 if ($source_file_key_to_submission_mapping{$chunk_key} ne &unmake_text_xml_safe($source_file_key_to_text_mapping{$chunk_key})) {
674 #if (&unmake_text_xml_safe($source_file_key_to_submission_mapping{$chunk_key}) ne &unmake_text_xml_safe($source_file_key_to_text_mapping{$chunk_key})) {
675 #print STDERR "**** $source_file_key_to_submission_mapping{$chunk_key}\n";
676 #print STDERR "**** " . &unmake_text_xml_safe($source_file_key_to_text_mapping{$chunk_key}) ."\n";
677
678 &log_message("Warning: Source chunk $chunk_key has changed (ignoring submission).");
679 &log_message("Submission source: $source_file_key_to_submission_mapping{$chunk_key}");
680 &log_message(" Source text: $source_file_key_to_text_mapping{$chunk_key}");
681 delete $source_file_key_to_submission_mapping{$chunk_key};
682 delete $target_file_key_to_submission_mapping{$chunk_key};
683 next;
684 }
685 }
686
687 # Apply the submitted translations
688 foreach my $chunk_key (keys(%target_file_key_to_submission_mapping)) {
689 # Only apply the submission if it is a change, unless -force_submission has been specified
690 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}) {
691 $target_file_key_to_text_mapping{$chunk_key} = $target_file_key_to_submission_mapping{$chunk_key};
692 $target_file_key_to_gti_comment_mapping{$chunk_key} = "Updated $submission_date by $submitter_username";
693 }
694 }
695
696 if ($translation_file_key ne "gs3interface") {
697 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)";
698 } else {
699 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)";
700 }
701}
702
703
704sub create_glihelp_zip_file
705{
706 my $target_language_code = shift(@_);
707 my $translation_file_key = "glihelp";
708
709 &log_message("Creating GLI Help zip file for $target_language_code");
710
711 my ($source_file, $target_file, $translation_file_type) = &get_translation_data_for($target_language_code, $translation_file_key);
712
713 my $classpath = &util::filename_cat($gsdl_root_directory, "gti-lib");
714 my $oldclasspath = $classpath;
715 if ( ! -e $classpath) {
716 $classpath = &util::filename_cat($gsdl_root_directory, "gli", "shared");
717 }
718 if ( ! -e $classpath) {
719 &throw_fatal_error("$classpath doesn't exist! (Neither does $oldclasspath.) Need the files in this directory (ApplyXLST and its related files) to create the zip file for GLI Help");
720 }
721
722 my $gli_help_directory = &util::filename_cat($gsdl_root_directory, "gli");
723 $gli_help_directory = &util::filename_cat($gli_help_directory, "help");
724
725 my $gen_many_html_xsl_filepath = &util::filename_cat($gli_help_directory, "gen-many-html.xsl");
726 if ( ! -e $gen_many_html_xsl_filepath) {
727 &throw_fatal_error("$gen_many_html_xsl_filepath doesn't exist! Need this file to create the zip file for GLI Help");
728 }
729
730 my $gen_index_xml_xsl_filepath = &util::filename_cat($gli_help_directory, "gen-index-xml.xsl");
731 my $split_script_filepath = &util::filename_cat($gli_help_directory, "splithelpdocument.pl");
732
733 my $target_file_directory = &util::filename_cat($gli_help_directory, $target_language_code);
734 $target_file_directory = $target_file_directory."/";
735
736 my $target_filepath = &util::filename_cat($gsdl_root_directory, $target_file);
737
738 my $perl_exec = &util::get_perl_exec();
739 my $java_exec = "java";
740 if(defined($ENV{'JAVA_HOME'}) && $ENV{'JAVA_HOME'} ne ""){
741 $java_exec = &util::filename_cat($ENV{'JAVA_HOME'}, "bin", "java");
742 }
743
744 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";
745 my $response = `$cmd`;
746
747 $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";
748 $response = `$cmd`;
749
750 #my $zip_file_path = "/greenstone/custom/gti/" . $target_language_code . "_GLIHelp.zip";
751 my $zip_file_path = &util::filename_cat($gsdl_root_directory, $target_language_code . "_GLIHelp.zip");
752 $cmd = "zip -rj $zip_file_path $target_file_directory -i \*.htm \*.xml";
753 $response = `$cmd`;
754}
755
756
757sub get_translation_configuration
758{
759 # Get the code of the target language
760 my $target_language_code = shift(@_);
761 # Get the key of the file to translate
762 my $translation_file_key = shift(@_);
763
764 # Read the translation data from the gti.cfg file
765 my ($source_file, $target_file, $translation_file_type) =
766 &get_translation_data_for($target_language_code, $translation_file_key);
767
768 # Check that the file to translate is defined in the gti.cfg file
769 if (!$source_file || !$target_file || !$translation_file_type) {
770 &throw_fatal_error("Missing or incomplete specification for translation file \"$translation_file_key\" in gti.pl.");
771 }
772
773 # Check that the source file exists
774 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
775 if (!-e $source_file_path) {
776 &throw_fatal_error("Source file $source_file_path does not exist.");
777 }
778
779 # Check that the source file is up to date
780 # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist
781 # unless ($translation_file_is_not_in_cvs) {
782 #my $source_file_cvs_status = `cd $gsdl_root_directory; cvs -d $anonymous_cvs_root update $source_file 2>/dev/null`;
783 my $source_file_cvs_status = `cd $gsdl_root_directory; svn status $source_file 2>/dev/null`;
784 if ($source_file_cvs_status =~ /^C /) {
785 &throw_fatal_error("Source file $source_file_path conflicts with the repository.");
786 }
787 if ($source_file_cvs_status =~ /^M /) {
788 &throw_fatal_error("Source file $source_file_path contains uncommitted changes.");
789 }
790 # }
791
792 return ($source_file, $target_file, $translation_file_type);
793}
794
795
796sub get_translation_data_for
797{
798 my ($target_language_code, $translation_file_key) = @_;
799
800 foreach my $translation_file (@$gti_translation_files) {
801 # If this isn't the correct translation file, move onto the next one
802 next if ($translation_file_key ne $translation_file->{'key'});
803
804 # Resolve the target language file
805 my $target_language_file = $translation_file->{'target_file'};
806 if ($target_language_file =~ /(\{.+\;.+\})/) {
807 my $unresolved_target_language_file_part = $1;
808
809 # Check for a special case for the target language code
810 if ($unresolved_target_language_file_part =~ /(\{|\;)$target_language_code:([^\;]+)(\;|\})/) {
811 my $resolved_target_language_file_part = $2;
812 $target_language_file =~ s/$unresolved_target_language_file_part/$resolved_target_language_file_part/;
813 }
814 # Otherwise use the last part as the default value
815 else {
816 my ($default_target_language_file_part) = $unresolved_target_language_file_part =~ /([^\;]+)\}/;
817 $target_language_file =~ s/$unresolved_target_language_file_part/\{$default_target_language_file_part\}/;
818 }
819 }
820
821 # Resolve instances of {iso_639_1_target_language_name}
822 my $iso_639_1_target_language_name = $iso639::fromiso639{$target_language_code};
823 $iso_639_1_target_language_name =~ tr/A-Z/a-z/ if $iso_639_1_target_language_name;
824 $target_language_file =~ s/\{iso_639_1_target_language_name\}/$iso_639_1_target_language_name/g;
825
826 # Resolve instances of {target_language_code}
827 $target_language_file =~ s/\{target_language_code\}/$target_language_code/g;
828
829 return ($translation_file->{'source_file'}, $target_language_file, $translation_file->{'file_type'});
830}
831
832return ();
833}
834
835
836sub read_file_lines
837{
838 my ($file_path) = @_;
839
840 if (!open(FILE_IN, "<$file_path")) {
841 &log_message("Note: Could not open file $file_path.");
842 return ();
843 }
844 my @file_lines = <FILE_IN>;
845 close(FILE_IN);
846
847 return @file_lines;
848}
849
850
851sub build_key_to_line_mapping
852{
853 my ($file_lines, $translation_file_type) = @_;
854 eval "return &build_key_to_line_mapping_for_${translation_file_type}(\@\$file_lines)";
855}
856
857
858sub build_key_to_text_mapping
859{
860 my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_;
861
862 my %key_to_text_mapping = ();
863 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 my $chunk_text = @$file_lines[$chunk_starting_line];
868 for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
869 $chunk_text .= @$file_lines[$l];
870 }
871
872 # Map from chunk key to text
873 eval "\$key_to_text_mapping{\${chunk_key}} = &import_chunk_from_${translation_file_type}(\$chunk_text)";
874 }
875
876 return %key_to_text_mapping;
877}
878
879
880sub build_key_to_last_update_date_mapping
881{
882 my ($file, $file_lines, $key_to_line_mapping, $translation_file_type) = @_;
883
884 # If the files aren't in CVS then we can't tell anything about what needs updating
885 # return () if ($translation_file_is_not_in_cvs);
886
887 # Build a mapping from key to CVS date
888 # Need to be careful with this mapping because the chunk keys won't necessarily all be valid
889 my %key_to_cvs_date_mapping = &build_key_to_cvs_date_mapping($file, $translation_file_type);
890
891 # Build a mapping from key to comment date
892 my %key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping($file_lines, $key_to_line_mapping, $translation_file_type);
893
894 # Build a mapping from key to last update date (the latter of the CVS date and comment date)
895 my %key_to_last_update_date_mapping = ();
896 foreach my $chunk_key (keys(%$key_to_line_mapping)) {
897 # Use the CVS date as a starting point
898 my $chunk_cvs_date = $key_to_cvs_date_mapping{$chunk_key};
899 $key_to_last_update_date_mapping{$chunk_key} = $chunk_cvs_date;
900
901 # If a comment date exists and it is after the CVS date, use that instead
902 # need to convert the comment date format to SVN format
903 my $chunk_gti_comment = $key_to_gti_comment_mapping{$chunk_key};
904 if (defined($chunk_gti_comment) && $chunk_gti_comment =~ /(\d?\d-\D\D\D-\d\d\d\d)/) {
905 my $chunk_comment_date = $1;
906 if ((!defined($chunk_cvs_date) || &is_date_after($chunk_comment_date, $chunk_cvs_date))) {
907 $key_to_last_update_date_mapping{$chunk_key} = $chunk_comment_date;
908 }
909 }
910 }
911
912 return %key_to_last_update_date_mapping;
913}
914
915
916sub build_key_to_cvs_date_mapping
917{
918 my ($filename, $translation_file_type) = @_;
919
920 # Use SVN to annotate each line of the file with the date it was last edited
921 # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist
922 my $cvs_annotated_file = `cd $gsdl_root_directory; svn annotate -v --force $filename 2>/dev/null`;
923
924 my @cvs_annotated_file_lines = split(/\n/, $cvs_annotated_file);
925
926 my @cvs_annotated_file_lines_date = ();
927 foreach my $cvs_annotated_file_line (@cvs_annotated_file_lines) {
928 # Extract the date from the SVN annotation at the front
929 # svn format : 2007-07-16
930 $cvs_annotated_file_line =~ s/^\s+\S+\s+\S+\s(\S+)//;
931
932 push(@cvs_annotated_file_lines_date, $1);
933
934 # trim extra date information in svn annotation format
935 # 15:42:49 +1200 (Wed, 21 Jun 2006)
936 $cvs_annotated_file_line =~ s/^\s+\S+\s\S+\s\((.+?)\)\s//;
937 }
938
939 # Build a key to line mapping for the CVS annotated file, for matching the chunk key to the CVS date
940 my %key_to_line_mapping = &build_key_to_line_mapping(\@cvs_annotated_file_lines, $translation_file_type);
941
942 my %key_to_cvs_date_mapping = ();
943 foreach my $chunk_key (keys(%key_to_line_mapping)) {
944 my $chunk_starting_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[0];
945 my $chunk_finishing_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[1];
946
947 # Find the date this chunk was last edited, from the CVS annotation
948 my $chunk_date = $cvs_annotated_file_lines_date[$chunk_starting_line];
949 for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
950 if (&is_date_after($cvs_annotated_file_lines_date[$l], $chunk_date)) {
951 # This part of the chunk has been updated more recently
952 $chunk_date = $cvs_annotated_file_lines_date[$l];
953
954 }
955 }
956
957 # Map from chunk key to CVS date
958 $key_to_cvs_date_mapping{$chunk_key} = $chunk_date;
959 }
960
961 return %key_to_cvs_date_mapping;
962}
963
964
965sub build_key_to_gti_comment_mapping
966{
967 my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_;
968
969 my %key_to_gti_comment_mapping = ();
970 foreach my $chunk_key (keys(%$key_to_line_mapping)) {
971 my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0];
972 my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1];
973
974 my $chunk_text = @$file_lines[$chunk_starting_line];
975 for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
976 $chunk_text .= @$file_lines[$l];
977 }
978
979 # Map from chunk key to GTI comment
980 my $chunk_gti_comment;
981 eval "\$chunk_gti_comment = &get_${translation_file_type}_chunk_gti_comment(\$chunk_text)";
982 $key_to_gti_comment_mapping{$chunk_key} = $chunk_gti_comment if (defined($chunk_gti_comment));
983 }
984
985 return %key_to_gti_comment_mapping;
986}
987
988
989sub determine_chunks_requiring_translation
990{
991 my $source_file_key_to_text_mapping = shift(@_);
992 my $target_file_key_to_text_mapping = shift(@_);
993
994 # Chunks needing translation are those in the source file with no translation in the target file
995 my @target_file_keys_requiring_translation = ();
996 foreach my $chunk_key (keys(%$source_file_key_to_text_mapping)) {
997 if ($source_file_key_to_text_mapping->{$chunk_key} && !$target_file_key_to_text_mapping->{$chunk_key}) {
998 # &log_message("Chunk with key $chunk_key needs translating.");
999 push(@target_file_keys_requiring_translation, $chunk_key);
1000 }
1001 }
1002
1003 return @target_file_keys_requiring_translation;
1004}
1005
1006
1007sub determine_chunks_requiring_updating
1008{
1009 my $source_file_key_to_last_update_date_mapping = shift(@_);
1010 my $target_file_key_to_last_update_date_mapping = shift(@_);
1011
1012 # Chunks needing updating are those in the target file that have been more recently edited in the source file
1013 my @target_file_keys_requiring_updating = ();
1014 foreach my $chunk_key (keys(%$source_file_key_to_last_update_date_mapping)) {
1015 my $source_chunk_last_update_date = $source_file_key_to_last_update_date_mapping->{$chunk_key};
1016 my $target_chunk_last_update_date = $target_file_key_to_last_update_date_mapping->{$chunk_key};
1017
1018 # 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";
1019
1020 if (defined($target_chunk_last_update_date) && &is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) {
1021 # &log_message("Chunk with key $chunk_key needs updating.");
1022 push(@target_file_keys_requiring_updating, $chunk_key);
1023 }
1024 }
1025
1026 return @target_file_keys_requiring_updating;
1027}
1028
1029
1030sub is_chunk_automatically_translated
1031{
1032 my ($chunk_key, $translation_file_type) = @_;
1033 eval "return &is_${translation_file_type}_chunk_automatically_translated(\$chunk_key)";
1034}
1035
1036
1037sub make_text_xml_safe
1038{
1039 my $text = shift(@_);
1040 $text =~ s/\&/\&amp\;/g;
1041 $text =~ s/\&amp\;lt\;/\&amp\;amp\;lt\;/g;
1042 $text =~ s/\&amp\;gt\;/\&amp\;amp\;gt\;/g;
1043 $text =~ s/\&amp\;rarr\;/\&amp\;amp\;rarr\;/g;
1044 $text =~ s/\&amp\;mdash\;/\&amp\;amp\;mdash\;/g;
1045 $text =~ s/</\&lt\;/g;
1046 $text =~ s/>/\&gt\;/g;
1047 return $text;
1048}
1049
1050
1051sub unmake_text_xml_safe
1052{
1053 my $text = shift(@_);
1054 $text =~ s/\&lt\;/</g;
1055 $text =~ s/\&gt\;/>/g;
1056 $text =~ s/\&amp\;/\&/g;
1057 return $text;
1058}
1059
1060
1061# Returns 1 if $date1 is after $date2, 0 otherwise
1062sub is_date_after_cvs
1063{
1064 my ($date1, $date2) = @_;
1065 my %months = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr", 4, "May", 5, "Jun", 6,
1066 "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12);
1067
1068 if(!defined $date1) {
1069 return 1;
1070 }
1071
1072 my @date1parts = split(/-/, $date1);
1073 my @date2parts = split(/-/, $date2);
1074
1075 # Compare year - nasty because we have rolled over into a new century
1076 my $year1 = $date1parts[2];
1077 if ($year1 < 80) {
1078 $year1 += 2000;
1079 }
1080 my $year2 = $date2parts[2];
1081 if ($year2 < 80) {
1082 $year2 += 2000;
1083 }
1084
1085 # Compare year
1086 if ($year1 > $year2) {
1087 return 1;
1088 }
1089 elsif ($year1 == $year2) {
1090 # Year is the same, so compare month
1091 if ($months{$date1parts[1]} > $months{$date2parts[1]}) {
1092 return 1;
1093 }
1094 elsif ($months{$date1parts[1]} == $months{$date2parts[1]}) {
1095 # Month is the same, so compare day
1096 if ($date1parts[0] > $date2parts[0]) {
1097 return 1;
1098 }
1099 }
1100 }
1101
1102 return 0;
1103}
1104
1105sub is_date_after
1106{
1107 my ($date1, $date2) = @_;
1108
1109 if(!defined $date1) {
1110 return 1;
1111 }
1112 if(!defined $date2) {
1113 return 0;
1114 }
1115
1116 # 16-Aug-2006
1117 if($date1=~ /(\d+?)-(\S\S\S)-(\d\d\d\d)/){
1118 my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr", "04", "May", "05", "Jun", "06",
1119 "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12");
1120 $date1=$3 . "-" . $months{$2} . "-" . $1;
1121 # print "** converted date1: $date1\n";
1122 }
1123 if($date2=~ /(\d+?)-(\S\S\S)-(\d\d\d\d)/){
1124 my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr", "04", "May", "05", "Jun", "06",
1125 "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12");
1126 $date2=$3 . "-" . $months{$2} . "-" . $1;
1127 # print "** converted date2: $date2\n";
1128 }
1129
1130
1131 # 2006-08-16
1132 my @date1parts = split(/-/, $date1);
1133 my @date2parts = split(/-/, $date2);
1134
1135 # Compare year
1136 if ($date1parts[0] > $date2parts[0]) {
1137 return 1;
1138 }
1139 elsif ($date1parts[0] == $date2parts[0]) {
1140 # Year is the same, so compare month
1141 if ($date1parts[1] > $date2parts[1]) {
1142 return 1;
1143 }
1144 elsif ($date1parts[1] == $date2parts[1]) {
1145 # Month is the same, so compare day
1146 if ($date1parts[2] > $date2parts[2]) {
1147 return 1;
1148 }
1149 }
1150 }
1151
1152 return 0;
1153}
1154
1155
1156sub create_xml_response_for_chunks_requiring_work
1157{
1158 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) = @_;
1159
1160 # Form an XML response to the command
1161 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
1162 $xml_response .= "<GTIResponse>\n";
1163 $xml_response .= " <TranslationFile"
1164 . " key=\"" . $translation_file_key . "\""
1165 . " target_file_path=\"" . $target_file . "\""
1166 . " num_chunks_translated=\"" . ($total_num_chunks - scalar(@$target_files_keys_requiring_translation)) . "\""
1167 . " num_chunks_requiring_translation=\"" . scalar(@$target_files_keys_requiring_translation) . "\""
1168 . " num_chunks_requiring_updating=\"" . scalar(@$target_files_keys_requiring_updating) . "\"\/>\n";
1169
1170 # Do chunks requiring translation first
1171 if ($num_chunks_to_return > scalar(@$target_files_keys_requiring_translation)) {
1172 $xml_response .= " <ChunksRequiringTranslation size=\"" . scalar(@$target_files_keys_requiring_translation) . "\">\n";
1173 }
1174 else {
1175 $xml_response .= " <ChunksRequiringTranslation size=\"" . $num_chunks_to_return . "\">\n";
1176 }
1177
1178 my @sorted_chunk_keys = sort (@$target_files_keys_requiring_translation);
1179 foreach my $chunk_key (@sorted_chunk_keys) {
1180 last if ($num_chunks_to_return == 0);
1181
1182 my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1183 my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});
1184
1185 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1186 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1187 $xml_response .= " <TargetFileText></TargetFileText>\n";
1188 $xml_response .= " </Chunk>\n";
1189
1190 $num_chunks_to_return--;
1191 }
1192
1193 $xml_response .= " </ChunksRequiringTranslation>\n";
1194
1195 # Then do chunks requiring updating
1196 if ($num_chunks_to_return > scalar(@$target_files_keys_requiring_updating)) {
1197 $xml_response .= " <ChunksRequiringUpdating size=\"" . scalar(@$target_files_keys_requiring_updating) . "\">\n";
1198 }
1199 else {
1200 $xml_response .= " <ChunksRequiringUpdating size=\"" . $num_chunks_to_return . "\">\n";
1201 }
1202
1203 # foreach my $chunk_key (@target_file_keys_requiring_updating) {
1204 @sorted_chunk_keys = sort (@$target_files_keys_requiring_updating);
1205 foreach my $chunk_key (@sorted_chunk_keys) {
1206 last if ($num_chunks_to_return == 0);
1207
1208 my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1209 my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});
1210 my $target_file_chunk_date = $target_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1211 my $target_file_chunk_text = &make_text_xml_safe($target_files_key_to_text_mapping->{$chunk_key});
1212
1213 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1214 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1215 $xml_response .= " <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
1216 $xml_response .= " </Chunk>\n";
1217
1218 $num_chunks_to_return--;
1219 }
1220
1221 $xml_response .= " </ChunksRequiringUpdating>\n";
1222
1223 $xml_response .= "</GTIResponse>\n";
1224
1225 return $xml_response;
1226}
1227
1228sub create_xml_response_for_uptodate_chunks
1229{
1230 my ($translation_file_key, $target_file, $uptodate_target_files_keys, $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) = @_;
1231
1232 # Form an XML response to the command
1233 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
1234 $xml_response .= "<GTIResponse>\n";
1235 $xml_response .= " <TranslationFile"
1236 . " key=\"" . $translation_file_key . "\""
1237 . " target_file_path=\"" . $target_file . "\""
1238 . " num_chunks_uptodate=\"" . scalar(@$uptodate_target_files_keys) . "\"\/>\n";
1239
1240
1241 # Then do chunks requiring updating
1242 $xml_response .= " <UptodateChunks size=\"" . scalar(@$uptodate_target_files_keys) . "\">\n";
1243
1244
1245 # foreach my $chunk_key (@uptodate_target_file_keys) {
1246 my @sorted_chunk_keys = sort (@$uptodate_target_files_keys);
1247 foreach my $chunk_key (@sorted_chunk_keys) {
1248
1249 my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1250 my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});
1251 my $target_file_chunk_date = $target_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1252 my $target_file_chunk_text = &make_text_xml_safe($target_files_key_to_text_mapping->{$chunk_key});
1253
1254 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1255 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1256 $xml_response .= " <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
1257 $xml_response .= " </Chunk>\n";
1258
1259 }
1260
1261 $xml_response .= " </UptodateChunks>\n";
1262
1263 $xml_response .= "</GTIResponse>\n";
1264
1265 return $xml_response;
1266}
1267
1268sub create_xml_response_for_all_chunks
1269{
1270 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) = @_;
1271
1272 # Form an XML response to the command
1273 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
1274 $xml_response .= "<GTIResponse>\n";
1275 $xml_response .= " <TranslationFile"
1276 . " key=\"" . $translation_file_key . "\""
1277 . " target_file_path=\"" . $target_file . "\"\/>\n";
1278
1279 # Do all the chunks
1280 $xml_response .= " <Chunks size=\"" . scalar(keys(%$source_file_key_to_text_mapping)) . "\">\n";
1281
1282 my @sorted_chunk_keys = sort (keys(%$source_file_key_to_text_mapping));
1283 foreach my $chunk_key (@sorted_chunk_keys) {
1284 my $source_file_chunk_date = $source_file_key_to_last_update_date_mapping->{$chunk_key} || "";
1285 my $source_file_chunk_text = &make_text_xml_safe($source_file_key_to_text_mapping->{$chunk_key});
1286
1287 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1288 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1289 if (defined($target_file_key_to_text_mapping->{$chunk_key})) {
1290 my $target_file_chunk_date = $target_file_key_to_last_update_date_mapping->{$chunk_key} || "";
1291 my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping->{$chunk_key});
1292 $xml_response .= " <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
1293 }
1294 else {
1295 $xml_response .= " <TargetFileText></TargetFileText>\n";
1296 }
1297
1298 $xml_response .= " </Chunk>\n";
1299 }
1300 $xml_response .= " </Chunks>\n";
1301
1302 $xml_response .= "</GTIResponse>\n";
1303 return $xml_response;
1304}
1305
1306
1307
1308# ==========================================================================================
1309# MACROFILE FUNCTIONS
1310
1311sub build_key_to_line_mapping_for_macrofile
1312{
1313 my (@file_lines) = @_;
1314
1315 my $macro_package;
1316 my %chunk_key_to_line_mapping = ();
1317 # Process the contents of the file, line by line
1318 for (my $i = 0; $i < scalar(@file_lines); $i++) {
1319 my $line = $file_lines[$i];
1320 $line =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1321
1322 # Check if a new package is being defined
1323 if ($line =~ m/^package\s+(.+)/) {
1324 $macro_package = $1;
1325 }
1326
1327 # Line contains a macro name
1328 elsif ($line =~ m/^(_\w+_)/) {
1329 my $macro_key = $1;
1330 $line =~ s/\s*([^\\]\#[^\}]+)?$//; # Remove any comments and nasty whitespace
1331
1332 # While there is still text of the macro to go...
1333 my $startline = $i;
1334 while ($line !~ /\}$/) {
1335 $i++;
1336 if ($i == scalar(@file_lines)) {
1337 &throw_fatal_error("Could not find end of macro $macro_key.");
1338 }
1339 $line = $file_lines[$i];
1340 $line =~ s/\s*([^\\]\#[^\}]+)?$//; # Remove any comments and nasty whitespace
1341 }
1342
1343 # The chunk key consists of the package name and the macro key
1344 my $chunk_key = $macro_package . "." . $macro_key;
1345 # Map from chunk key to line
1346 $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i;
1347 }
1348
1349 # Icon: line in format ## "image text" ## image_type ## macro_name ##
1350 elsif ($line =~ m/^\#\# .* \#\# .* \#\# (.*) \#\#/) {
1351 # The chunk key consists of package name and macro key
1352 my $chunk_key = $macro_package . "." . $1;
1353 # Map from chunk key to line
1354 $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i;
1355}
1356}
1357
1358return %chunk_key_to_line_mapping;
1359}
1360
1361
1362sub import_chunk_from_macrofile
1363{
1364 my ($chunk_text) = @_;
1365
1366 # Is this an icon macro??
1367 if ($chunk_text =~ /^\#\# (.*)/) {
1368 # Extract image macro text
1369 $chunk_text =~ /^\#\#\s+([^\#]+)\s+\#\#/;
1370 $chunk_text = $1;
1371
1372 # Remove enclosing quotes
1373 $chunk_text =~ s/^\"//;
1374 $chunk_text =~ s/\"$//;
1375}
1376
1377# No, so it must be a text macro
1378else {
1379 # Remove macro key
1380 $chunk_text =~ s/^_([^_]+)_(\s*)//;
1381
1382 # Remove language specifier
1383 $chunk_text =~ s/^\[l=.*\](\s*)//;
1384
1385 # Remove braces enclosing text
1386 $chunk_text =~ s/^{(\s*)((.|\n)*)}(\s*)(\#.+\s*)?/$2/;
1387}
1388
1389return $chunk_text;
1390}
1391
1392
1393sub get_macrofile_chunk_gti_comment
1394{
1395 my ($chunk_text) = @_;
1396
1397 # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
1398 if ($chunk_text =~ /\#\s+(Updated\s+\d?\d-\D\D\D-\d\d\d\d.*)\s*$/i) {
1399 return $1;
1400}
1401
1402return undef;
1403}
1404
1405
1406sub is_macrofile_chunk_automatically_translated
1407{
1408 my ($chunk_key) = @_;
1409
1410 # The _httpiconX_, _widthX_ and _heightX_ image macros are automatically translated
1411 if ($chunk_key =~ /\._(httpicon|width|height)/) {
1412 return 1;
1413 }
1414
1415 return 0;
1416}
1417
1418
1419# Use the source file to generate a target file that is formatted the same
1420sub write_translated_macrofile
1421{
1422 my $source_file = shift(@_); # Not used
1423 my @source_file_lines = @{shift(@_)};
1424 my $source_file_key_to_text_mapping = shift(@_);
1425 my $target_file = shift(@_);
1426 my @target_file_lines = @{shift(@_)};
1427 my $target_file_key_to_text_mapping = shift(@_);
1428 my $target_file_key_to_gti_comment_mapping = shift(@_);
1429 my $target_language_code = shift(@_);
1430
1431 # Build a mapping from source file line to chunk key
1432 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@source_file_lines);
1433 my %source_file_line_to_key_mapping = ();
1434 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1435 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1436 }
1437 my @source_file_line_keys = (sort sort_by_line (keys(%source_file_line_to_key_mapping)));
1438 my $source_file_line_number = 0;
1439
1440 # Build a mapping from target file line to chunk key
1441 my %target_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@target_file_lines);
1442 my %target_file_line_to_key_mapping = ();
1443 foreach my $chunk_key (keys(%target_file_key_to_line_mapping)) {
1444 $target_file_line_to_key_mapping{$target_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1445 }
1446 my @target_file_line_keys = (sort sort_by_line (keys(%target_file_line_to_key_mapping)));
1447
1448 # Write the new target file
1449 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1450 if (!open(TARGET_FILE, ">$target_file_path")) {
1451 &throw_fatal_error("Could not write target file $target_file_path.");
1452 }
1453
1454 # Use the header from the target file, to keep language and author information
1455 if (scalar(@target_file_line_keys) > 0) {
1456 my $target_file_line_number = 0;
1457 my $target_file_chunk_starting_line_number = (split(/-/, $target_file_line_keys[0]))[0];
1458 while ($target_file_line_number < $target_file_chunk_starting_line_number) {
1459 my $target_file_line = $target_file_lines[$target_file_line_number];
1460 last if ($target_file_line =~ /^\# -- Missing translation: /); # We don't want to get into the macros
1461 print TARGET_FILE $target_file_line;
1462 $target_file_line_number++;
1463 }
1464
1465 $source_file_line_number = (split(/-/, $source_file_line_keys[0]))[0];
1466 }
1467
1468 # Model the new target file on the source file, with the target file translations
1469 foreach my $line_key (@source_file_line_keys) {
1470 # Fill in the gaps before this chunk starts
1471 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1472 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1473 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1474 print TARGET_FILE $source_file_lines[$source_file_line_number];
1475 $source_file_line_number++;
1476 }
1477 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
1478
1479 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
1480 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
1481 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
1482
1483 my $macrofile_key = $chunk_key;
1484 $macrofile_key =~ s/^(.+?)\.//;
1485
1486 # If no translation exists for this chunk, show this, and move on
1487 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
1488 print TARGET_FILE "# -- Missing translation: $macrofile_key\n";
1489 next;
1490 }
1491
1492 # Grab the source chunk text
1493 my $source_file_chunk = $source_file_lines[$source_file_chunk_starting_line_number];
1494 for (my $l = ($source_file_chunk_starting_line_number + 1); $l <= $source_file_chunk_finishing_line_number; $l++) {
1495 $source_file_chunk .= $source_file_lines[$l];
1496 }
1497
1498 # Is this an icon macro??
1499 if ($source_file_chunk =~ /^\#\# (.*)/) {
1500 # Escape any newline and question mark characters so the source text is replaced correctly
1501 $source_file_chunk_text =~ s/\\/\\\\/g;
1502 $source_file_chunk_text =~ s/\?/\\\?/g;
1503
1504 # Build the new target chunk from the source chunk
1505 my $target_file_chunk = $source_file_chunk;
1506 $target_file_chunk =~ s/$source_file_chunk_text/$target_file_chunk_text/;
1507 $target_file_chunk =~ s/(\s)*$//;
1508 print TARGET_FILE "$target_file_chunk";
1509 }
1510
1511 # No, it is just a normal text macro
1512 else {
1513 print TARGET_FILE "$macrofile_key [l=$target_language_code] {$target_file_chunk_text}";
1514 }
1515
1516 # Add the "updated" comment, if one exists
1517 if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) {
1518 print TARGET_FILE " # " . $target_file_key_to_gti_comment_mapping->{$chunk_key};
1519 }
1520 print TARGET_FILE "\n";
1521}
1522
1523close(TARGET_FILE);
1524}
1525
1526
1527sub sort_by_line
1528{
1529 return ((split(/-/, $a))[0] <=> (split(/-/, $b))[0]);
1530}
1531
1532
1533# ==========================================================================================
1534# RESOURCE BUNDLE FUNCTIONS
1535
1536sub build_key_to_line_mapping_for_resource_bundle
1537{
1538 my (@file_lines) = @_;
1539
1540 my %chunk_key_to_line_mapping = ();
1541 for (my $i = 0; $i < scalar(@file_lines); $i++) {
1542 my $line = $file_lines[$i];
1543 $line =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1544
1545 # Line contains a dictionary string
1546 if ($line =~ /^(\S+?)[:|=](.*)$/) {
1547 my $chunk_key = $1;
1548
1549 # Map from chunk key to line
1550 $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i;
1551 }
1552 }
1553
1554 return %chunk_key_to_line_mapping;
1555}
1556
1557
1558sub import_chunk_from_resource_bundle
1559{
1560 my ($chunk_text) = @_;
1561
1562 # Simple: just remove string key
1563 $chunk_text =~ s/^(\S+?)[:|=](\s*)//;
1564 $chunk_text =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1565 $chunk_text =~ s/(\s*)\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d.*)\s*$//i;
1566
1567 return $chunk_text;
1568}
1569
1570
1571sub get_resource_bundle_chunk_gti_comment
1572{
1573 my ($chunk_text) = @_;
1574
1575 # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
1576 if ($chunk_text =~ /\#\s+(Updated\s+\d?\d-\D\D\D-\d\d\d\d.*)\s*$/i) {
1577 return $1;
1578}
1579
1580return undef;
1581}
1582
1583
1584sub is_resource_bundle_chunk_automatically_translated
1585{
1586 # No resource bundle chunks are automatically translated
1587 return 0;
1588}
1589
1590
1591sub write_translated_resource_bundle
1592{
1593 my $source_file = shift(@_); # Not used
1594 my @source_file_lines = @{shift(@_)};
1595 my $source_file_key_to_text_mapping = shift(@_);
1596 my $target_file = shift(@_);
1597 my @target_file_lines = @{shift(@_)}; # Not used
1598 my $target_file_key_to_text_mapping = shift(@_);
1599 my $target_file_key_to_gti_comment_mapping = shift(@_);
1600 my $target_language_code = shift(@_); # Not used
1601
1602 # Build a mapping from chunk key to source file line, and from source file line to chunk key
1603 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines);
1604 my %source_file_line_to_key_mapping = ();
1605 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1606 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1607 }
1608
1609 # Write the new target file
1610 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1611 if (!open(TARGET_FILE, ">$target_file_path")) {
1612 &throw_fatal_error("Could not write target file $target_file_path.");
1613 }
1614
1615 # Model the new target file on the source file, with the target file translations
1616 my $source_file_line_number = 0;
1617 foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
1618 # Fill in the gaps before this chunk starts
1619 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1620 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1621 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1622 print TARGET_FILE $source_file_lines[$source_file_line_number];
1623 $source_file_line_number++;
1624 }
1625 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
1626
1627 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
1628 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
1629 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
1630
1631 # If no translation exists for this chunk, show this, and move on
1632 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
1633 print TARGET_FILE "# -- Missing translation: $chunk_key\n";
1634 next;
1635 }
1636
1637 print TARGET_FILE "$chunk_key:$target_file_chunk_text";
1638 if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) {
1639 print TARGET_FILE " # " . $target_file_key_to_gti_comment_mapping->{$chunk_key};
1640 }
1641 print TARGET_FILE "\n";
1642 }
1643
1644 close(TARGET_FILE);
1645}
1646
1647
1648# ==========================================================================================
1649# GREENSTONE XML FUNCTIONS
1650
1651sub build_key_to_line_mapping_for_greenstone_xml
1652{
1653 my (@file_lines) = @_;
1654
1655 my %chunk_key_to_line_mapping = ();
1656 for (my $i = 0; $i < scalar(@file_lines); $i++) {
1657 my $line = $file_lines[$i];
1658 $line =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1659
1660 # Line contains a string to translate
1661 if ($line =~ /^\s*<Text id=\"(.*?)\">/) {
1662 my $chunk_key = $1;
1663 $line =~ s/\s*$//; # Remove any nasty whitespace
1664 $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//;
1665
1666 # While there is still text of the string to go...
1667 my $startline = $i;
1668 while ($line !~ /<\/Text>$/) {
1669 $i++;
1670 if ($i == scalar(@file_lines)) {
1671 &throw_fatal_error("Could not find end of string $chunk_key.");
1672 }
1673 $line = $file_lines[$i];
1674 $line =~ s/\s*$//; # Remove any nasty whitespace
1675 $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//;
1676 }
1677
1678 # Map from chunk key to line
1679 if (!defined($chunk_key_to_line_mapping{$chunk_key})) {
1680 $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i;
1681 }
1682 else {
1683 &throw_fatal_error("Duplicate key $chunk_key.");
1684 }
1685 }
1686 }
1687
1688 return %chunk_key_to_line_mapping;
1689}
1690
1691
1692sub import_chunk_from_greenstone_xml
1693{
1694 my ($chunk_text) = @_;
1695
1696 # Simple: just remove the Text tags
1697 $chunk_text =~ s/^\s*<Text id=\"(.*?)\">(\s*)//;
1698 $chunk_text =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//;
1699 $chunk_text =~ s/<\/Text>$//;
1700
1701 return $chunk_text;
1702}
1703
1704
1705sub get_greenstone_xml_chunk_gti_comment
1706{
1707 my ($chunk_text) = @_;
1708
1709 # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
1710 if ($chunk_text =~ /<Updated date=\"(\d?\d-\D\D\D-\d\d\d\d.*)\"\/>$/i) {
1711 return $1;
1712 }
1713
1714 return undef;
1715}
1716
1717
1718sub is_greenstone_xml_chunk_automatically_translated
1719{
1720 # No greenstone XML chunks are automatically translated
1721 return 0;
1722}
1723
1724
1725sub write_translated_greenstone_xml
1726{
1727 my $source_file = shift(@_); # Not used
1728 my @source_file_lines = @{shift(@_)};
1729 my $source_file_key_to_text_mapping = shift(@_);
1730 my $target_file = shift(@_);
1731 my @target_file_lines = @{shift(@_)}; # Not used
1732 my $target_file_key_to_text_mapping = shift(@_);
1733 my $target_file_key_to_gti_comment_mapping = shift(@_);
1734 my $target_language_code = shift(@_); # Not used
1735
1736 # Build a mapping from chunk key to source file line, and from source file line to chunk key
1737 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_greenstone_xml(@source_file_lines);
1738 my %source_file_line_to_key_mapping = ();
1739 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1740 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1741 }
1742
1743 # Write the new target file
1744 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1745 if (!open(TARGET_FILE, ">$target_file_path")) {
1746 &throw_fatal_error("Could not write target file $target_file_path.");
1747 }
1748
1749 # Model the new target file on the source file, with the target file translations
1750 my $source_file_line_number = 0;
1751 foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
1752 # Fill in the gaps before this chunk starts
1753 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1754 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1755 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1756 print TARGET_FILE $source_file_lines[$source_file_line_number];
1757 $source_file_line_number++;
1758 }
1759 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
1760
1761 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
1762 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
1763 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
1764 $target_file_chunk_text =~ s/(\n)*$//g;
1765
1766 # If no translation exists for this chunk, show this, and move on
1767 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
1768 print TARGET_FILE "<!-- Missing translation: $chunk_key -->\n";
1769 next;
1770 }
1771
1772 print TARGET_FILE "<Text id=\"$chunk_key\">$target_file_chunk_text</Text>";
1773 if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) {
1774 my $chunk_gti_comment = $target_file_key_to_gti_comment_mapping->{$chunk_key};
1775 $chunk_gti_comment =~ s/^Updated //;
1776 print TARGET_FILE "<Updated date=\"" . $chunk_gti_comment . "\"\/>";
1777 }
1778 print TARGET_FILE "\n";
1779 }
1780
1781 # Fill in the end of the file
1782 while ($source_file_line_number < scalar(@source_file_lines)) {
1783 print TARGET_FILE $source_file_lines[$source_file_line_number];
1784 $source_file_line_number++;
1785 }
1786
1787 close(TARGET_FILE);
1788}
1789
1790
1791# ==========================================================================================
1792# GREENSTONE3 FUNCTIONS
1793
1794sub get_all_chunks_for_gs3
1795{
1796 # The code of the target language (ensure it is lowercase)
1797 my $target_language_code = lc(shift(@_));
1798 my $translation_file_key = lc(shift(@_));
1799
1800 # Check that the necessary arguments were supplied
1801 if (!$target_language_code) {
1802 &throw_fatal_error("Missing command argument.");
1803 }
1804
1805 # Get (and check) the translation configuration
1806 # my ($source_file_dir, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file_key);
1807
1808 my %source_files_key_to_text_mapping = ();
1809 my %target_files_key_to_text_mapping = ();
1810 my %source_files_key_to_last_update_date_mapping = ();
1811 my %target_files_key_to_last_update_date_mapping = ();
1812
1813 &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);
1814
1815 &log_message("Total number of source chunks: " . scalar(keys(%source_files_key_to_text_mapping)));
1816 &log_message("Total number of target chunks: " . scalar(keys(%target_files_key_to_text_mapping)));
1817
1818 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);
1819 return $xml_response;
1820}
1821
1822
1823sub get_first_n_chunks_requiring_work_for_gs3
1824{
1825 # The code of the target language (ensure it is lowercase)
1826 my $target_language_code = lc(shift(@_));
1827 # The key of the file to translate (ensure it is lowercase)
1828 my $translation_file_key = lc(shift(@_));
1829 # The number of chunks to return (defaults to one if not specified)
1830 my $num_chunks_to_return = shift(@_) || "1";
1831
1832 # Check that the necessary arguments were supplied
1833 if (!$target_language_code || !$translation_file_key) {
1834 &throw_fatal_error("Missing command argument.");
1835 }
1836
1837 my %source_files_key_to_text_mapping = ();
1838 my %target_files_key_to_text_mapping = ();
1839 my %source_files_key_to_last_update_date_mapping = ();
1840 my %target_files_key_to_last_update_date_mapping = ();
1841
1842 &build_gs3_configuration($target_language_code, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,
1843 \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1844
1845 # Determine the target file chunks requiring translation
1846 my @target_files_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping);
1847 # Determine the target file chunks requiring updating
1848 my @target_files_keys_requiring_updating = &determine_chunks_requiring_updating(\%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1849 &log_message("Total number of target chunks requiring translation: " . scalar(@target_files_keys_requiring_translation));
1850 &log_message("Total number of target chunks requiring updating: " . scalar(@target_files_keys_requiring_updating));
1851
1852 my $xml_response = &create_xml_response_for_chunks_requiring_work($translation_file_key, "", scalar(keys(%source_files_key_to_text_mapping)),
1853 \@target_files_keys_requiring_translation, \@target_files_keys_requiring_updating,
1854 $num_chunks_to_return, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,
1855 \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1856
1857 return $xml_response;
1858}
1859
1860sub get_uptodate_chunks_for_gs3
1861{
1862 # The code of the target language (ensure it is lowercase)
1863 my $target_language_code = lc(shift(@_));
1864 # The key of the file to translate (ensure it is lowercase)
1865 my $translation_file_key = lc(shift(@_));
1866 # The number of chunks to return (defaults to one if not specified)
1867 my $num_chunks_to_return = shift(@_) || "1";
1868
1869 # Check that the necessary arguments were supplied
1870 if (!$target_language_code || !$translation_file_key) {
1871 &throw_fatal_error("Missing command argument.");
1872 }
1873
1874 my %source_files_key_to_text_mapping = ();
1875 my %target_files_key_to_text_mapping = ();
1876 my %source_files_key_to_last_update_date_mapping = ();
1877 my %target_files_key_to_last_update_date_mapping = ();
1878
1879 &build_gs3_configuration($target_language_code, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,
1880 \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1881
1882
1883 # Chunks needing updating are those in the target file that have been more recently edited in the source file
1884 # All others are uptodate (which implies that they have certainly been translated at some point and would not be empty)
1885 my @uptodate_target_file_keys = ();
1886 foreach my $chunk_key (keys(%source_files_key_to_last_update_date_mapping)) {
1887 my $source_chunk_last_update_date = $source_files_key_to_last_update_date_mapping{$chunk_key};
1888 my $target_chunk_last_update_date = $target_files_key_to_last_update_date_mapping{$chunk_key};
1889
1890 # 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";
1891
1892 if (defined($target_chunk_last_update_date) && !&is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) {
1893 # &log_message("Chunk with key $chunk_key needs updating.");
1894 push(@uptodate_target_file_keys, $chunk_key);
1895 }
1896 }
1897
1898 my $xml_response = &create_xml_response_for_uptodate_chunks($translation_file_key, "", \@uptodate_target_file_keys, \%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);
1899
1900 return $xml_response;
1901}
1902
1903
1904sub build_gs3_configuration
1905{
1906 my ($target_language_code, $source_files_key_to_text_mapping, $target_files_key_to_text_mapping,
1907 $source_files_key_to_gti_comment_mapping, $target_files_key_to_gti_comment_mapping) = @_;
1908
1909 my $source_file_directory = "greenstone3"; # my $source_file_directory = &util::filename_cat("WEB-INF","classes");
1910 my $translation_file_type = "resource_bundle";
1911
1912 foreach my $interface_file_key (@gs3_interface_files) {
1913
1914 &log_message("Greenstone 3 interface file: " . $interface_file_key);
1915
1916 # Parse the source language and target language files
1917 my $source_file = &util::filename_cat($source_file_directory, $interface_file_key.".properties");
1918 my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file));
1919 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
1920 my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
1921 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);
1922
1923 my $target_file = &util::filename_cat($source_file_directory, $interface_file_key."_".$target_language_code.".properties");
1924 my @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file));
1925 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
1926 my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
1927 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);
1928
1929
1930 # Filter out any automatically translated chunks
1931 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1932 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
1933 delete $source_file_key_to_line_mapping{$chunk_key};
1934 delete $target_file_key_to_line_mapping{$chunk_key};
1935 }
1936 }
1937
1938 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
1939 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
1940
1941 foreach my $chunk_key (keys(%source_file_key_to_text_mapping)) {
1942 my $global_chunk_key = "$interface_file_key.$chunk_key";
1943 $source_files_key_to_text_mapping->{$global_chunk_key} = $source_file_key_to_text_mapping{$chunk_key};
1944 $source_files_key_to_gti_comment_mapping->{$global_chunk_key} = $source_file_key_to_gti_comment_mapping{$chunk_key};
1945
1946 if (defined $target_file_key_to_text_mapping{$chunk_key}) {
1947 $target_files_key_to_text_mapping->{$global_chunk_key} = $target_file_key_to_text_mapping{$chunk_key};
1948 $target_files_key_to_gti_comment_mapping->{$global_chunk_key} = $target_file_key_to_gti_comment_mapping{$chunk_key};
1949 }
1950 }
1951 }
1952}
1953
1954
1955sub write_translated_gs3interface
1956{
1957 my $source_file_key_to_text_mapping = shift(@_);
1958 my $target_file_key_to_text_mapping = shift(@_);
1959 my $target_file_key_to_gti_comment_mapping = shift(@_);
1960 my $target_language_code = shift(@_);
1961
1962 my @sorted_chunk_keys = sort (keys(%$source_file_key_to_text_mapping));
1963
1964 my %translated_interface_file_keys = ();
1965 foreach my $chunk_key (keys(%$target_file_key_to_text_mapping)) {
1966 $chunk_key =~ /^([^\.]+)?\.(.*)$/;
1967 if (!defined $translated_interface_file_keys{$1}) {
1968 &log_message("Updated interface file: " . $1);
1969 $translated_interface_file_keys{$1}="";
1970 }
1971 }
1972 &log_message("Updated interface files: " . scalar(keys(%translated_interface_file_keys)));
1973
1974 my $source_file_directory = "greenstone3";
1975
1976 foreach my $interface_file_key (keys(%translated_interface_file_keys)) {
1977
1978 # Build a mapping from chunk key to source file line, and from source file line to chunk key
1979 my $source_file = &util::filename_cat($source_file_directory, "$interface_file_key.properties");
1980 my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file));
1981 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines);
1982 my %source_file_line_to_key_mapping = ();
1983 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1984 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1985 }
1986
1987 # Write the new target file
1988 my $target_file = &util::filename_cat($source_file_directory, $interface_file_key . "_" . $target_language_code . ".properties");
1989 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1990 if (!open(TARGET_FILE, ">$target_file_path")) {
1991 &throw_fatal_error("Could not write target file $target_file_path.");
1992 }
1993
1994 # Model the new target file on the source file, with the target file translations
1995 my $source_file_line_number = 0;
1996 foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
1997 # Fill in the gaps before this chunk starts
1998 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1999 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
2000 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
2001 print TARGET_FILE $source_file_lines[$source_file_line_number];
2002 $source_file_line_number++;
2003 }
2004 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
2005
2006 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
2007 my $global_chunk_key = "$interface_file_key.$chunk_key";
2008 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$global_chunk_key};
2009 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$global_chunk_key} || "";
2010
2011 # If no translation exists for this chunk, show this, and move on
2012 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
2013 print TARGET_FILE "# -- Missing translation: $chunk_key\n";
2014 next;
2015 }
2016
2017 print TARGET_FILE "$chunk_key:$target_file_chunk_text";
2018 if ($target_file_key_to_gti_comment_mapping->{$global_chunk_key}) {
2019 print TARGET_FILE " # " . $target_file_key_to_gti_comment_mapping->{$global_chunk_key};
2020 }
2021 print TARGET_FILE "\n";
2022 }
2023
2024 close(TARGET_FILE);
2025 }
2026}
2027
2028&main(@ARGV);
Note: See TracBrowser for help on using the repository browser.