source: trunk/third/gcalctool/intltool-update.in @ 21030

Revision 21030, 23.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21029, which included commits to RCS files with non-trunk default branches.
RevLine 
[21029]1#!@INTLTOOL_PERL@ -w
2
3#
4#  The Intltool Message Updater
5#
6#  Copyright (C) 2000-2003 Free Software Foundation.
7#
8#  Intltool is free software; you can redistribute it and/or
9#  modify it under the terms of the GNU General Public License
10#  version 2 published by the Free Software Foundation.
11#
12#  Intltool 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 program; if not, write to the Free Software
19#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20#
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#
26#  Authors: Kenneth Christiansen <kenneth@gnu.org>
27#           Maciej Stachowiak
28#           Darin Adler <darin@bentspoon.com>
29
30## Release information
31my $PROGRAM = "intltool-update";
32my $VERSION = "0.30";
33my $PACKAGE = "intltool";
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
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;
51my $GETTEXT_PACKAGE = "";
52my $OUTPUT_FILE    = "";
53
54my @languages;
55my %varhash = ();
56my %po_files_by_lang = ();
57
58# Regular expressions to categorize file types.
59# FIXME: Please check if the following is correct
60
61my $xml_support =
62"xml(?:\\.in)*|".       # http://www.w3.org/XML/ (Note: .in is not required)
63"ui|".                  # Bonobo specific - User Interface desc. files
64"lang|".                # ?
65"glade2?(?:\\.in)*|".   # Glade specific - User Interface desc. files (Note: .in is not required)
66"scm(?:\\.in)*|".       # ? (Note: .in is not required)
67"oaf(?:\\.in)+|".       # DEPRECATED: Replaces by Bonobo .server files
68"etspec|".              # ?
69"server(?:\\.in)+|".    # Bonobo specific
70"sheet(?:\\.in)+|".     # ?
71"schemas(?:\\.in)+|".   # GConf specific
72"pong(?:\\.in)+|".      # DEPRECATED: PONG is not used [by GNOME] any longer.
73"kbd(?:\\.in)+";        # GOK specific.
74
75my $ini_support =
76"desktop(?:\\.in)+|".   # http://www.freedesktop.org/Standards/menu-spec
77"caves(?:\\.in)+|".     # GNOME Games specific
78"directory(?:\\.in)+|". # http://www.freedesktop.org/Standards/menu-spec
79"soundlist(?:\\.in)+|". # GNOME specific
80"keys(?:\\.in)+|".      # GNOME Mime database specific
81"theme(?:\\.in)+";      # http://www.freedesktop.org/Standards/icon-theme-spec
82
83my $buildin_gettext_support =
84"c|y|cc|cpp|c\\+\\+|h|hh|gob|py";
85
86## Always flush buffer when printing
87$| = 1;
88
89## Sometimes the source tree will be rooted somewhere else.
90my $SRCDIR = ".";
91my $POTFILES_in;
92
93$SRCDIR = $ENV{"srcdir"} if $ENV{"srcdir"};
94$POTFILES_in = "<$SRCDIR/POTFILES.in";
95
96## Handle options
97GetOptions
98(
99 "help"                => \$HELP_ARG,
100 "version"             => \$VERSION_ARG,
101 "dist|d"              => \$DIST_ARG,
102 "pot|p"               => \$POT_ARG,
103 "headers|s"           => \$HEADERS_ARG,
104 "maintain|m"          => \$MAINTAIN_ARG,
105 "report|r"            => \$REPORT_ARG,
106 "verbose|x"           => \$VERBOSE,
107 "gettext-package|g=s" => \$GETTEXT_PACKAGE,
108 "output-file|o=s"     => \$OUTPUT_FILE,
109 ) or &Console_WriteError_InvalidOption;
110
111&Console_Write_IntltoolHelp if $HELP_ARG;
112&Console_Write_IntltoolVersion if $VERSION_ARG;
113
114my $arg_count = ($DIST_ARG > 0)
115    + ($POT_ARG > 0)
116    + ($HEADERS_ARG > 0)
117    + ($MAINTAIN_ARG > 0)
118    + ($REPORT_ARG > 0);
119
120&Console_Write_IntltoolHelp if $arg_count > 1;
121
122# --version and --help don't require a module name
123my $MODULE = $GETTEXT_PACKAGE || &FindPackageName;
124
125if ($POT_ARG)
126{
127    &GenerateHeaders;
128    &GeneratePOTemplate;
129}
130elsif ($HEADERS_ARG)
131{
132    &GenerateHeaders;
133}
134elsif ($MAINTAIN_ARG)
135{
136    &FindLeftoutFiles;
137}
138elsif ($REPORT_ARG)
139{
140    &GenerateHeaders;
141    &GeneratePOTemplate;
142    &Console_Write_CoverageReport;
143}
144elsif ((defined $ARGV[0]) && $ARGV[0] =~ /^[a-z]/)
145{
146    my $lang = $ARGV[0];
147
148    ## Report error if the language file supplied
149    ## to the command line is non-existent
150    &Console_WriteError_NotExisting("$lang.po") if ! -s "$lang.po";
151
152    if (!$DIST_ARG)
153    {
154        print "Working, please wait..." if $VERBOSE;
155        &GenerateHeaders;
156        &GeneratePOTemplate;
157    }
158    &POFile_Update ($lang, $OUTPUT_FILE);
159    &Console_Write_TranslationStatus ($lang, $OUTPUT_FILE);
160}
161else
162{
163    &Console_Write_IntltoolHelp;
164}
165
166exit;
167
168#########
169
170sub Console_Write_IntltoolVersion
171{
172    print <<_EOF_;
173${PROGRAM} (${PACKAGE}) $VERSION
174Written by Kenneth Christiansen, Maciej Stachowiak, and Darin Adler.
175
176Copyright (C) 2000-2003 Free Software Foundation, Inc.
177This is free software; see the source for copying conditions.  There is NO
178warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
179_EOF_
180    exit;
181}
182
183sub Console_Write_IntltoolHelp
184{
185    print <<_EOF_;
186Usage: ${PROGRAM} [OPTION]... LANGCODE
187Updates PO template files and merge them with the translations.
188
189Mode of operation (only one is allowed):
190  -p, --pot                   generate the PO template only
191  -s, --headers               generate the header files in POTFILES.in
192  -m, --maintain              search for left out files from POTFILES.in
193  -r, --report                display a status report for the module
194  -d, --dist                  merge LANGCODE.po with existing PO template
195
196Extra options:
197  -g, --gettext-package=NAME  override PO template name, useful with --pot
198  -o, --output-file=FILE      write merged translation to FILE
199  -x, --verbose               display lots of feedback
200      --help                  display this help and exit
201      --version               output version information and exit
202
203Examples of use:
204${PROGRAM} --pot    just create a new PO template
205${PROGRAM} xy       create new PO template and merge xy.po with it
206
207Report bugs to http://bugzilla.gnome.org/ (product name "$PACKAGE")
208or send email to <xml-i18n-tools\@gnome.org>.
209_EOF_
210    exit;
211}
212
213sub POFile_DetermineType ($)
214{
215   my $type = $_;
216   my $gettext_type;
217
218   my $xml_regex     = "(?:" . $xml_support . ")";
219   my $ini_regex     = "(?:" . $ini_support . ")";
220   my $buildin_regex = "(?:" . $buildin_gettext_support . ")";
221
222   if ($type =~ /\[type: gettext\/([^\]].*)]/)
223   {
224        $gettext_type=$1;
225   }
226   elsif ($type =~ /schemas(\.in)+$/)
227   {
228        $gettext_type="schemas";
229   }
230   elsif ($type =~ /glade2?(\.in)*$/)
231   {
232       $gettext_type="glade";
233   }
234   elsif ($type =~ /scm(\.in)*$/)
235   {
236       $gettext_type="scheme";
237   }
238   elsif ($type =~ /keys(\.in)+$/)
239   {
240       $gettext_type="keys";
241   }
242
243   # bucket types
244
245   elsif ($type =~ /$xml_regex$/)
246   {
247       $gettext_type="xml";
248   }
249   elsif ($type =~ /$ini_regex$/)
250   {
251       $gettext_type="ini";
252   }
253   elsif ($type =~ /$buildin_regex$/)
254   {
255       $gettext_type="buildin";
256   }
257   else
258   {
259       $gettext_type="unknown";
260   }
261
262   return "gettext\/$gettext_type";
263}
264
265sub TextFile_DetermineEncoding ($)
266{
267    my $gettext_code="ASCII"; # All files are ASCII by default
268    my $filetype=`file $_ | cut -d ' ' -f 2`;
269
270    if ($? eq "0")
271    {
272        if ($filetype =~ /^(ISO|UTF)/)
273        {
274            chomp ($gettext_code = $filetype);
275        }
276        elsif ($filetype =~ /^XML/)
277        {
278            $gettext_code="UTF-8"; # We asume that .glade and other .xml files are UTF-8
279        }
280    }
281
282    return $gettext_code;
283}
284
285
286sub FindLeftoutFiles
287{
288    my (@buf_i18n_plain,
289        @buf_i18n_xml,
290        @buf_i18n_xml_unmarked,
291        @buf_i18n_ini,
292        @buf_potfiles,
293        @buf_potfiles_ignore,
294        @buf_allfiles,
295        @buf_allfiles_sorted,
296        @buf_potfiles_sorted
297    );
298
299    ## Search and find all translatable files
300    find sub {
301        push @buf_i18n_plain,        "$File::Find::name" if /\.($buildin_gettext_support)$/;
302        push @buf_i18n_xml,          "$File::Find::name" if /\.($xml_support)$/;
303        push @buf_i18n_ini,          "$File::Find::name" if /\.($ini_support)$/;
304        push @buf_i18n_xml_unmarked, "$File::Find::name" if /\.(schemas(\.in)+)$/;
305        }, "..";
306
307
308    open POTFILES, $POTFILES_in or die "$PROGRAM:  there's no POTFILES.in!\n";
309    @buf_potfiles = grep !/^(#|\s*$)/, <POTFILES>;
310    close POTFILES;
311
312    foreach (@buf_potfiles) {
313        s/^\[.*]\s*//;
314    }
315
316    print "Searching for missing translatable files...\n" if $VERBOSE;
317
318    ## Check if we should ignore some found files, when
319    ## comparing with POTFILES.in
320    foreach my $ignore ("POTFILES.skip", "POTFILES.ignore")
321    {
322        (-s $ignore) or next;
323
324        if ("$ignore" eq "POTFILES.ignore")
325        {
326            print "The usage of POTFILES.ignore is deprecated. Please consider moving the\n".
327                  "content of this file to POTFILES.skip.\n";
328        }
329
330        print "Found $ignore: Ignoring files...\n" if $VERBOSE;
331        open FILE, "<$ignore" or die "ERROR: Failed to open $ignore!\n";
332           
333        while (<FILE>)
334        {
335            push @buf_potfiles_ignore, $_ unless /^(#|\s*$)/;
336        }
337        close FILE;
338
339        @buf_potfiles = (@buf_potfiles_ignore, @buf_potfiles);
340    }
341
342    foreach my $file (@buf_i18n_plain)
343    {
344        my $in_comment = 0;
345        my $in_macro = 0;
346
347        open FILE, "<$file";
348        while (<FILE>)
349        {
350            # Handle continued multi-line comment.
351            if ($in_comment)
352            {
353                next unless s-.*\*/--;
354                $in_comment = 0;
355            }
356
357            # Handle continued macro.
358            if ($in_macro)
359            {
360                $in_macro = 0 unless /\\$/;
361                next;
362            }
363
364            # Handle start of macro (or any preprocessor directive).
365            if (/^\s*\#/)
366            {
367                $in_macro = 1 if /^([^\\]|\\.)*\\$/;
368                next;
369            }
370
371            # Handle comments and quoted text.
372            while (m-(/\*|//|\'|\")-) # \' and \" keep emacs perl mode happy
373            {
374                my $match = $1;
375                if ($match eq "/*")
376                {
377                    if (!s-/\*.*?\*/--)
378                    {
379                        s-/\*.*--;
380                        $in_comment = 1;
381                    }
382                }
383                elsif ($match eq "//")
384                {
385                    s-//.*--;
386                }
387                else # ' or "
388                {
389                    if (!s-$match([^\\]|\\.)*?$match-QUOTEDTEXT-)
390                    {
391                        warn "mismatched quotes at line $. in $file\n";
392                        s-$match.*--;
393                    }
394                }
395            }       
396
397            if (/_\(QUOTEDTEXT/)
398            {
399                ## Remove the first 3 chars and add newline
400                push @buf_allfiles, unpack("x3 A*", $file) . "\n";
401                last;
402            }
403        }
404        close FILE;
405    }
406
407    foreach my $file (@buf_i18n_xml)
408    {
409        open FILE, "<$file";
410       
411        while (<FILE>)
412        {
413            # FIXME: share the pattern matching code with intltool-extract
414            if (/\s_(.*)=\"/ || /<_[^>]+>/ || /translatable=\"yes\"/)
415            {
416                push @buf_allfiles, unpack("x3 A*", $file) . "\n";
417                last;
418            }
419        }
420        close FILE;
421    }
422
423    foreach my $file (@buf_i18n_ini)
424    {
425        open FILE, "<$file";
426        while (<FILE>)
427        {
428            if (/_(.*)=/)
429            {
430                push @buf_allfiles, unpack("x3 A*", $file) . "\n";
431                last;
432            }
433        }
434        close FILE;
435    }
436
437    foreach my $file (@buf_i18n_xml_unmarked)
438    {
439        push @buf_allfiles, unpack("x3 A*", $file) . "\n";
440    }
441
442
443    @buf_allfiles_sorted = sort (@buf_allfiles);
444    @buf_potfiles_sorted = sort (@buf_potfiles);
445
446    my %in2;
447    foreach (@buf_potfiles_sorted)
448    {
449        $in2{$_} = 1;
450    }
451
452    my @result;
453
454    foreach (@buf_allfiles_sorted)
455    {
456        if (!exists($in2{$_}))
457        {
458            push @result, $_
459        }
460    }
461
462    my @buf_potfiles_notexist;
463
464    foreach (@buf_potfiles_sorted)
465    {
466        chomp (my $dummy = $_);
467        if ("$dummy" ne "" and ! -f "../$dummy")
468        {
469            push @buf_potfiles_notexist, $_;
470        }
471    }
472
473    ## Save file with information about the files missing
474    ## if any, and give information about this procedure.
475    if (@result + @buf_potfiles_notexist > 0)
476    {
477        if (@result)
478        {
479            print "\n" if $VERBOSE;
480            unlink "missing";
481            open OUT, ">missing";
482            print OUT @result;
483            close OUT;
484            warn "\e[1mThe following files contain translations and are currently not in use. Please\e[0m\n".
485                 "\e[1mconsider adding these to the POTFILES.in file, located in the po/ directory.\e[0m\n\n";
486            print STDERR @result, "\n";
487            warn "If some of these files are left out on purpose then please add them to\n".
488                 "POTFILES.skip instead of POTFILES.in. A file \e[1m'missing'\e[0m containing this list\n".
489                 "of left out files has been written in the current directory.\n";
490        }
491        if (@buf_potfiles_notexist)
492        {
493            unlink "notexist";
494            open OUT, ">notexist";
495            print OUT @buf_potfiles_notexist;
496            close OUT;
497            warn "\n" if ($VERBOSE or @result);
498            warn "\e[1mThe following files do not exist anymore:\e[0m\n\n";
499            warn @buf_potfiles_notexist, "\n";
500            warn "Please remove them from POTFILES.in or POTFILES.skip. A file \e[1m'notexist'\e[0m\n".
501                 "containing this list of absent files has been written in the current directory.\n";
502        }
503    }
504
505    ## If there is nothing to complain about, notify the user
506    else {
507        print "\nAll files containing translations are present in POTFILES.in.\n" if $VERBOSE;
508    }
509}
510
511sub Console_WriteError_InvalidOption
512{
513    ## Handle invalid arguments
514    print STDERR "Try `${PROGRAM} --help' for more information.\n";
515    exit 1;
516}
517
518sub GenerateHeaders
519{
520    my $EXTRACT = `which intltool-extract 2>/dev/null`;
521    chomp $EXTRACT;
522
523    $EXTRACT = $ENV{"INTLTOOL_EXTRACT"} if $ENV{"INTLTOOL_EXTRACT"};
524
525    ## Generate the .h header files, so we can allow glade and
526    ## xml translation support
527    if (! -x "$EXTRACT")
528    {
529        print STDERR "\n *** The intltool-extract script wasn't found!"
530             ."\n *** Without it, intltool-update can not generate files.\n";
531        exit;
532    }
533    else
534    {
535        open (FILE, $POTFILES_in) or die "$PROGRAM: POTFILES.in not found.\n";
536       
537        while (<FILE>)
538        {
539           chomp;
540           next if /^\[\s*encoding/;
541
542           ## Find xml files in POTFILES.in and generate the
543           ## files with help from the extract script
544
545           my $gettext_type= &POFile_DetermineType ($1);
546
547           if (/\.($xml_support|$ini_support)$/ || /^\[/)
548           {
549               s/^\[[^\[].*]\s*//;
550
551               my $filename = "../$_";
552
553               if ($VERBOSE)
554               {
555                   system ($EXTRACT, "--update", "--srcdir=$SRCDIR",
556                           "--type=$gettext_type", $filename);
557               }
558               else
559               {
560                   system ($EXTRACT, "--update", "--type=$gettext_type",
561                           "--srcdir=$SRCDIR", "--quiet", $filename);
562               }
563           }
564       }
565       close FILE;
566   }
567}
568
569#
570# Generate .pot file from POTFILES.in
571#
572sub GeneratePOTemplate
573{
574    my $XGETTEXT = `which xgettext 2>/dev/null`;
575    my $XGETTEXT_ARGS = '';
576    chomp $XGETTEXT;
577
578    $XGETTEXT = $ENV{"XGETTEXT"} if $ENV{"XGETTEXT"};
579    $XGETTEXT_ARGS = $ENV{"XGETTEXT_ARGS"} if $ENV{"XGETTEXT_ARGS"};
580
581    if (! -x $XGETTEXT)
582    {
583        print STDERR " *** xgettext is not found on this system!\n".
584                     " *** Without it, intltool-update can not extract strings.\n";
585        exit;
586    }
587
588    print "Building $MODULE.pot...\n" if $VERBOSE;
589
590    open INFILE, $POTFILES_in;
591    unlink "POTFILES.in.temp";
592    open OUTFILE, ">POTFILES.in.temp";
593
594    my $gettext_support_nonascii = 0;
595
596    # checks for GNU gettext >= 0.12
597    my $dummy = `$XGETTEXT --version --from-code=UTF-8 >/dev/null 2>/dev/null`;
598    if ($? == 0)
599    {
600        $gettext_support_nonascii = 1;
601    }
602    else
603    {
604        # urge everybody to upgrade gettext
605        print STDERR "WARNING: This version of gettext does not support extracting non-ASCII\n".
606                     "         strings. That means you should install a version of gettext\n".
607                     "         that supports non-ASCII strings (such as GNU gettext >= 0.12),\n".
608                     "         or have to let non-ASCII strings untranslated. (If there is any)\n";
609    }
610
611    my $encoding = "ASCII";
612    my $forced_gettext_code;
613    my @temp_headers;
614    my $encoding_problem_is_reported = 0;
615
616    while (<INFILE>)
617    {
618        next if (/^#/ or /^\s*$/);
619
620        chomp;
621
622        my $gettext_code;
623
624        if (/^\[\s*encoding:\s*(.*)\s*\]/)
625        {
626            $forced_gettext_code=$1;
627        }
628        elsif (/\.($xml_support|$ini_support)$/ || /^\[/)
629        {
630            s/^\[.*]\s*//;
631            print OUTFILE "$_.h\n";
632            push @temp_headers, "../$_.h";
633            $gettext_code = &TextFile_DetermineEncoding ("../$_.h") if ($gettext_support_nonascii and not defined $forced_gettext_code);
634        }
635        else
636        {
637            if ($SRCDIR eq ".") {
638                print OUTFILE "$_\n";
639            } else {
640                print OUTFILE "$SRCDIR/../$_\n";
641            }
642            $gettext_code = &TextFile_DetermineEncoding ("../$_") if ($gettext_support_nonascii and not defined $forced_gettext_code);
643        }
644
645        next if (! $gettext_support_nonascii);
646
647        if (defined $forced_gettext_code)
648        {
649            $encoding=$forced_gettext_code;
650        }
651        elsif (defined $gettext_code and "$encoding" ne "$gettext_code")
652        {
653            if ($encoding eq "ASCII")
654            {
655                $encoding=$gettext_code;
656            }
657            elsif ($gettext_code ne "ASCII")
658            {
659                # Only report once because the message is quite long
660                if (! $encoding_problem_is_reported)
661                {
662                    print STDERR "WARNING: You should use the same file encoding for all your project files,\n".
663                                 "         but $PROGRAM thinks that most of the source files are in\n".
664                                 "         $encoding encoding, while \"$_\" is (likely) in\n".
665                                 "         $gettext_code encoding. If you are sure that all translatable strings\n".
666                                 "         are in same encoding (say UTF-8), please \e[1m*prepend*\e[0m the following\n".
667                                 "         line to POTFILES.in:\n\n".
668                                 "                 [encoding: UTF-8]\n\n".
669                                 "         and make sure that configure.in/ac checks for $PACKAGE >= 0.27 .\n".
670                                 "(such warning message will only be reported once.)\n";
671                    $encoding_problem_is_reported = 1;
672                }
673            }
674        }
675    }
676
677    close OUTFILE;
678    close INFILE;
679
680    unlink "$MODULE.pot";
681    my @xgettext_argument=("$XGETTEXT",
682                           "--add-comments",
683                           "--directory\=\.\.",
684                           "--output\=$MODULE\.pot",
685                           "--files-from\=\.\/POTFILES\.in\.temp");
686    my $XGETTEXT_KEYWORDS = &FindPOTKeywords;
687    push @xgettext_argument, $XGETTEXT_KEYWORDS;
688    push @xgettext_argument, "--from-code\=$encoding" if ($gettext_support_nonascii);
689    push @xgettext_argument, $XGETTEXT_ARGS if $XGETTEXT_ARGS;
690    my $xgettext_command = join ' ', @xgettext_argument;
691
692    # intercept xgettext error message
693    print "Running $xgettext_command\n" if $VERBOSE;
694    my $xgettext_error_msg = `$xgettext_command 2>\&1`;
695    my $command_failed = $?;
696
697    unlink "POTFILES.in.temp";
698
699    print "Removing generated header (.h) files..." if $VERBOSE;
700    unlink foreach (@temp_headers);
701    print "done.\n" if $VERBOSE;
702
703    if (! $command_failed)
704    {
705        if (! -e "$MODULE.pot")
706        {
707            print "None of the files in POTFILES.in contain strings marked for translation.\n" if $VERBOSE;
708        }
709        else
710        {
711            print "Wrote $MODULE.pot\n" if $VERBOSE;
712        }
713    }
714    else
715    {
716        if ($xgettext_error_msg =~ /--from-code/)
717        {
718            # replace non-ASCII error message with a more useful one.
719            print STDERR "ERROR: xgettext failed to generate PO template file because there is non-ASCII\n".
720                         "       string marked for translation. Please make sure that all strings marked\n".
721                         "       for translation are in uniform encoding (say UTF-8), then \e[1m*prepend*\e[0m the\n".
722                         "       following line to POTFILES.in and rerun $PROGRAM:\n\n".
723                         "           [encoding: UTF-8]\n\n";
724        }
725        else
726        {
727            print STDERR "$xgettext_error_msg";
728            if (-e "$MODULE.pot")
729            {
730                # is this possible?
731                print STDERR "ERROR: xgettext failed but still managed to generate PO template file.\n".
732                             "       Please consult error message above if there is any.\n";
733            }
734            else
735            {
736                print STDERR "ERROR: xgettext failed to generate PO template file. Please consult\n".
737                             "       error message above if there is any.\n";
738            }
739        }
740        exit (1);
741    }
742}
743
744sub POFile_Update
745{
746    -f "$MODULE.pot" or die "$PROGRAM: $MODULE.pot does not exist.\n";
747
748    my ($lang, $outfile) = @_;
749
750    print "Merging $lang.po with $MODULE.pot..." if $VERBOSE;
751
752    my $infile = "$lang.po";
753    $outfile = "$lang.po" if ($outfile eq "");
754
755    # I think msgmerge won't overwrite old file if merge is not successful
756    system ("msgmerge", "-o", $outfile, $infile, "$MODULE.pot");
757}
758
759sub Console_WriteError_NotExisting
760{
761    my ($file) = @_;
762
763    ## Report error if supplied language file is non-existing
764    print STDERR "$PROGRAM: $file does not exist!\n";
765    print STDERR "Try '$PROGRAM --help' for more information.\n";
766    exit;
767}
768
769sub GatherPOFiles
770{
771    my @po_files = glob ("./*.po");
772
773    @languages = map (&GetLanguageFromPOFile, @po_files);
774
775    foreach my $lang (@languages)
776    {
777        $po_files_by_lang{$lang} = shift (@po_files);
778    }
779}
780
781sub POFile_GetLanguage ($)
782{
783    s/^(.*\/)?(.+)\.po$/$2/;
784    return $_;
785}
786
787sub Console_Write_TranslationStatus
788{
789    my ($lang, $output_file) = @_;
790
791    $output_file = "$lang.po" if ($output_file eq "");
792
793    system ("msgfmt", "-o", "/dev/null", "--statistics", $output_file);
794}
795
796sub Console_Write_CoverageReport
797{
798    &GatherPOFiles;
799
800    foreach my $lang (@languages)
801    {
802        print "$lang: ";
803        &POFile_Update ($lang, "");
804    }
805
806    print "\n\n * Current translation support in $MODULE \n\n";
807
808    foreach my $lang (@languages)
809    {
810        print "$lang: ";
811        system ("msgfmt", "-o", "/dev/null", "--statistics", "$lang.po");
812    }
813}
814
815sub SubstituteVariable
816{
817    my ($str) = @_;
818   
819    # always need to rewind file whenever it has been accessed
820    seek (CONF, 0, 0);
821
822    # cache each variable. varhash is global to we can add
823    # variables elsewhere.
824    while (<CONF>)
825    {
826        if (/^(\w+)=(\S+)/)
827        {
828            $varhash{$1} = $2;
829        }
830    }
831   
832    if ($str =~ /^(.*)\${?([A-Z_]+)}?(.*)$/)
833    {
834        my $rest = $3;
835        my $untouched = $1;
836        my $sub = $varhash{$2};
837       
838        return SubstituteVariable ("$untouched$sub$rest");
839    }
840    return $str;
841}
842
843sub CONF_Handle_Open
844{
845    my $base_dirname = getcwd();
846    $base_dirname =~ s@.*/@@;
847
848    my ($conf_in, $src_dir);
849
850    if ($base_dirname =~ /^po(-.+)?$/)
851    {
852        if (-f "../configure.ac")
853        {
854            $conf_in = "../configure.ac";
855        }
856        elsif (-f "../configure.in")
857        {
858            $conf_in = "../configure.in";
859        }
860        else
861        {
862            my $makefile_source;
863
864            local (*IN);
865            open IN, "<Makefile" || die "can't open Makefile: $!";
866
867            while (<IN>)
868            {
869                if (/^top_srcdir[ \t]*=/)
870                {
871                    $src_dir = $_;                 
872                    $src_dir =~ s/^top_srcdir[ \t]*=[ \t]*([^ \t\n\r]*)/$1/;
873
874                    chomp $src_dir;
875                    $conf_in = "$src_dir" . "/configure.in" . "\n";
876
877                    last;
878                }
879            }
880            close IN;
881
882            $conf_in || die "Cannot find top_srcdir in Makefile.";
883        }
884
885        open (CONF, "<$conf_in") || die "can't open $conf_in: $!";
886    }
887    else
888    {
889        print STDERR "$PROGRAM: Unable to proceed.\n" .
890                     "Make sure to run this script inside the po directory.\n";
891        exit;
892    }
893}
894
895sub FindPackageName
896{
897    &CONF_Handle_Open;
898
899    my $conf_source; {
900        local (*IN);
901        open (IN, "<&CONF") || die "can't open configure.in/configure.ac: $!";
902        seek (IN, 0, 0);
903        local $/; # slurp mode
904        $conf_source = <IN>;
905        close IN;
906    }
907
908    my $name = "untitled";
909    my $version;
910
911    # priority for getting package name:
912    # 1. GETTEXT_PACKAGE
913    # 2. first argument of AC_INIT (with >= 2 arguments)
914    # 3. first argument of AM_INIT_AUTOMAKE (with >= 2 argument)
915
916    # /^AM_INIT_AUTOMAKE\([\s\[]*([^,\)\s\]]+)/m
917    # the \s makes this not work, why?
918    if ($conf_source =~ /^AM_INIT_AUTOMAKE\(([^,\)]+),([^,\)]+)/m)
919    {
920        ($name, $version) = ($1, $2);
921        $name =~ s/[\[\]\s]//g;
922        ($varhash{"AC_PACKAGE_VERSION"} = $version) =~ s/[\[\]\s]//g;
923    }
924   
925    if ($conf_source =~ /^AC_INIT\(([^,\)]+),([^,\)]+)/m)
926    {
927        ($name, $version) = ($1, $2);
928        $name=~ s/[\[\]\s]//g;
929        $varhash{"AC_PACKAGE_NAME"} = $name;
930        ($varhash{"AC_PACKAGE_VERSION"} = $version) =~ s/[\[\]\s]//g;
931    }
932
933    # \s makes this not work, why?
934    $name = $1 if $conf_source =~ /^GETTEXT_PACKAGE=\[?([^\n\]]+)/m;
935   
936    # prepend '$' to auto* internal variables, usually they are
937    # used in configure.in/ac without the '$'
938    $name =~ s/AC_/\$AC_/g;
939    $name =~ s/\$\$/\$/g;
940   
941    $name = SubstituteVariable ($name);
942
943    return $name if $name;
944}
945
946
947sub FindPOTKeywords
948{
949
950    my $keywords = "--keyword\=\_ --keyword\=N\_ --keyword\=U\_";
951    my $make_source; {
952        local (*IN);
953        open (IN, "<Makefile.in.in") || return $keywords;
954        seek (IN, 0, 0);
955        local $/; # slurp mode
956        $make_source = <IN>;
957        close IN;
958    }
959
960    # \s makes this not work, why?
961    $keywords = $1 if $make_source =~ /^XGETTEXT_KEYWORDS[ ]*=\[?([^\n\]]+)/m;
962   
963    return $keywords;
964}
Note: See TracBrowser for help on using the repository browser.