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

Last change on this file since 28976 was 28976, checked in by ak19, 10 years ago

module variable is empty when the gti command is create-glihelp-zip-file

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 85.1 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 if ( ! -e $classpath) {
715 &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");
716 }
717
718 my $gli_help_directory = &util::filename_cat($gsdl_root_directory, "gli");
719 $gli_help_directory = &util::filename_cat($gli_help_directory, "help");
720
721 my $gen_many_html_xsl_filepath = &util::filename_cat($gli_help_directory, "gen-many-html.xsl");
722 if ( ! -e $gen_many_html_xsl_filepath) {
723 &throw_fatal_error("$gen_many_html_xsl_filepath doesn't exist! Need this file to create the zip file for GLI Help");
724 }
725
726 my $gen_index_xml_xsl_filepath = &util::filename_cat($gli_help_directory, "gen-index-xml.xsl");
727 my $split_script_filepath = &util::filename_cat($gli_help_directory, "splithelpdocument.pl");
728
729 my $target_file_directory = &util::filename_cat($gli_help_directory, $target_language_code);
730 $target_file_directory = $target_file_directory."/";
731
732 my $target_filepath = &util::filename_cat($gsdl_root_directory, $target_file);
733
734 my $perl_exec = &util::get_perl_exec();
735 my $java_exec = "java";
736 if(defined($ENV{'JAVA_HOME'}) && $ENV{'JAVA_HOME'} ne ""){
737 $java_exec = &util::filename_cat($ENV{'JAVA_HOME'}, "bin", "java");
738 }
739
740 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";
741 my $response = `$cmd`;
742
743 $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";
744 $response = `$cmd`;
745
746 my $zip_file_path = "/greenstone/custom/gti/" . $target_language_code . "_GLIHelp.zip";
747 $cmd = "zip -rj $zip_file_path $target_file_directory -i \*.htm \*.xml";
748 $response = `$cmd`;
749}
750
751
752sub get_translation_configuration
753{
754 # Get the code of the target language
755 my $target_language_code = shift(@_);
756 # Get the key of the file to translate
757 my $translation_file_key = shift(@_);
758
759 # Read the translation data from the gti.cfg file
760 my ($source_file, $target_file, $translation_file_type) =
761 &get_translation_data_for($target_language_code, $translation_file_key);
762
763 # Check that the file to translate is defined in the gti.cfg file
764 if (!$source_file || !$target_file || !$translation_file_type) {
765 &throw_fatal_error("Missing or incomplete specification for translation file \"$translation_file_key\" in gti.pl.");
766 }
767
768 # Check that the source file exists
769 my $source_file_path = &util::filename_cat($gsdl_root_directory, $source_file);
770 if (!-e $source_file_path) {
771 &throw_fatal_error("Source file $source_file_path does not exist.");
772 }
773
774 # Check that the source file is up to date
775 # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist
776 # unless ($translation_file_is_not_in_cvs) {
777 #my $source_file_cvs_status = `cd $gsdl_root_directory; cvs -d $anonymous_cvs_root update $source_file 2>/dev/null`;
778 my $source_file_cvs_status = `cd $gsdl_root_directory; svn status $source_file 2>/dev/null`;
779 if ($source_file_cvs_status =~ /^C /) {
780 &throw_fatal_error("Source file $source_file_path conflicts with the repository.");
781 }
782 if ($source_file_cvs_status =~ /^M /) {
783 &throw_fatal_error("Source file $source_file_path contains uncommitted changes.");
784 }
785 # }
786
787 return ($source_file, $target_file, $translation_file_type);
788}
789
790
791sub get_translation_data_for
792{
793 my ($target_language_code, $translation_file_key) = @_;
794
795 foreach my $translation_file (@$gti_translation_files) {
796 # If this isn't the correct translation file, move onto the next one
797 next if ($translation_file_key ne $translation_file->{'key'});
798
799 # Resolve the target language file
800 my $target_language_file = $translation_file->{'target_file'};
801 if ($target_language_file =~ /(\{.+\;.+\})/) {
802 my $unresolved_target_language_file_part = $1;
803
804 # Check for a special case for the target language code
805 if ($unresolved_target_language_file_part =~ /(\{|\;)$target_language_code:([^\;]+)(\;|\})/) {
806 my $resolved_target_language_file_part = $2;
807 $target_language_file =~ s/$unresolved_target_language_file_part/$resolved_target_language_file_part/;
808 }
809 # Otherwise use the last part as the default value
810 else {
811 my ($default_target_language_file_part) = $unresolved_target_language_file_part =~ /([^\;]+)\}/;
812 $target_language_file =~ s/$unresolved_target_language_file_part/\{$default_target_language_file_part\}/;
813 }
814 }
815
816 # Resolve instances of {iso_639_1_target_language_name}
817 my $iso_639_1_target_language_name = $iso639::fromiso639{$target_language_code};
818 $iso_639_1_target_language_name =~ tr/A-Z/a-z/ if $iso_639_1_target_language_name;
819 $target_language_file =~ s/\{iso_639_1_target_language_name\}/$iso_639_1_target_language_name/g;
820
821 # Resolve instances of {target_language_code}
822 $target_language_file =~ s/\{target_language_code\}/$target_language_code/g;
823
824 return ($translation_file->{'source_file'}, $target_language_file, $translation_file->{'file_type'});
825}
826
827return ();
828}
829
830
831sub read_file_lines
832{
833 my ($file_path) = @_;
834
835 if (!open(FILE_IN, "<$file_path")) {
836 &log_message("Note: Could not open file $file_path.");
837 return ();
838 }
839 my @file_lines = <FILE_IN>;
840 close(FILE_IN);
841
842 return @file_lines;
843}
844
845
846sub build_key_to_line_mapping
847{
848 my ($file_lines, $translation_file_type) = @_;
849 eval "return &build_key_to_line_mapping_for_${translation_file_type}(\@\$file_lines)";
850}
851
852
853sub build_key_to_text_mapping
854{
855 my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_;
856
857 my %key_to_text_mapping = ();
858 foreach my $chunk_key (keys(%$key_to_line_mapping)) {
859 my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0];
860 my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1];
861
862 my $chunk_text = @$file_lines[$chunk_starting_line];
863 for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
864 $chunk_text .= @$file_lines[$l];
865 }
866
867 # Map from chunk key to text
868 eval "\$key_to_text_mapping{\${chunk_key}} = &import_chunk_from_${translation_file_type}(\$chunk_text)";
869 }
870
871 return %key_to_text_mapping;
872}
873
874
875sub build_key_to_last_update_date_mapping
876{
877 my ($file, $file_lines, $key_to_line_mapping, $translation_file_type) = @_;
878
879 # If the files aren't in CVS then we can't tell anything about what needs updating
880 # return () if ($translation_file_is_not_in_cvs);
881
882 # Build a mapping from key to CVS date
883 # Need to be careful with this mapping because the chunk keys won't necessarily all be valid
884 my %key_to_cvs_date_mapping = &build_key_to_cvs_date_mapping($file, $translation_file_type);
885
886 # Build a mapping from key to comment date
887 my %key_to_gti_comment_mapping = &build_key_to_gti_comment_mapping($file_lines, $key_to_line_mapping, $translation_file_type);
888
889 # Build a mapping from key to last update date (the latter of the CVS date and comment date)
890 my %key_to_last_update_date_mapping = ();
891 foreach my $chunk_key (keys(%$key_to_line_mapping)) {
892 # Use the CVS date as a starting point
893 my $chunk_cvs_date = $key_to_cvs_date_mapping{$chunk_key};
894 $key_to_last_update_date_mapping{$chunk_key} = $chunk_cvs_date;
895
896 # If a comment date exists and it is after the CVS date, use that instead
897 # need to convert the comment date format to SVN format
898 my $chunk_gti_comment = $key_to_gti_comment_mapping{$chunk_key};
899 if (defined($chunk_gti_comment) && $chunk_gti_comment =~ /(\d?\d-\D\D\D-\d\d\d\d)/) {
900 my $chunk_comment_date = $1;
901 if ((!defined($chunk_cvs_date) || &is_date_after($chunk_comment_date, $chunk_cvs_date))) {
902 $key_to_last_update_date_mapping{$chunk_key} = $chunk_comment_date;
903 }
904 }
905 }
906
907 return %key_to_last_update_date_mapping;
908}
909
910
911sub build_key_to_cvs_date_mapping
912{
913 my ($filename, $translation_file_type) = @_;
914
915 # Use SVN to annotate each line of the file with the date it was last edited
916 # The "2>/dev/null" is very important! If it is missing this will never return when run from the receptionist
917 my $cvs_annotated_file = `cd $gsdl_root_directory; svn annotate -v --force $filename 2>/dev/null`;
918
919 my @cvs_annotated_file_lines = split(/\n/, $cvs_annotated_file);
920
921 my @cvs_annotated_file_lines_date = ();
922 foreach my $cvs_annotated_file_line (@cvs_annotated_file_lines) {
923 # Extract the date from the SVN annotation at the front
924 # svn format : 2007-07-16
925 $cvs_annotated_file_line =~ s/^\s+\S+\s+\S+\s(\S+)//;
926
927 push(@cvs_annotated_file_lines_date, $1);
928
929 # trim extra date information in svn annotation format
930 # 15:42:49 +1200 (Wed, 21 Jun 2006)
931 $cvs_annotated_file_line =~ s/^\s+\S+\s\S+\s\((.+?)\)\s//;
932 }
933
934 # Build a key to line mapping for the CVS annotated file, for matching the chunk key to the CVS date
935 my %key_to_line_mapping = &build_key_to_line_mapping(\@cvs_annotated_file_lines, $translation_file_type);
936
937 my %key_to_cvs_date_mapping = ();
938 foreach my $chunk_key (keys(%key_to_line_mapping)) {
939 my $chunk_starting_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[0];
940 my $chunk_finishing_line = (split(/-/, $key_to_line_mapping{$chunk_key}))[1];
941
942 # Find the date this chunk was last edited, from the CVS annotation
943 my $chunk_date = $cvs_annotated_file_lines_date[$chunk_starting_line];
944 for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
945 if (&is_date_after($cvs_annotated_file_lines_date[$l], $chunk_date)) {
946 # This part of the chunk has been updated more recently
947 $chunk_date = $cvs_annotated_file_lines_date[$l];
948
949 }
950 }
951
952 # Map from chunk key to CVS date
953 $key_to_cvs_date_mapping{$chunk_key} = $chunk_date;
954 }
955
956 return %key_to_cvs_date_mapping;
957}
958
959
960sub build_key_to_gti_comment_mapping
961{
962 my ($file_lines, $key_to_line_mapping, $translation_file_type) = @_;
963
964 my %key_to_gti_comment_mapping = ();
965 foreach my $chunk_key (keys(%$key_to_line_mapping)) {
966 my $chunk_starting_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[0];
967 my $chunk_finishing_line = (split(/-/, $key_to_line_mapping->{$chunk_key}))[1];
968
969 my $chunk_text = @$file_lines[$chunk_starting_line];
970 for (my $l = ($chunk_starting_line + 1); $l <= $chunk_finishing_line; $l++) {
971 $chunk_text .= @$file_lines[$l];
972 }
973
974 # Map from chunk key to GTI comment
975 my $chunk_gti_comment;
976 eval "\$chunk_gti_comment = &get_${translation_file_type}_chunk_gti_comment(\$chunk_text)";
977 $key_to_gti_comment_mapping{$chunk_key} = $chunk_gti_comment if (defined($chunk_gti_comment));
978 }
979
980 return %key_to_gti_comment_mapping;
981}
982
983
984sub determine_chunks_requiring_translation
985{
986 my $source_file_key_to_text_mapping = shift(@_);
987 my $target_file_key_to_text_mapping = shift(@_);
988
989 # Chunks needing translation are those in the source file with no translation in the target file
990 my @target_file_keys_requiring_translation = ();
991 foreach my $chunk_key (keys(%$source_file_key_to_text_mapping)) {
992 if ($source_file_key_to_text_mapping->{$chunk_key} && !$target_file_key_to_text_mapping->{$chunk_key}) {
993 # &log_message("Chunk with key $chunk_key needs translating.");
994 push(@target_file_keys_requiring_translation, $chunk_key);
995 }
996 }
997
998 return @target_file_keys_requiring_translation;
999}
1000
1001
1002sub determine_chunks_requiring_updating
1003{
1004 my $source_file_key_to_last_update_date_mapping = shift(@_);
1005 my $target_file_key_to_last_update_date_mapping = shift(@_);
1006
1007 # Chunks needing updating are those in the target file that have been more recently edited in the source file
1008 my @target_file_keys_requiring_updating = ();
1009 foreach my $chunk_key (keys(%$source_file_key_to_last_update_date_mapping)) {
1010 my $source_chunk_last_update_date = $source_file_key_to_last_update_date_mapping->{$chunk_key};
1011 my $target_chunk_last_update_date = $target_file_key_to_last_update_date_mapping->{$chunk_key};
1012
1013 # 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";
1014
1015 if (defined($target_chunk_last_update_date) && &is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) {
1016 # &log_message("Chunk with key $chunk_key needs updating.");
1017 push(@target_file_keys_requiring_updating, $chunk_key);
1018 }
1019 }
1020
1021 return @target_file_keys_requiring_updating;
1022}
1023
1024
1025sub is_chunk_automatically_translated
1026{
1027 my ($chunk_key, $translation_file_type) = @_;
1028 eval "return &is_${translation_file_type}_chunk_automatically_translated(\$chunk_key)";
1029}
1030
1031
1032sub make_text_xml_safe
1033{
1034 my $text = shift(@_);
1035 $text =~ s/\&/\&amp\;/g;
1036 $text =~ s/\&amp\;lt\;/\&amp\;amp\;lt\;/g;
1037 $text =~ s/\&amp\;gt\;/\&amp\;amp\;gt\;/g;
1038 $text =~ s/\&amp\;rarr\;/\&amp\;amp\;rarr\;/g;
1039 $text =~ s/\&amp\;mdash\;/\&amp\;amp\;mdash\;/g;
1040 $text =~ s/</\&lt\;/g;
1041 $text =~ s/>/\&gt\;/g;
1042 return $text;
1043}
1044
1045
1046sub unmake_text_xml_safe
1047{
1048 my $text = shift(@_);
1049 $text =~ s/\&lt\;/</g;
1050 $text =~ s/\&gt\;/>/g;
1051 $text =~ s/\&amp\;/\&/g;
1052 return $text;
1053}
1054
1055
1056# Returns 1 if $date1 is after $date2, 0 otherwise
1057sub is_date_after_cvs
1058{
1059 my ($date1, $date2) = @_;
1060 my %months = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr", 4, "May", 5, "Jun", 6,
1061 "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12);
1062
1063 if(!defined $date1) {
1064 return 1;
1065 }
1066
1067 my @date1parts = split(/-/, $date1);
1068 my @date2parts = split(/-/, $date2);
1069
1070 # Compare year - nasty because we have rolled over into a new century
1071 my $year1 = $date1parts[2];
1072 if ($year1 < 80) {
1073 $year1 += 2000;
1074 }
1075 my $year2 = $date2parts[2];
1076 if ($year2 < 80) {
1077 $year2 += 2000;
1078 }
1079
1080 # Compare year
1081 if ($year1 > $year2) {
1082 return 1;
1083 }
1084 elsif ($year1 == $year2) {
1085 # Year is the same, so compare month
1086 if ($months{$date1parts[1]} > $months{$date2parts[1]}) {
1087 return 1;
1088 }
1089 elsif ($months{$date1parts[1]} == $months{$date2parts[1]}) {
1090 # Month is the same, so compare day
1091 if ($date1parts[0] > $date2parts[0]) {
1092 return 1;
1093 }
1094 }
1095 }
1096
1097 return 0;
1098}
1099
1100sub is_date_after
1101{
1102 my ($date1, $date2) = @_;
1103
1104 if(!defined $date1) {
1105 return 1;
1106 }
1107 if(!defined $date2) {
1108 return 0;
1109 }
1110
1111 # 16-Aug-2006
1112 if($date1=~ /(\d+?)-(\S\S\S)-(\d\d\d\d)/){
1113 my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr", "04", "May", "05", "Jun", "06",
1114 "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12");
1115 $date1=$3 . "-" . $months{$2} . "-" . $1;
1116 # print "** converted date1: $date1\n";
1117 }
1118 if($date2=~ /(\d+?)-(\S\S\S)-(\d\d\d\d)/){
1119 my %months = ("Jan", "01", "Feb", "02", "Mar", "03", "Apr", "04", "May", "05", "Jun", "06",
1120 "Jul", "07", "Aug", "08", "Sep", "09", "Oct", "10", "Nov", "11", "Dec", "12");
1121 $date2=$3 . "-" . $months{$2} . "-" . $1;
1122 # print "** converted date2: $date2\n";
1123 }
1124
1125
1126 # 2006-08-16
1127 my @date1parts = split(/-/, $date1);
1128 my @date2parts = split(/-/, $date2);
1129
1130 # Compare year
1131 if ($date1parts[0] > $date2parts[0]) {
1132 return 1;
1133 }
1134 elsif ($date1parts[0] == $date2parts[0]) {
1135 # Year is the same, so compare month
1136 if ($date1parts[1] > $date2parts[1]) {
1137 return 1;
1138 }
1139 elsif ($date1parts[1] == $date2parts[1]) {
1140 # Month is the same, so compare day
1141 if ($date1parts[2] > $date2parts[2]) {
1142 return 1;
1143 }
1144 }
1145 }
1146
1147 return 0;
1148}
1149
1150
1151sub create_xml_response_for_chunks_requiring_work
1152{
1153 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) = @_;
1154
1155 # Form an XML response to the command
1156 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
1157 $xml_response .= "<GTIResponse>\n";
1158 $xml_response .= " <TranslationFile"
1159 . " key=\"" . $translation_file_key . "\""
1160 . " target_file_path=\"" . $target_file . "\""
1161 . " num_chunks_translated=\"" . ($total_num_chunks - scalar(@$target_files_keys_requiring_translation)) . "\""
1162 . " num_chunks_requiring_translation=\"" . scalar(@$target_files_keys_requiring_translation) . "\""
1163 . " num_chunks_requiring_updating=\"" . scalar(@$target_files_keys_requiring_updating) . "\"\/>\n";
1164
1165 # Do chunks requiring translation first
1166 if ($num_chunks_to_return > scalar(@$target_files_keys_requiring_translation)) {
1167 $xml_response .= " <ChunksRequiringTranslation size=\"" . scalar(@$target_files_keys_requiring_translation) . "\">\n";
1168 }
1169 else {
1170 $xml_response .= " <ChunksRequiringTranslation size=\"" . $num_chunks_to_return . "\">\n";
1171 }
1172
1173 my @sorted_chunk_keys = sort (@$target_files_keys_requiring_translation);
1174 foreach my $chunk_key (@sorted_chunk_keys) {
1175 last if ($num_chunks_to_return == 0);
1176
1177 my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1178 my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});
1179
1180 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1181 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1182 $xml_response .= " <TargetFileText></TargetFileText>\n";
1183 $xml_response .= " </Chunk>\n";
1184
1185 $num_chunks_to_return--;
1186 }
1187
1188 $xml_response .= " </ChunksRequiringTranslation>\n";
1189
1190 # Then do chunks requiring updating
1191 if ($num_chunks_to_return > scalar(@$target_files_keys_requiring_updating)) {
1192 $xml_response .= " <ChunksRequiringUpdating size=\"" . scalar(@$target_files_keys_requiring_updating) . "\">\n";
1193 }
1194 else {
1195 $xml_response .= " <ChunksRequiringUpdating size=\"" . $num_chunks_to_return . "\">\n";
1196 }
1197
1198 # foreach my $chunk_key (@target_file_keys_requiring_updating) {
1199 @sorted_chunk_keys = sort (@$target_files_keys_requiring_updating);
1200 foreach my $chunk_key (@sorted_chunk_keys) {
1201 last if ($num_chunks_to_return == 0);
1202
1203 my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1204 my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});
1205 my $target_file_chunk_date = $target_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1206 my $target_file_chunk_text = &make_text_xml_safe($target_files_key_to_text_mapping->{$chunk_key});
1207
1208 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1209 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1210 $xml_response .= " <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
1211 $xml_response .= " </Chunk>\n";
1212
1213 $num_chunks_to_return--;
1214 }
1215
1216 $xml_response .= " </ChunksRequiringUpdating>\n";
1217
1218 $xml_response .= "</GTIResponse>\n";
1219
1220 return $xml_response;
1221}
1222
1223sub create_xml_response_for_uptodate_chunks
1224{
1225 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) = @_;
1226
1227 # Form an XML response to the command
1228 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
1229 $xml_response .= "<GTIResponse>\n";
1230 $xml_response .= " <TranslationFile"
1231 . " key=\"" . $translation_file_key . "\""
1232 . " target_file_path=\"" . $target_file . "\""
1233 . " num_chunks_uptodate=\"" . scalar(@$uptodate_target_files_keys) . "\"\/>\n";
1234
1235
1236 # Then do chunks requiring updating
1237 $xml_response .= " <UptodateChunks size=\"" . scalar(@$uptodate_target_files_keys) . "\">\n";
1238
1239
1240 # foreach my $chunk_key (@uptodate_target_file_keys) {
1241 my @sorted_chunk_keys = sort (@$uptodate_target_files_keys);
1242 foreach my $chunk_key (@sorted_chunk_keys) {
1243
1244 my $source_file_chunk_date = $source_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1245 my $source_file_chunk_text = &make_text_xml_safe($source_files_key_to_text_mapping->{$chunk_key});
1246 my $target_file_chunk_date = $target_files_key_to_last_update_date_mapping->{$chunk_key} || "";
1247 my $target_file_chunk_text = &make_text_xml_safe($target_files_key_to_text_mapping->{$chunk_key});
1248
1249 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1250 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1251 $xml_response .= " <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
1252 $xml_response .= " </Chunk>\n";
1253
1254 }
1255
1256 $xml_response .= " </UptodateChunks>\n";
1257
1258 $xml_response .= "</GTIResponse>\n";
1259
1260 return $xml_response;
1261}
1262
1263sub create_xml_response_for_all_chunks
1264{
1265 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) = @_;
1266
1267 # Form an XML response to the command
1268 my $xml_response = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
1269 $xml_response .= "<GTIResponse>\n";
1270 $xml_response .= " <TranslationFile"
1271 . " key=\"" . $translation_file_key . "\""
1272 . " target_file_path=\"" . $target_file . "\"\/>\n";
1273
1274 # Do all the chunks
1275 $xml_response .= " <Chunks size=\"" . scalar(keys(%$source_file_key_to_text_mapping)) . "\">\n";
1276
1277 my @sorted_chunk_keys = sort (keys(%$source_file_key_to_text_mapping));
1278 foreach my $chunk_key (@sorted_chunk_keys) {
1279 my $source_file_chunk_date = $source_file_key_to_last_update_date_mapping->{$chunk_key} || "";
1280 my $source_file_chunk_text = &make_text_xml_safe($source_file_key_to_text_mapping->{$chunk_key});
1281
1282 $xml_response .= " <Chunk key=\"" . &make_text_xml_safe($chunk_key) . "\">\n";
1283 $xml_response .= " <SourceFileText date=\"$source_file_chunk_date\">$source_file_chunk_text</SourceFileText>\n";
1284 if (defined($target_file_key_to_text_mapping->{$chunk_key})) {
1285 my $target_file_chunk_date = $target_file_key_to_last_update_date_mapping->{$chunk_key} || "";
1286 my $target_file_chunk_text = &make_text_xml_safe($target_file_key_to_text_mapping->{$chunk_key});
1287 $xml_response .= " <TargetFileText date=\"$target_file_chunk_date\">$target_file_chunk_text</TargetFileText>\n";
1288 }
1289 else {
1290 $xml_response .= " <TargetFileText></TargetFileText>\n";
1291 }
1292
1293 $xml_response .= " </Chunk>\n";
1294 }
1295 $xml_response .= " </Chunks>\n";
1296
1297 $xml_response .= "</GTIResponse>\n";
1298 return $xml_response;
1299}
1300
1301
1302
1303# ==========================================================================================
1304# MACROFILE FUNCTIONS
1305
1306sub build_key_to_line_mapping_for_macrofile
1307{
1308 my (@file_lines) = @_;
1309
1310 my $macro_package;
1311 my %chunk_key_to_line_mapping = ();
1312 # Process the contents of the file, line by line
1313 for (my $i = 0; $i < scalar(@file_lines); $i++) {
1314 my $line = $file_lines[$i];
1315 $line =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1316
1317 # Check if a new package is being defined
1318 if ($line =~ m/^package\s+(.+)/) {
1319 $macro_package = $1;
1320 }
1321
1322 # Line contains a macro name
1323 elsif ($line =~ m/^(_\w+_)/) {
1324 my $macro_key = $1;
1325 $line =~ s/\s*([^\\]\#[^\}]+)?$//; # Remove any comments and nasty whitespace
1326
1327 # While there is still text of the macro to go...
1328 my $startline = $i;
1329 while ($line !~ /\}$/) {
1330 $i++;
1331 if ($i == scalar(@file_lines)) {
1332 &throw_fatal_error("Could not find end of macro $macro_key.");
1333 }
1334 $line = $file_lines[$i];
1335 $line =~ s/\s*([^\\]\#[^\}]+)?$//; # Remove any comments and nasty whitespace
1336 }
1337
1338 # The chunk key consists of the package name and the macro key
1339 my $chunk_key = $macro_package . "." . $macro_key;
1340 # Map from chunk key to line
1341 $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i;
1342 }
1343
1344 # Icon: line in format ## "image text" ## image_type ## macro_name ##
1345 elsif ($line =~ m/^\#\# .* \#\# .* \#\# (.*) \#\#/) {
1346 # The chunk key consists of package name and macro key
1347 my $chunk_key = $macro_package . "." . $1;
1348 # Map from chunk key to line
1349 $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i;
1350}
1351}
1352
1353return %chunk_key_to_line_mapping;
1354}
1355
1356
1357sub import_chunk_from_macrofile
1358{
1359 my ($chunk_text) = @_;
1360
1361 # Is this an icon macro??
1362 if ($chunk_text =~ /^\#\# (.*)/) {
1363 # Extract image macro text
1364 $chunk_text =~ /^\#\#\s+([^\#]+)\s+\#\#/;
1365 $chunk_text = $1;
1366
1367 # Remove enclosing quotes
1368 $chunk_text =~ s/^\"//;
1369 $chunk_text =~ s/\"$//;
1370}
1371
1372# No, so it must be a text macro
1373else {
1374 # Remove macro key
1375 $chunk_text =~ s/^_([^_]+)_(\s*)//;
1376
1377 # Remove language specifier
1378 $chunk_text =~ s/^\[l=.*\](\s*)//;
1379
1380 # Remove braces enclosing text
1381 $chunk_text =~ s/^{(\s*)((.|\n)*)}(\s*)(\#.+\s*)?/$2/;
1382}
1383
1384return $chunk_text;
1385}
1386
1387
1388sub get_macrofile_chunk_gti_comment
1389{
1390 my ($chunk_text) = @_;
1391
1392 # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
1393 if ($chunk_text =~ /\#\s+(Updated\s+\d?\d-\D\D\D-\d\d\d\d.*)\s*$/i) {
1394 return $1;
1395}
1396
1397return undef;
1398}
1399
1400
1401sub is_macrofile_chunk_automatically_translated
1402{
1403 my ($chunk_key) = @_;
1404
1405 # The _httpiconX_, _widthX_ and _heightX_ image macros are automatically translated
1406 if ($chunk_key =~ /\._(httpicon|width|height)/) {
1407 return 1;
1408 }
1409
1410 return 0;
1411}
1412
1413
1414# Use the source file to generate a target file that is formatted the same
1415sub write_translated_macrofile
1416{
1417 my $source_file = shift(@_); # Not used
1418 my @source_file_lines = @{shift(@_)};
1419 my $source_file_key_to_text_mapping = shift(@_);
1420 my $target_file = shift(@_);
1421 my @target_file_lines = @{shift(@_)};
1422 my $target_file_key_to_text_mapping = shift(@_);
1423 my $target_file_key_to_gti_comment_mapping = shift(@_);
1424 my $target_language_code = shift(@_);
1425
1426 # Build a mapping from source file line to chunk key
1427 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@source_file_lines);
1428 my %source_file_line_to_key_mapping = ();
1429 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1430 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1431 }
1432 my @source_file_line_keys = (sort sort_by_line (keys(%source_file_line_to_key_mapping)));
1433 my $source_file_line_number = 0;
1434
1435 # Build a mapping from target file line to chunk key
1436 my %target_file_key_to_line_mapping = &build_key_to_line_mapping_for_macrofile(@target_file_lines);
1437 my %target_file_line_to_key_mapping = ();
1438 foreach my $chunk_key (keys(%target_file_key_to_line_mapping)) {
1439 $target_file_line_to_key_mapping{$target_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1440 }
1441 my @target_file_line_keys = (sort sort_by_line (keys(%target_file_line_to_key_mapping)));
1442
1443 # Write the new target file
1444 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1445 if (!open(TARGET_FILE, ">$target_file_path")) {
1446 &throw_fatal_error("Could not write target file $target_file_path.");
1447 }
1448
1449 # Use the header from the target file, to keep language and author information
1450 if (scalar(@target_file_line_keys) > 0) {
1451 my $target_file_line_number = 0;
1452 my $target_file_chunk_starting_line_number = (split(/-/, $target_file_line_keys[0]))[0];
1453 while ($target_file_line_number < $target_file_chunk_starting_line_number) {
1454 my $target_file_line = $target_file_lines[$target_file_line_number];
1455 last if ($target_file_line =~ /^\# -- Missing translation: /); # We don't want to get into the macros
1456 print TARGET_FILE $target_file_line;
1457 $target_file_line_number++;
1458 }
1459
1460 $source_file_line_number = (split(/-/, $source_file_line_keys[0]))[0];
1461 }
1462
1463 # Model the new target file on the source file, with the target file translations
1464 foreach my $line_key (@source_file_line_keys) {
1465 # Fill in the gaps before this chunk starts
1466 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1467 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1468 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1469 print TARGET_FILE $source_file_lines[$source_file_line_number];
1470 $source_file_line_number++;
1471 }
1472 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
1473
1474 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
1475 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
1476 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
1477
1478 my $macrofile_key = $chunk_key;
1479 $macrofile_key =~ s/^(.+?)\.//;
1480
1481 # If no translation exists for this chunk, show this, and move on
1482 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
1483 print TARGET_FILE "# -- Missing translation: $macrofile_key\n";
1484 next;
1485 }
1486
1487 # Grab the source chunk text
1488 my $source_file_chunk = $source_file_lines[$source_file_chunk_starting_line_number];
1489 for (my $l = ($source_file_chunk_starting_line_number + 1); $l <= $source_file_chunk_finishing_line_number; $l++) {
1490 $source_file_chunk .= $source_file_lines[$l];
1491 }
1492
1493 # Is this an icon macro??
1494 if ($source_file_chunk =~ /^\#\# (.*)/) {
1495 # Escape any newline and question mark characters so the source text is replaced correctly
1496 $source_file_chunk_text =~ s/\\/\\\\/g;
1497 $source_file_chunk_text =~ s/\?/\\\?/g;
1498
1499 # Build the new target chunk from the source chunk
1500 my $target_file_chunk = $source_file_chunk;
1501 $target_file_chunk =~ s/$source_file_chunk_text/$target_file_chunk_text/;
1502 $target_file_chunk =~ s/(\s)*$//;
1503 print TARGET_FILE "$target_file_chunk";
1504 }
1505
1506 # No, it is just a normal text macro
1507 else {
1508 print TARGET_FILE "$macrofile_key [l=$target_language_code] {$target_file_chunk_text}";
1509 }
1510
1511 # Add the "updated" comment, if one exists
1512 if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) {
1513 print TARGET_FILE " # " . $target_file_key_to_gti_comment_mapping->{$chunk_key};
1514 }
1515 print TARGET_FILE "\n";
1516}
1517
1518close(TARGET_FILE);
1519}
1520
1521
1522sub sort_by_line
1523{
1524 return ((split(/-/, $a))[0] <=> (split(/-/, $b))[0]);
1525}
1526
1527
1528# ==========================================================================================
1529# RESOURCE BUNDLE FUNCTIONS
1530
1531sub build_key_to_line_mapping_for_resource_bundle
1532{
1533 my (@file_lines) = @_;
1534
1535 my %chunk_key_to_line_mapping = ();
1536 for (my $i = 0; $i < scalar(@file_lines); $i++) {
1537 my $line = $file_lines[$i];
1538 $line =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1539
1540 # Line contains a dictionary string
1541 if ($line =~ /^(\S+?)[:|=](.*)$/) {
1542 my $chunk_key = $1;
1543
1544 # Map from chunk key to line
1545 $chunk_key_to_line_mapping{$chunk_key} = $i . "-" . $i;
1546 }
1547 }
1548
1549 return %chunk_key_to_line_mapping;
1550}
1551
1552
1553sub import_chunk_from_resource_bundle
1554{
1555 my ($chunk_text) = @_;
1556
1557 # Simple: just remove string key
1558 $chunk_text =~ s/^(\S+?)[:|=](\s*)//;
1559 $chunk_text =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1560 $chunk_text =~ s/(\s*)\#\s+Updated\s+(\d?\d-\D\D\D-\d\d\d\d.*)\s*$//i;
1561
1562 return $chunk_text;
1563}
1564
1565
1566sub get_resource_bundle_chunk_gti_comment
1567{
1568 my ($chunk_text) = @_;
1569
1570 # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
1571 if ($chunk_text =~ /\#\s+(Updated\s+\d?\d-\D\D\D-\d\d\d\d.*)\s*$/i) {
1572 return $1;
1573}
1574
1575return undef;
1576}
1577
1578
1579sub is_resource_bundle_chunk_automatically_translated
1580{
1581 # No resource bundle chunks are automatically translated
1582 return 0;
1583}
1584
1585
1586sub write_translated_resource_bundle
1587{
1588 my $source_file = shift(@_); # Not used
1589 my @source_file_lines = @{shift(@_)};
1590 my $source_file_key_to_text_mapping = shift(@_);
1591 my $target_file = shift(@_);
1592 my @target_file_lines = @{shift(@_)}; # Not used
1593 my $target_file_key_to_text_mapping = shift(@_);
1594 my $target_file_key_to_gti_comment_mapping = shift(@_);
1595 my $target_language_code = shift(@_); # Not used
1596
1597 # Build a mapping from chunk key to source file line, and from source file line to chunk key
1598 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines);
1599 my %source_file_line_to_key_mapping = ();
1600 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1601 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1602 }
1603
1604 # Write the new target file
1605 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1606 if (!open(TARGET_FILE, ">$target_file_path")) {
1607 &throw_fatal_error("Could not write target file $target_file_path.");
1608 }
1609
1610 # Model the new target file on the source file, with the target file translations
1611 my $source_file_line_number = 0;
1612 foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
1613 # Fill in the gaps before this chunk starts
1614 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1615 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1616 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1617 print TARGET_FILE $source_file_lines[$source_file_line_number];
1618 $source_file_line_number++;
1619 }
1620 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
1621
1622 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
1623 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
1624 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
1625
1626 # If no translation exists for this chunk, show this, and move on
1627 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
1628 print TARGET_FILE "# -- Missing translation: $chunk_key\n";
1629 next;
1630 }
1631
1632 print TARGET_FILE "$chunk_key:$target_file_chunk_text";
1633 if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) {
1634 print TARGET_FILE " # " . $target_file_key_to_gti_comment_mapping->{$chunk_key};
1635 }
1636 print TARGET_FILE "\n";
1637 }
1638
1639 close(TARGET_FILE);
1640}
1641
1642
1643# ==========================================================================================
1644# GREENSTONE XML FUNCTIONS
1645
1646sub build_key_to_line_mapping_for_greenstone_xml
1647{
1648 my (@file_lines) = @_;
1649
1650 my %chunk_key_to_line_mapping = ();
1651 for (my $i = 0; $i < scalar(@file_lines); $i++) {
1652 my $line = $file_lines[$i];
1653 $line =~ s/(\s*)$//; # Remove any nasty whitespace, carriage returns etc.
1654
1655 # Line contains a string to translate
1656 if ($line =~ /^\s*<Text id=\"(.*?)\">/) {
1657 my $chunk_key = $1;
1658 $line =~ s/\s*$//; # Remove any nasty whitespace
1659 $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//;
1660
1661 # While there is still text of the string to go...
1662 my $startline = $i;
1663 while ($line !~ /<\/Text>$/) {
1664 $i++;
1665 if ($i == scalar(@file_lines)) {
1666 &throw_fatal_error("Could not find end of string $chunk_key.");
1667 }
1668 $line = $file_lines[$i];
1669 $line =~ s/\s*$//; # Remove any nasty whitespace
1670 $line =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//;
1671 }
1672
1673 # Map from chunk key to line
1674 if (!defined($chunk_key_to_line_mapping{$chunk_key})) {
1675 $chunk_key_to_line_mapping{$chunk_key} = $startline . "-" . $i;
1676 }
1677 else {
1678 &throw_fatal_error("Duplicate key $chunk_key.");
1679 }
1680 }
1681 }
1682
1683 return %chunk_key_to_line_mapping;
1684}
1685
1686
1687sub import_chunk_from_greenstone_xml
1688{
1689 my ($chunk_text) = @_;
1690
1691 # Simple: just remove the Text tags
1692 $chunk_text =~ s/^\s*<Text id=\"(.*?)\">(\s*)//;
1693 $chunk_text =~ s/<Updated date=\"\d?\d-\D\D\D-\d\d\d\d.*\"\/>$//;
1694 $chunk_text =~ s/<\/Text>$//;
1695
1696 return $chunk_text;
1697}
1698
1699
1700sub get_greenstone_xml_chunk_gti_comment
1701{
1702 my ($chunk_text) = @_;
1703
1704 # Check for an "Updated DD-MMM-YYYY" comment at the end of the chunk
1705 if ($chunk_text =~ /<Updated date=\"(\d?\d-\D\D\D-\d\d\d\d.*)\"\/>$/i) {
1706 return $1;
1707 }
1708
1709 return undef;
1710}
1711
1712
1713sub is_greenstone_xml_chunk_automatically_translated
1714{
1715 # No greenstone XML chunks are automatically translated
1716 return 0;
1717}
1718
1719
1720sub write_translated_greenstone_xml
1721{
1722 my $source_file = shift(@_); # Not used
1723 my @source_file_lines = @{shift(@_)};
1724 my $source_file_key_to_text_mapping = shift(@_);
1725 my $target_file = shift(@_);
1726 my @target_file_lines = @{shift(@_)}; # Not used
1727 my $target_file_key_to_text_mapping = shift(@_);
1728 my $target_file_key_to_gti_comment_mapping = shift(@_);
1729 my $target_language_code = shift(@_); # Not used
1730
1731 # Build a mapping from chunk key to source file line, and from source file line to chunk key
1732 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_greenstone_xml(@source_file_lines);
1733 my %source_file_line_to_key_mapping = ();
1734 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1735 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1736 }
1737
1738 # Write the new target file
1739 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1740 if (!open(TARGET_FILE, ">$target_file_path")) {
1741 &throw_fatal_error("Could not write target file $target_file_path.");
1742 }
1743
1744 # Model the new target file on the source file, with the target file translations
1745 my $source_file_line_number = 0;
1746 foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
1747 # Fill in the gaps before this chunk starts
1748 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1749 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1750 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1751 print TARGET_FILE $source_file_lines[$source_file_line_number];
1752 $source_file_line_number++;
1753 }
1754 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
1755
1756 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
1757 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$chunk_key};
1758 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$chunk_key} || "";
1759 $target_file_chunk_text =~ s/(\n)*$//g;
1760
1761 # If no translation exists for this chunk, show this, and move on
1762 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
1763 print TARGET_FILE "<!-- Missing translation: $chunk_key -->\n";
1764 next;
1765 }
1766
1767 print TARGET_FILE "<Text id=\"$chunk_key\">$target_file_chunk_text</Text>";
1768 if ($target_file_key_to_gti_comment_mapping->{$chunk_key}) {
1769 my $chunk_gti_comment = $target_file_key_to_gti_comment_mapping->{$chunk_key};
1770 $chunk_gti_comment =~ s/^Updated //;
1771 print TARGET_FILE "<Updated date=\"" . $chunk_gti_comment . "\"\/>";
1772 }
1773 print TARGET_FILE "\n";
1774 }
1775
1776 # Fill in the end of the file
1777 while ($source_file_line_number < scalar(@source_file_lines)) {
1778 print TARGET_FILE $source_file_lines[$source_file_line_number];
1779 $source_file_line_number++;
1780 }
1781
1782 close(TARGET_FILE);
1783}
1784
1785
1786# ==========================================================================================
1787# GREENSTONE3 FUNCTIONS
1788
1789sub get_all_chunks_for_gs3
1790{
1791 # The code of the target language (ensure it is lowercase)
1792 my $target_language_code = lc(shift(@_));
1793 my $translation_file_key = lc(shift(@_));
1794
1795 # Check that the necessary arguments were supplied
1796 if (!$target_language_code) {
1797 &throw_fatal_error("Missing command argument.");
1798 }
1799
1800 # Get (and check) the translation configuration
1801 # my ($source_file_dir, $target_file, $translation_file_type) = &get_translation_configuration($target_language_code, $translation_file_key);
1802
1803 my %source_files_key_to_text_mapping = ();
1804 my %target_files_key_to_text_mapping = ();
1805 my %source_files_key_to_last_update_date_mapping = ();
1806 my %target_files_key_to_last_update_date_mapping = ();
1807
1808 &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);
1809
1810 &log_message("Total number of source chunks: " . scalar(keys(%source_files_key_to_text_mapping)));
1811 &log_message("Total number of target chunks: " . scalar(keys(%target_files_key_to_text_mapping)));
1812
1813 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);
1814 return $xml_response;
1815}
1816
1817
1818sub get_first_n_chunks_requiring_work_for_gs3
1819{
1820 # The code of the target language (ensure it is lowercase)
1821 my $target_language_code = lc(shift(@_));
1822 # The key of the file to translate (ensure it is lowercase)
1823 my $translation_file_key = lc(shift(@_));
1824 # The number of chunks to return (defaults to one if not specified)
1825 my $num_chunks_to_return = shift(@_) || "1";
1826
1827 # Check that the necessary arguments were supplied
1828 if (!$target_language_code || !$translation_file_key) {
1829 &throw_fatal_error("Missing command argument.");
1830 }
1831
1832 my %source_files_key_to_text_mapping = ();
1833 my %target_files_key_to_text_mapping = ();
1834 my %source_files_key_to_last_update_date_mapping = ();
1835 my %target_files_key_to_last_update_date_mapping = ();
1836
1837 &build_gs3_configuration($target_language_code, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,
1838 \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1839
1840 # Determine the target file chunks requiring translation
1841 my @target_files_keys_requiring_translation = &determine_chunks_requiring_translation(\%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping);
1842 # Determine the target file chunks requiring updating
1843 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);
1844 &log_message("Total number of target chunks requiring translation: " . scalar(@target_files_keys_requiring_translation));
1845 &log_message("Total number of target chunks requiring updating: " . scalar(@target_files_keys_requiring_updating));
1846
1847 my $xml_response = &create_xml_response_for_chunks_requiring_work($translation_file_key, "", scalar(keys(%source_files_key_to_text_mapping)),
1848 \@target_files_keys_requiring_translation, \@target_files_keys_requiring_updating,
1849 $num_chunks_to_return, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,
1850 \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1851
1852 return $xml_response;
1853}
1854
1855sub get_uptodate_chunks_for_gs3
1856{
1857 # The code of the target language (ensure it is lowercase)
1858 my $target_language_code = lc(shift(@_));
1859 # The key of the file to translate (ensure it is lowercase)
1860 my $translation_file_key = lc(shift(@_));
1861 # The number of chunks to return (defaults to one if not specified)
1862 my $num_chunks_to_return = shift(@_) || "1";
1863
1864 # Check that the necessary arguments were supplied
1865 if (!$target_language_code || !$translation_file_key) {
1866 &throw_fatal_error("Missing command argument.");
1867 }
1868
1869 my %source_files_key_to_text_mapping = ();
1870 my %target_files_key_to_text_mapping = ();
1871 my %source_files_key_to_last_update_date_mapping = ();
1872 my %target_files_key_to_last_update_date_mapping = ();
1873
1874 &build_gs3_configuration($target_language_code, \%source_files_key_to_text_mapping, \%target_files_key_to_text_mapping,
1875 \%source_files_key_to_last_update_date_mapping, \%target_files_key_to_last_update_date_mapping);
1876
1877
1878 # Chunks needing updating are those in the target file that have been more recently edited in the source file
1879 # All others are uptodate (which implies that they have certainly been translated at some point and would not be empty)
1880 my @uptodate_target_file_keys = ();
1881 foreach my $chunk_key (keys(%source_files_key_to_last_update_date_mapping)) {
1882 my $source_chunk_last_update_date = $source_files_key_to_last_update_date_mapping{$chunk_key};
1883 my $target_chunk_last_update_date = $target_files_key_to_last_update_date_mapping{$chunk_key};
1884
1885 # 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";
1886
1887 if (defined($target_chunk_last_update_date) && !&is_date_after($source_chunk_last_update_date, $target_chunk_last_update_date)) {
1888 # &log_message("Chunk with key $chunk_key needs updating.");
1889 push(@uptodate_target_file_keys, $chunk_key);
1890 }
1891 }
1892
1893 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);
1894
1895 return $xml_response;
1896}
1897
1898
1899sub build_gs3_configuration
1900{
1901 my ($target_language_code, $source_files_key_to_text_mapping, $target_files_key_to_text_mapping,
1902 $source_files_key_to_gti_comment_mapping, $target_files_key_to_gti_comment_mapping) = @_;
1903
1904 my $source_file_directory = "greenstone3"; # my $source_file_directory = &util::filename_cat("WEB-INF","classes");
1905 my $translation_file_type = "resource_bundle";
1906
1907 foreach my $interface_file_key (@gs3_interface_files) {
1908
1909 &log_message("Greenstone 3 interface file: " . $interface_file_key);
1910
1911 # Parse the source language and target language files
1912 my $source_file = &util::filename_cat($source_file_directory, $interface_file_key.".properties");
1913 my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file));
1914 my %source_file_key_to_line_mapping = &build_key_to_line_mapping(\@source_file_lines, $translation_file_type);
1915 my %source_file_key_to_text_mapping = &build_key_to_text_mapping(\@source_file_lines, \%source_file_key_to_line_mapping, $translation_file_type);
1916 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);
1917
1918 my $target_file = &util::filename_cat($source_file_directory, $interface_file_key."_".$target_language_code.".properties");
1919 my @target_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $target_file));
1920 my %target_file_key_to_line_mapping = &build_key_to_line_mapping(\@target_file_lines, $translation_file_type);
1921 my %target_file_key_to_text_mapping = &build_key_to_text_mapping(\@target_file_lines, \%target_file_key_to_line_mapping, $translation_file_type);
1922 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);
1923
1924
1925 # Filter out any automatically translated chunks
1926 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1927 if (&is_chunk_automatically_translated($chunk_key, $translation_file_type)) {
1928 delete $source_file_key_to_line_mapping{$chunk_key};
1929 delete $target_file_key_to_line_mapping{$chunk_key};
1930 }
1931 }
1932
1933 &log_message("Number of source chunks: " . scalar(keys(%source_file_key_to_text_mapping)));
1934 &log_message("Number of target chunks: " . scalar(keys(%target_file_key_to_text_mapping)));
1935
1936 foreach my $chunk_key (keys(%source_file_key_to_text_mapping)) {
1937 my $global_chunk_key = "$interface_file_key.$chunk_key";
1938 $source_files_key_to_text_mapping->{$global_chunk_key} = $source_file_key_to_text_mapping{$chunk_key};
1939 $source_files_key_to_gti_comment_mapping->{$global_chunk_key} = $source_file_key_to_gti_comment_mapping{$chunk_key};
1940
1941 if (defined $target_file_key_to_text_mapping{$chunk_key}) {
1942 $target_files_key_to_text_mapping->{$global_chunk_key} = $target_file_key_to_text_mapping{$chunk_key};
1943 $target_files_key_to_gti_comment_mapping->{$global_chunk_key} = $target_file_key_to_gti_comment_mapping{$chunk_key};
1944 }
1945 }
1946 }
1947}
1948
1949
1950sub write_translated_gs3interface
1951{
1952 my $source_file_key_to_text_mapping = shift(@_);
1953 my $target_file_key_to_text_mapping = shift(@_);
1954 my $target_file_key_to_gti_comment_mapping = shift(@_);
1955 my $target_language_code = shift(@_);
1956
1957 my @sorted_chunk_keys = sort (keys(%$source_file_key_to_text_mapping));
1958
1959 my %translated_interface_file_keys = ();
1960 foreach my $chunk_key (keys(%$target_file_key_to_text_mapping)) {
1961 $chunk_key =~ /^([^\.]+)?\.(.*)$/;
1962 if (!defined $translated_interface_file_keys{$1}) {
1963 &log_message("Updated interface file: " . $1);
1964 $translated_interface_file_keys{$1}="";
1965 }
1966 }
1967 &log_message("Updated interface files: " . scalar(keys(%translated_interface_file_keys)));
1968
1969 my $source_file_directory = "greenstone3";
1970
1971 foreach my $interface_file_key (keys(%translated_interface_file_keys)) {
1972
1973 # Build a mapping from chunk key to source file line, and from source file line to chunk key
1974 my $source_file = &util::filename_cat($source_file_directory, "$interface_file_key.properties");
1975 my @source_file_lines = &read_file_lines(&util::filename_cat($gsdl_root_directory, $source_file));
1976 my %source_file_key_to_line_mapping = &build_key_to_line_mapping_for_resource_bundle(@source_file_lines);
1977 my %source_file_line_to_key_mapping = ();
1978 foreach my $chunk_key (keys(%source_file_key_to_line_mapping)) {
1979 $source_file_line_to_key_mapping{$source_file_key_to_line_mapping{$chunk_key}} = $chunk_key;
1980 }
1981
1982 # Write the new target file
1983 my $target_file = &util::filename_cat($source_file_directory, $interface_file_key . "_" . $target_language_code . ".properties");
1984 my $target_file_path = &util::filename_cat($gsdl_root_directory, $target_file);
1985 if (!open(TARGET_FILE, ">$target_file_path")) {
1986 &throw_fatal_error("Could not write target file $target_file_path.");
1987 }
1988
1989 # Model the new target file on the source file, with the target file translations
1990 my $source_file_line_number = 0;
1991 foreach my $line_key (sort sort_by_line (keys(%source_file_line_to_key_mapping))) {
1992 # Fill in the gaps before this chunk starts
1993 my $source_file_chunk_starting_line_number = (split(/-/, $line_key))[0];
1994 my $source_file_chunk_finishing_line_number = (split(/-/, $line_key))[1];
1995 while ($source_file_line_number < $source_file_chunk_starting_line_number) {
1996 print TARGET_FILE $source_file_lines[$source_file_line_number];
1997 $source_file_line_number++;
1998 }
1999 $source_file_line_number = $source_file_chunk_finishing_line_number + 1;
2000
2001 my $chunk_key = $source_file_line_to_key_mapping{$line_key};
2002 my $global_chunk_key = "$interface_file_key.$chunk_key";
2003 my $source_file_chunk_text = $source_file_key_to_text_mapping->{$global_chunk_key};
2004 my $target_file_chunk_text = $target_file_key_to_text_mapping->{$global_chunk_key} || "";
2005
2006 # If no translation exists for this chunk, show this, and move on
2007 if ($source_file_chunk_text ne "" && $target_file_chunk_text eq "") {
2008 print TARGET_FILE "# -- Missing translation: $chunk_key\n";
2009 next;
2010 }
2011
2012 print TARGET_FILE "$chunk_key:$target_file_chunk_text";
2013 if ($target_file_key_to_gti_comment_mapping->{$global_chunk_key}) {
2014 print TARGET_FILE " # " . $target_file_key_to_gti_comment_mapping->{$global_chunk_key};
2015 }
2016 print TARGET_FILE "\n";
2017 }
2018
2019 close(TARGET_FILE);
2020 }
2021}
2022
2023&main(@ARGV);
Note: See TracBrowser for help on using the repository browser.