~ubuntu-branches/ubuntu/hardy/gnomad2/hardy

« back to all changes in this revision

Viewing changes to intltool-update.in

  • Committer: Bazaar Package Importer
  • Author(s): Shaun Jackman
  • Date: 2004-10-25 10:24:21 UTC
  • Revision ID: james.westby@ubuntu.com-20041025102421-hnnl6uzlkutcibvi
Tags: upstream-2.5.0
ImportĀ upstreamĀ versionĀ 2.5.0

Show diffs side-by-side

added added

removed removed

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