source: trunk/third/evolution/xml-i18n-update.in @ 19030

Revision 19030, 16.0 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19029, which included commits to RCS files with non-trunk default branches.
RevLine 
[17187]1#!@INTLTOOL_PERL@ -w
[16769]2
[17396]3#
[17187]4#  The Intltool Message Updater
[16769]5#
[17396]6#  Copyright (C) 2000-2002 Free Software Foundation.
[16769]7#
[17187]8#  Intltool is free software; you can redistribute it and/or
[17396]9#  modify it under the terms of the GNU General Public License
10#  version 2 published by the Free Software Foundation.
[16769]11#
[17187]12#  Intltool is distributed in the hope that it will be useful,
[16769]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
[17187]18#  along with this program; if not, write to the Free Software
[16769]19#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20#
[17187]21#  As a special exception to the GNU General Public License, if you
22#  distribute this file as part of a program that contains a
23#  configuration script generated by Autoconf, you may include it under
24#  the same distribution terms that you use for the rest of that program.
25#
[17396]26#  Authors: Kenneth Christiansen <kenneth@gnu.org>
27#           Maciej Stachowiak
28#           Darin Adler <darin@bentspoon.com>
[16769]29
30## Release information
[17396]31my $PROGRAM = "intltool-update";
[19029]32my $VERSION = "0.25";
[17396]33my $PACKAGE = "intltool";
[16769]34
35## Loaded modules
36use strict;
37use Getopt::Long;
38use Cwd;
39use File::Copy;
40use File::Find;
41
42## Scalars used by the option stuff
[17396]43my $HELP_ARG       = 0;
44my $VERSION_ARG    = 0;
45my $DIST_ARG       = 0;
46my $POT_ARG        = 0;
47my $HEADERS_ARG    = 0;
48my $MAINTAIN_ARG   = 0;
49my $REPORT_ARG     = 0;
50my $VERBOSE        = 0;
[17187]51my $GETTEXT_PACKAGE = "";
[16769]52
53my @languages;
54my %po_files_by_lang = ();
55
[17396]56# Regular expressions to categorize file types.
57# FIXME: Please check if the following is correct
58
59my $xml_extension =
[16769]60"xml(\.in)*|".          # .in is not required
61"ui|".
[17396]62"glade2?(\.in)*|".      # .in is not required
[17187]63"scm(\.in)*|".          # .in is not required
[16769]64"oaf(\.in)+|".
65"etspec|".
[16864]66"sheet(\.in)+|".
[18141]67"schemas(\.in)+|".
[16769]68"pong(\.in)+";
69
[17396]70my $ini_extension =
71"desktop(\.in)+|".
72"caves(\.in)+|".
73"directory(\.in)+|".
74"soundlist(\.in)+|".
75"keys(\.in)+|".
[19029]76"theme(\.in)+|".
[17396]77"server(\.in)+";
78
[16769]79## Always print as the first thing
80$| = 1;
81
82## Handle options
[17396]83GetOptions
84(
85 "help"                => \$HELP_ARG,
86 "version"             => \$VERSION_ARG,
87 "dist|d"              => \$DIST_ARG,
88 "pot|p"               => \$POT_ARG,
89 "headers|s"           => \$HEADERS_ARG,
90 "maintain|m"          => \$MAINTAIN_ARG,
91 "report|r"            => \$REPORT_ARG,
92 "verbose|x"           => \$VERBOSE,
93 "gettext-package|g=s" => \$GETTEXT_PACKAGE,
94 ) or &print_error_invalid_option;
[16769]95
[17396]96&print_help if $HELP_ARG;
97&print_version if $VERSION_ARG;
[16769]98
[17396]99my $arg_count = ($DIST_ARG > 0)
100    + ($POT_ARG > 0)
101    + ($HEADERS_ARG > 0)
102    + ($MAINTAIN_ARG > 0)
103    + ($REPORT_ARG > 0);
104&print_help if $arg_count > 1;
[16769]105
[17396]106# --version and --help don't require a module name
107my $MODULE = $GETTEXT_PACKAGE || &find_package_name;
[16769]108
[17396]109if ($DIST_ARG) {
110    if ($ARGV[0] =~ /^[a-z]/){
111        &update_po_file ($ARGV[0]);
112        &print_status ($ARGV[0]);
113    } else {
114        &print_help;
115    }
116} elsif ($POT_ARG) {
117    &generate_headers;
118    &generate_po_template;
119} elsif ($HEADERS_ARG) {
120    &generate_headers;
121} elsif ($MAINTAIN_ARG) {
122    &find_leftout_files;
123} elsif ($REPORT_ARG) {
124    &print_report;
125} else {
126    if ($ARGV[0] =~ /^[a-z]/) {
127        &main ($ARGV[0]);
128    } else {
129        &print_help;
130    }
131}
[16769]132
[17396]133exit;
[16769]134
[17396]135#########
[16769]136
[17396]137sub print_version
138{
139    ## Print version information
140    print "${PROGRAM} (${PACKAGE}) $VERSION\n";
141    print "Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler.\n\n";
142    print "Copyright (C) 2000-2002 Free Software Foundation, Inc.\n";
143    print "This is free software; see the source for copying conditions.  There is NO\n";
144    print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
145    exit;
146}
[16769]147
[17396]148sub print_help
149{
150    ## Print usage information
151    print "Usage: ${PROGRAM} [OPTIONS] ...LANGCODE\n";
152    print "Updates PO template files and merge them with the translations.\n\n";
153    print "  -p, --pot              generate the PO template only\n";
154    print "  -s, --headers          generate the header files in POTFILES.in\n";
155    print "  -m, --maintain         search for left out files from POTFILES.in\n";
156    print "  -r, --report           display a status report for the module.\n";
157    print "  -x, --verbose          display lots of feedback\n";
158    print "      --help             display this help and exit\n";
159    print "      --version          output version information and exit\n";
160    print "\nExamples of use:\n";
161    print "${PROGRAM} --pot    just creates a new PO template from the source\n";
162    print "${PROGRAM} da       created new PO template and updated the da.po file\n\n";
163    print "Report bugs to bugzilla.gnome.org, module 'intltool'.\n";
164    exit;
[16769]165}
166
167sub main
168{
[17396]169    my ($lang) = @_;
[16769]170
[17396]171    ## Report error if the language file supplied
172    ## to the command line is non-existent
173    &print_error_not_existing("$lang.po") if ! -s "$lang.po";
174
175    print "Working, please wait..." unless $VERBOSE;
176    &generate_headers;
177    &generate_po_template;
178    &update_po_file ($lang);
179    &print_status ($lang);
[16769]180}
181
[17396]182sub determine_type ($)
183{
[16769]184   my $type = $_;
185   my $gettext_type;
186
[17396]187   # FIXME: Use $xml_extentions, and maybe do all this even nicer
188   my $xml_regex =
189       "(?:xml(\.in)*|ui|oaf(?:\.in)+|server(?:\.in)+|sheet(?:\.in)+|".
[18141]190       "pong(?:\.in)+|etspec|schemas(?:\.in)+)";
[17396]191   my $ini_regex =
[19029]192       "(?:desktop(?:\.in)+|theme(?:\.in)+|caves(?:\.in)+|directory(?:\.in)+|".
[17396]193       "soundlist(?:\.in)+)";
194
195   if ($type =~ /\[type: gettext\/([^\]].*)]/) {
[16769]196        $gettext_type=$1;
197   }
[18141]198   elsif ($type =~ /schemas(\.in)+$/) {
199        $gettext_type="schemas";
200   }
[17396]201   elsif ($type =~ /$xml_regex$/) {
202        $gettext_type="xml";
[16769]203   }
[17396]204   elsif ($type =~ /glade2?(\.in)*$/) {
205        $gettext_type="glade";
[16769]206   }
[17396]207   elsif ($type =~ /$ini_regex$/) {
208        $gettext_type="ini";
[16769]209   }
[17187]210   elsif ($type =~ /scm(\.in)*$/) {
[17396]211        $gettext_type="scheme";
[17187]212   }
[16769]213   elsif ($type =~ /keys(\.in)+$/) {
[17396]214        $gettext_type="keys";
[16769]215   }
216   else { $gettext_type=""; }
217
[17396]218   return "gettext\/$gettext_type";
[16769]219}
220
[17396]221sub find_leftout_files
[16769]222{
223    my (@buf_i18n_plain,
224        @buf_i18n_xml,
[18141]225        @buf_i18n_xml_unmarked,
[17396]226        @buf_i18n_ini,
[16769]227        @buf_potfiles,
228        @buf_potfiles_ignore,
229        @buf_allfiles,
230        @buf_allfiles_sorted,
231        @buf_potfiles_sorted
232    );
233
234    ## Search and find all translatable files
[17396]235    find sub {
236        push @buf_i18n_plain, "$File::Find::name" if /\.(c|y|cc|cpp|c\+\+|h|gob)$/
237        }, "..";
238    find sub {
239        push @buf_i18n_xml, "$File::Find::name" if /\.($xml_extension)$/
240        }, "..";
241    find sub {
242        push @buf_i18n_ini, "$File::Find::name" if /\.($ini_extension)$/
243        }, "..";
[18141]244    find sub {
245        push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/
246        }, "..";
[16769]247
[17396]248
[18141]249    open POTFILES, "POTFILES.in" or die "$PROGRAM:  there's no POTFILES.in!\n";
250
[17187]251    @buf_potfiles = grep /^[^#]/, <POTFILES>;
[19029]252    foreach (@buf_potfiles) {
253        s/^\[.*]\s*//;
254    }
[17396]255                           
256    print "Searching for missing translatable files...\n" if $VERBOSE;
[16769]257
258    ## Check if we should ignore some found files, when
259    ## comparing with POTFILES.in
[17396]260    foreach my $ignore ("POTFILES.skip", "POTFILES.ignore") {
261        if (-s $ignore) {
262            open FILE, $ignore;
263            while (<FILE>) {
264                if (/^[^#]/){
265                    push @buf_potfiles_ignore, $_;
266                }
[16769]267            }
[17396]268            print "Found $ignore: Ignoring files...\n" if $VERBOSE;
269            @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles);
[16769]270        }
271    }
272
[17396]273    foreach my $file (@buf_i18n_plain)
274      {
275        my $in_comment = 0;
276        my $in_macro = 0;
277
[16769]278        open FILE, "<$file";
[17396]279        while (<FILE>)
280          {
281            # Handle continued multi-line comment.
282            if ($in_comment)
283              {
284                next unless s-.*\*/--;
285                $in_comment = 0;
286              }
287
288            # Handle continued macro.
289            if ($in_macro)
290              {
291                $in_macro = 0 unless /\\$/;
292                next;
293              }
294
295            # Handle start of macro (or any preprocessor directive).
296            if (/^\s*\#/)
297              {
298                $in_macro = 1 if /^([^\\]|\\.)*\\$/;
299                next;
300              }
301
302            # Handle comments and quoted text.
303            while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy
304              {
305                my $match = $1;
306                if ($match eq "/*")
307                  {
308                    if (!s-/\*.*?\*/--)
309                      {
310                        s-/\*.*--;
311                        $in_comment = 1;
312                      }
313                  }
314                elsif ($match eq "//")
315                  {
316                    s-//.*--;
317                  }
318                else # ' or "
319                  {
320                    if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-)
321                      {
322                        warn "mismatched quotes at line $. in $file\n";
323                        s-$match.*--;
324                      }
325                  }
326              }
327       
328
329            if (/_\(QUOTEDTEXT/)
330              {
[16769]331                ## Remove the first 3 chars and add newline
332                push @buf_allfiles, unpack("x3 A*", $file) . "\n";
[17396]333                last;
334              }
335          }
336        close FILE;
337      }
338
339    foreach my $file (@buf_i18n_xml) {
340        open FILE, "<$file";
341        while (<FILE>) {
[18141]342            if (/\s_(.*)=\"/ || /translatable=\"yes\"/){
[17396]343                push @buf_allfiles, unpack("x3 A*", $file) . "\n";
[16769]344                last;
345            }
346        }
347    }
348
[17396]349    foreach my $file (@buf_i18n_ini){
[16769]350        open FILE, "<$file";
351        while (<FILE>) {
[17396]352            if (/_(.*)=/){
[16769]353                push @buf_allfiles, unpack("x3 A*", $file) . "\n";
354                last;
355            }
356        }
357    }
358
[18141]359    foreach my $file (@buf_i18n_xml_unmarked){
360        push @buf_allfiles, unpack("x3 A*", $file) . "\n";
361    }
362
363
[16769]364    @buf_allfiles_sorted = sort (@buf_allfiles);
365    @buf_potfiles_sorted = sort (@buf_potfiles);
366
367    my %in2;
368    foreach (@buf_potfiles_sorted) {
369        $in2{$_} = 1;
370    }
371
372    my @result;
373
374    foreach (@buf_allfiles_sorted){
375        if (!exists($in2{$_})){
376            push @result, $_
377        }
378    }
379
380    ## Save file with information about the files missing
[17396]381    ## if any, and give information about this procedure.
382    if (@result) {
383        print "\n" if $VERBOSE;
[16769]384        open OUT, ">missing";
385        print OUT @result;
[17396]386        print "The following files contain translations and are currently not in use. Please\n";
387        print "consider adding these to the POTFILES.in file, located in the po/ directory.\n\n";
388        print @result, "\n";
389        print "If some of these files are left out on purpose then please add them to\n";
390        print "POTFILES.skip instead of POTFILES.in. A file 'missing' containing this list\n";
391        print "of left out files has been written in the current directory.\n";
[16769]392    }
393
[17396]394    ## If there is nothing to complain about, notify the user
395    else {
396        print "\nAll files containing translations are present in POTFILES.in.\n";
[16769]397    }
398}
399
[17396]400sub print_error_invalid_option
[16769]401{
402    ## Handle invalid arguments
403    print "Try `${PROGRAM} --help' for more information.\n";
404    exit 1;
405}
406
[17396]407sub generate_headers
[16769]408{
[17187]409    my $EXTRACT = `which intltool-extract 2>/dev/null`;
410    chomp $EXTRACT;
[16769]411
[17187]412    $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"};
[16769]413
414    ## Generate the .h header files, so we can allow glade and
415    ## xml translation support
[17187]416    if (! -s $EXTRACT)
[16769]417    {
[17187]418        print "\n *** The intltool-extract script wasn't found!"
[17396]419             ."\n *** Without it, intltool-update can not generate files.\n";
[16769]420        exit;
421    }
422    else
423    {
424        open FILE, "<POTFILES.in";
425        while (<FILE>) {
426           chomp;
427
428           ## Find xml files in POTFILES.in and generate the
[17187]429           ## files with help from the extract script
[16769]430
[17396]431           my $gettext_type= &determine_type ($1);
[16769]432
[17396]433           if (/\.($xml_extension|$ini_extension)$/ || /^\[/){
[16769]434               $_ =~ s/^\[[^\[].*]\s*//;
435               my $filename = "../$_";
436
437               if ($VERBOSE){
[17187]438                   system($EXTRACT, "--update", "--type=$gettext_type", $filename);
[16769]439               } else {
[17187]440                   system($EXTRACT, "--update", "--type=$gettext_type", "--quiet", $filename);
[16769]441               }
442           }
443       }
444       close FILE;
445   }
446}
447
[17396]448sub generate_po_template
[16769]449{
450    ## Generate the potfiles from the POTFILES.in file
451
[17396]452    print "Building the $MODULE.pot...\n" if $VERBOSE;
[16769]453
[17396]454    move ("POTFILES.in", "POTFILES.in.old");
[16769]455
456    open INFILE, "<POTFILES.in.old";
457    open OUTFILE, ">POTFILES.in";
458    while (<INFILE>) {
[19029]459        chomp;
460        if (/\.($xml_extension|$ini_extension)$/ || /^\[/) {
461            s/^\[.*]\s*//;
462            print OUTFILE "$_.h\n";
463        } else {
464            print OUTFILE "$_\n";
465        }
[16769]466    }
467    close OUTFILE;
468    close INFILE;
469
[17396]470    system ("xgettext", "--default-domain\=$MODULE",
471                        "--directory\=\.\.",
472                        "--add-comments",
473                        "--keyword\=\_",
474                        "--keyword\=N\_",
475                        "--keyword\=U\_",
476                        "--files-from\=\.\/POTFILES\.in");
[16769]477
[17396]478    move ("POTFILES.in.old", "POTFILES.in");
[16769]479
480    print "Removing generated header (.h) files..." if $VERBOSE;
481
482    open FILE, "<POTFILES.in";
[17396]483
[16769]484    while (<FILE>)
485    {
486        chomp;
[17396]487        unlink "../$_.h" if /\.($xml_extension|$ini_extension)$/;
[16769]488    }
[17396]489
[16769]490    close FILE;
491    print "done\n" if $VERBOSE;
[18141]492
493    if (!-e "$MODULE.po") {
494        print "WARNING: It seems that none of the files in POTFILES.in ".
495              "contain marked strings\n";
496        exit (1);
497    }
498
499    system ("rm", "-f", "$MODULE.pot");
500    move ("$MODULE.po", "$MODULE.pot") or die "$PROGRAM: couldn't move $MODULE.po to $MODULE.pot.\n";
501
502    print "Wrote $MODULE.pot\n" if $VERBOSE;
[16769]503}
504
[17396]505sub update_po_file
[16769]506{
[17396]507    my ($lang) = @_;
[16769]508
[17396]509    print "Merging $lang.po with $MODULE.pot..." if $VERBOSE;
[16769]510
[17396]511    copy ("$lang.po", "$lang.po.old") || die "copy failed: $!";
512
513    # Perform merge, remove backup file and the "messages" trash file
514    # generated by gettext
[19029]515    system ("msgmerge", "-o", "$lang.po", "$lang.po.old", "$MODULE.pot");
[17396]516    unlink "$lang.po.old";
[16769]517    unlink "messages";
518}
519
[17396]520sub print_error_not_existing
[16769]521{
[17396]522    my ($file) = @_;
[16769]523
524    ## Report error if supplied language file is non-existing
[17396]525    print "$PROGRAM: $file does not exist!\n";
526    print "Try '$PROGRAM --help' for more information.\n";
[16769]527    exit;
528}
529
530sub gather_po_files
531{
[17396]532    my @po_files = glob ("./*.po");
[16769]533
534    @languages = map (&po_file2lang, @po_files);
535
536    foreach my $lang (@languages) {
537        $po_files_by_lang{$lang} = shift (@po_files);
538    }
539}
540
[17396]541sub po_file2lang ($)
[16769]542{
543    my $tmp = $_;
544    $tmp =~ s/^.*\/(.*)\.po$/$1/;
545    return $tmp;
546}
547
[17396]548sub print_status
[16769]549{
[17396]550    my ($lang) = @_;
551
552    system ("msgfmt", "--statistics", "$lang.po");
[16769]553    print "\n";
554}
555
[17396]556sub print_report
[16769]557{
[17396]558    &generate_headers;
559    &generate_po_template;
[16769]560    &gather_po_files;
561
[17396]562    foreach my $lang (@languages) {
[16769]563        print "$lang: ";
[17396]564        &update_po_file ($lang);
[16769]565    }
566
[17396]567    print "\n\n * Current translation support in $MODULE \n\n";
[16769]568
569    foreach my $lang (@languages){
570        print "$lang: ";
[17396]571        system ("msgfmt", "--statistics", "$lang.po");
[16769]572    }
573}
574
575sub find_package_name
576{
577    my $base_dirname = getcwd();
578    $base_dirname =~ s@.*/@@;
579
580    my ($conf_in, $src_dir);
581
[17396]582    if ($base_dirname =~ /^po(-.+)?$/) {
[16769]583        if (-f "../configure.in") {
584            $conf_in = "../configure.in";
[18141]585        } elsif (-f "../configure.ac") {
586            $conf_in = "../configure.ac";
[16769]587        } else {
588            my $makefile_source;
589            local (*IN);
[17396]590            open IN, "<Makefile" || die "can't open Makefile: $!";
[16769]591
592            while (<IN>) {
593                if (/^top_srcdir[ \t]*=/) {
594                    $src_dir = $_;
595                    # print "${src_dir}\n";
596
597                    $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/;
598                    # print "${src_dir}\n";
599                    chomp $src_dir;
600                    $conf_in = "$src_dir" . "/configure.in" . "\n";
601                    last;
602                }
603            }
604            $conf_in || die "Cannot find top_srcdir in Makefile."
605        }
606
[18141]607        my %varhash = ();
[16769]608        my $conf_source; {
609           local (*IN);
[18141]610           open (IN, "<$conf_in") || die "can't open $conf_in: $!";
611           while (<IN>) {
612              if (/^(\w+)=(\S+)/) { $varhash{$1} = $2 };
613           }
614           seek (IN, 0, 0);
[16769]615           local $/; # slurp mode
616           $conf_source = <IN>;
617        }
618
[17187]619        my $name = "";
[18141]620        $name = $1 if $conf_source =~ /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m;
621        if ($conf_source =~ /^AC_INIT\([\s\[]*([^,\)\s\]]+)\]?\s*,/m) {
622            $name = $1;
623            $varhash{"AC_PACKAGE_NAME"} = $1;
624        }
625        $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\s\]]+)/m;
626
627        $name = "\$AC_PACKAGE_NAME" if "$name" eq "AC_PACKAGE_NAME";
628
629        my $oldname = "";
630        while (($name =~ /[\$](\S+)/) && ("$oldname" ne "$name")) {
631            $oldname = $name;
632            if (exists $varhash{$1}) {
633                $name =~ s/[\$](\S+)/$varhash{$1}/;
634            }
635        }
[17187]636        return $name if $name;
[16769]637    }
638
639    print "$PROGRAM: Unable to determine package name.\n" .
640          "Make sure to run this script inside the po directory.\n";
641    exit;
642}
Note: See TracBrowser for help on using the repository browser.