source: trunk/third/gal/xml-i18n-update.in @ 17392

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