Added SILC Thread Queue API
[crypto.git] / apps / silcer / xml-i18n-update.in
1 #!@XML_I18N_TOOLS_PERL@ -w
2
3 #  The GNOME Translation Update Tool
4 #
5 #  Copyright (C) 2000 Free Software Foundation.
6 #
7 #  This library is free software; you can redistribute it and/or
8 #  modify it under the terms of the GNU General Public License as
9 #  published by the Free Software Foundation; either version 2 of the
10 #  License, or (at your option) any later version.
11 #
12 #  This script is distributed in the hope that it will be useful,
13 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 #  General Public License for more details.
16 #
17 #  You should have received a copy of the GNU General Public License
18 #  along with this library; if not, write to the Free Software
19 #  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #
21 #  Author(s): Kenneth Christiansen
22
23 ## Release information
24 my $PROGRAM  = "xml-i18n-update";
25 my $VERSION  = "0.9";
26 my $_PACKAGE = "xml-i18n-tools";
27
28 ## Loaded modules
29 use strict;
30 use Getopt::Long;
31 use Cwd;
32 use File::Copy;
33 use File::Find;
34
35 ## Scalars used by the option stuff
36 my $LANG           = $ARGV[0];
37 my $HELP_ARG       = "0";
38 my $VERSION_ARG    = "0";
39 my $DIST_ARG       = "0";
40 my $POT_ARG        = "0";
41 my $HEADERS_ARG    = "0";
42 my $MAINTAIN_ARG   = "0";
43 my $REPORT_ARG     = "0";
44 my $VERBOSE        = "0";
45
46 my @languages;
47 my %po_files_by_lang = ();
48
49 my $xml_extension = 
50 "xml(\.in)*|".          # .in is not required
51 "ui|".
52 "glade(\.in)*|".        # .in is not required
53 "desktop(\.in)+|".
54 "directory(\.in)+|".
55 "soundlist(\.in)+|".
56 "keys(\.in)+|".
57 "oaf(\.in)+|".
58 "server(\.in)+|".
59 "etspec|".
60 "pong(\.in)+";
61
62 my $PACKAGE = &find_package_name;
63
64 ## Always print as the first thing
65 $| = 1;
66
67 ## Give error if script is run without an argument
68 if (! $LANG){
69     print "${PROGRAM}:  missing file arguments\n";
70     print "Try `${PROGRAM} --help' for more information.\n";
71     exit;
72 }
73
74 ## Handle options
75 GetOptions (
76             "help|h|?"          => \$HELP_ARG,
77             "version|v"         => \$VERSION_ARG,
78             "dist|d"            => \$DIST_ARG,
79             "pot|p"             => \$POT_ARG,
80             "headers|s"         => \$HEADERS_ARG,
81             "maintain|m"        => \$MAINTAIN_ARG,
82             "report|r"          => \$REPORT_ARG,
83             "verbose|x"         => \$VERBOSE
84             ) or &invalid_option;
85
86
87 ## Use the supplied arguments
88 ## Check for options.
89 ## This section will check for the different options.
90
91 sub split_on_argument {
92
93     if ($VERSION_ARG) {
94         &version;
95
96     } elsif ($HELP_ARG) {
97         &help;
98
99     } elsif ($DIST_ARG) {
100         &merging;
101         &status;
102
103     } elsif ($POT_ARG) {
104         &gen_headers;
105         &generate_pot;
106
107     } elsif ($HEADERS_ARG) {
108         &gen_headers;
109         exit;
110
111     } elsif ($MAINTAIN_ARG) {
112         &maintain;
113
114     } elsif ($REPORT_ARG) {
115         &show_status;
116
117     } elsif ($LANG) {
118         if ($LANG =~ /^-/){ ## not an option
119             &help;
120         } else {
121             &main;
122         }
123
124     } else {
125         &help;
126     }
127 }
128
129 &split_on_argument;
130
131 sub main
132 {
133    if(-s "$LANG.po"){
134         print "Working, please wait..." unless $VERBOSE;
135         &gen_headers;
136         &generate_pot;
137         &merging;
138         &status;
139    }
140
141    ## Report error if the language file supplied
142    ## to the command line is non-existent
143    else {
144         &not_existing;
145    }
146 }
147
148 sub determine_type($) {
149    my $type = $_;
150
151    my $gettext_type;
152
153    if ($type =~ /\[type: (gettext\/[^\]].*)]/) {
154         $gettext_type=$1;
155    }
156    elsif ($type =~ /(?:xml(\.in)*|ui|oaf(?:\.in)+|pong(?:\.in)+|etspec)$/) {
157         $gettext_type="gettext\/xml";
158    }
159    elsif ($type =~ /glade(\.in)*$/) {
160         $gettext_type="gettext\/glade";
161    }
162    elsif ($type =~ /(?:desktop(?:\.in)+|directory(?:\.in)+|soundlist(?:\.in)+)$/) {
163         $gettext_type="gettext\/ini";
164    }
165    elsif ($type =~ /keys(\.in)+$/) {
166         $gettext_type="gettext\/keys";
167    }
168    else { $gettext_type=""; }
169
170    return $gettext_type;
171 }
172
173 sub version{
174
175     ## Print version information
176     print "${PROGRAM} (${_PACKAGE}) $VERSION\n";
177     print "Written by Kenneth Christiansen <kenneth\@gnome.org>, 2000.\n\n";
178     print "Copyright (C) 2000 Free Software Foundation, Inc.\n";
179     print "This is free software; see the source for copying conditions.  There is NO\n";
180     print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
181     exit;
182 }
183
184 sub help
185 {
186     ## Print usage information
187     print "Usage: ./${PROGRAM} [OPTIONS] ...LANGCODE\n";
188     print "Updates pot files and merge them with the translations.\n\n";
189     print "  -H, --help                   shows this help page\n";
190     print "  -P, --pot                    generate the pot file only\n";
191     print "  -S, --headers                generate the XML headerfiles in POTFILES.in\n";
192     print "  -M, --maintain               search for missing files in POTFILES.in\n";
193     print "  -R, --report                 creates a status report for the module.\n";
194     print "  -X, --verbose                show lots of feedback\n";
195     print "  -V, --version                shows the version\n";
196     print "\nExamples of use:\n";
197     print "${PROGRAM} --pot    just creates a new pot file from the source\n";
198     print "${PROGRAM} da       created new pot file and updated the da.po file\n\n";
199     print "Report bugs to <kenneth\@gnome.org>.\n";
200     exit;
201 }
202
203 sub maintain
204 {
205     my (@buf_i18n_plain,
206         @buf_i18n_xml,
207         @buf_potfiles,
208         @buf_potfiles_ignore,
209         @buf_allfiles,
210         @buf_allfiles_sorted,
211         @buf_potfiles_sorted
212     );
213
214     ## Search and find all translatable files
215     find sub { push @buf_i18n_plain, "$File::Find::name" if /\.(c|y|cc|c\+\+|h|gob)$/ }, "..";
216     find sub { push @buf_i18n_xml, "$File::Find::name" if /\.($xml_extension)$/ }, "..";
217
218     open(POTFILES, "POTFILES.in") || die "$PROGRAM:  there's no POTFILES.in!!!\n";
219     @buf_potfiles = <POTFILES>;
220
221     print "Searching for missing translatable files...\n";
222
223     ## Check if we should ignore some found files, when
224     ## comparing with POTFILES.in
225     if (-s "POTFILES.skip"){
226         open FILE, "POTFILES.skip";
227         while (<FILE>) {
228             if (/^[^#]/){
229                 push @buf_potfiles_ignore, $_;
230             }
231         }
232         print "Found POTFILES.skip: Ignoring files...\n";
233         @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles);
234     }
235
236     foreach my $file (@buf_i18n_plain){
237         open FILE, "<$file";
238         while (<FILE>) {
239             if (/_\(\"/){
240                 ## Remove the first 3 chars and add newline
241                 push @buf_allfiles, unpack("x3 A*", $file) . "\n";
242                 last;
243             }
244         }
245     }
246
247     foreach my $file (@buf_i18n_xml){
248         open FILE, "<$file";
249         while (<FILE>) {
250             if (/\s_(.*)=\"/){
251                 ## Remove the first 3 chars and add newline
252                 push @buf_allfiles, unpack("x3 A*", $file) . "\n";
253                 last;
254             }
255         }
256     }
257
258     @buf_allfiles_sorted = sort (@buf_allfiles);
259     @buf_potfiles_sorted = sort (@buf_potfiles);
260
261     my %in2;
262     foreach (@buf_potfiles_sorted) {
263         $in2{$_} = 1;
264     }
265
266     my @result;
267
268     foreach (@buf_allfiles_sorted){
269         if (!exists($in2{$_})){
270             push @result, $_
271         }
272     }
273
274     ## Save file with information about the files missing
275     ## if any, and give information about this proceedier
276     if(@result){
277         open OUT, ">missing";
278         print OUT @result;
279         print "\nHere is the result:\n\n", @result, "\n";
280         print "The file \"missing\" has been placed in the current directory.\n";
281         print "Files supposed to be ignored should be placed in \"POTFILES.skip\"\n";
282     }
283
284     ## If there is nothing to complain about, notice the user
285     else{
286         print "\nWell, it's all perfect! Congratulation!\n";
287     }
288 }
289
290 sub invalid_option
291 {
292     ## Handle invalid arguments
293     print "${PROGRAM}: invalid option -- $LANG\n";
294     print "Try `${PROGRAM} --help' for more information.\n";
295     exit 1;
296 }
297
298 sub gen_headers
299 {
300     my $XML_I18N_EXTRACT = `which xml-i18n-extract 2>/dev/null`;
301     chomp $XML_I18N_EXTRACT;
302
303     $XML_I18N_EXTRACT = $ENV{"XML_I18N_EXTRACT"} if $ENV{"XML_I18N_EXTRACT"};
304
305     ## Generate the .h header files, so we can allow glade and
306     ## xml translation support
307     if (! -s $XML_I18N_EXTRACT)
308     {
309         print "\n *** The xml-i18n-extract script wasn't found!"
310              ."\n *** Without this xml-i18n-update can not generate files.\n";
311         exit;
312     }
313     else
314     {
315         open FILE, "<POTFILES.in";
316         while (<FILE>) {
317            chomp;
318
319            ## Find xml files in POTFILES.in and generate the
320            ## files with help from the xml-i18n-extract script
321
322            my $gettext_type=&determine_type($1);
323
324            if (/\.($xml_extension)$/ || /^\[/){
325                $_ =~ s/^\[[^\[].*]\s*//;
326                my $filename = "../$_";
327
328                if ($VERBOSE){
329                    system($XML_I18N_EXTRACT, "--update", "--type=$gettext_type", $filename);
330                } else {
331                    system($XML_I18N_EXTRACT, "--update", "--type=$gettext_type", "--quiet", $filename);
332                }
333            }
334        }
335        close FILE;
336    }
337 }
338
339 sub generate_pot
340 {
341     ## Generate the potfiles from the POTFILES.in file
342
343     print "Building the $PACKAGE.pot...\n" if $VERBOSE;
344
345     move("POTFILES.in", "POTFILES.in.old");
346
347     open INFILE, "<POTFILES.in.old";
348     open OUTFILE, ">POTFILES.in";
349     while (<INFILE>) {
350         s/\.($xml_extension)$/$&.h/;
351         s/^\[.*]\s*(.*)/$1.h/;
352         print OUTFILE $_;
353     }
354     close OUTFILE;
355     close INFILE;
356
357     my $gettext_test   ="test \! -f $PACKAGE\.po \|\| \( rm -f \.\/$PACKAGE\.pot "
358                        ."&& mv $PACKAGE\.po \.\/$PACKAGE\.pot \)";
359
360     system("xgettext", "--default-domain\=$PACKAGE", "--directory\=\.\.",
361            "--add-comments", "--keyword\=\_", "--keyword\=N\_",
362            "--files-from\=\.\/POTFILES\.in");
363
364     system($gettext_test);
365
366     print "Wrote $PACKAGE.pot\n" if $VERBOSE;
367
368     move("POTFILES.in.old", "POTFILES.in");
369
370     print "Removing generated header (.h) files..." if $VERBOSE;
371
372     open FILE, "<POTFILES.in";
373     while (<FILE>)
374     {
375         chomp;
376         unlink "../$_.h" if /\.($xml_extension)$/;
377     }
378     close FILE;
379     print "done\n" if $VERBOSE;
380 }
381
382 sub merging
383 {
384     if ($ARGV[1]){
385         $LANG   = $ARGV[1];
386     } else {
387         $LANG   = $ARGV[0];
388     }
389
390     if ($ARGV[0] ne "--dist" && $ARGV[0] ne "-D") {
391         print "Merging $LANG.po with $PACKAGE.pot..." if $VERBOSE;
392     }
393
394     &perform_merge($LANG);
395     ## Remove the "messages" trash file generated by gettext
396     unlink "messages";
397 }
398
399 sub perform_merge
400 {
401     my ($LANG) = @_;
402
403     copy("$LANG.po", "$LANG.po.old") || die "copy failed: $!";
404
405     ## Preform merge
406     system("msgmerge", "$LANG.po.old", "$PACKAGE.pot", "-o", "$LANG.po");
407
408     ## Remove the backup file
409     unlink "$LANG.po.old";
410 }
411
412 sub not_existing
413 {
414     ## Report error if supplied language file is non-existing
415     print "$PROGRAM:  sorry, $LANG.po does not exist!\n";
416     print "Try `$PROGRAM --help' for more information.\n";
417     exit;
418 }
419
420 sub gather_po_files
421 {
422     my @po_files = glob("./*.po");
423
424     @languages = map (&po_file2lang, @po_files);
425
426     foreach my $lang (@languages) {
427         $po_files_by_lang{$lang} = shift (@po_files);
428     }
429 }
430
431 sub po_file2lang
432 {
433     my $tmp = $_;
434     $tmp =~ s/^.*\/(.*)\.po$/$1/;
435     return $tmp;
436 }
437
438 sub status
439 {
440     ## Print statistics
441     system("msgfmt", "--statistics", "$LANG.po");
442     print "\n";
443 }
444
445 sub show_status
446 {
447     &gen_headers;
448     &generate_pot;
449     &gather_po_files;
450
451     foreach my $lang (@languages){
452         print "$lang: ";
453         &perform_merge($lang);
454     }
455
456     print "\n\n * Current translation support in $PACKAGE \n\n";
457
458     foreach my $lang (@languages){
459         print "$lang: ";
460         ## Print statistics
461         system("msgfmt", "--statistics", "$lang.po");
462     }
463 }
464
465 sub find_package_name
466 {
467     my $base_dirname = getcwd();
468     $base_dirname =~ s@.*/@@;
469
470     my ($conf_in, $src_dir);
471
472     if ($base_dirname eq "po") {
473         if (-f "../configure.in") {
474             $conf_in = "../configure.in";
475         } else {
476             my $makefile_source;
477             local (*IN);
478             open (IN, "<Makefile") || die "can't open Makefile: $!";
479
480             while (<IN>) {
481                 if (/^top_srcdir[ \t]*=/) {
482                     $src_dir = $_;
483                     # print "${src_dir}\n";
484
485                     $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/;
486                     # print "${src_dir}\n";
487                     chomp $src_dir;
488                     $conf_in = "$src_dir" . "/configure.in" . "\n";
489                     last;
490                 }
491             }
492             $conf_in || die "Cannot find top_srcdir in Makefile."
493         }
494
495         my $conf_source; {
496            local (*IN);
497            local $/; # slurp mode
498            open (IN, "<$conf_in") || die "can't open $conf_in: $!";
499            $conf_source = <IN>;
500         }
501
502         if ($conf_source =~ /AM_INIT_AUTOMAKE\(([^,]*),(.*)/) {
503             my $package_name = $1;
504             if ($package_name =~ /^[\$](.*)/){
505                 if ($conf_source =~ /$1=(.*)/) {
506                     $package_name = $1;
507                 }
508             }
509             return $package_name;
510         }
511     }
512
513     print "$PROGRAM: Unable to determine package name.\n" .
514           "Make sure to run this script inside the po directory.\n";
515     exit;
516 }