5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
8 # author: Michael Gerz, michael.gerz@teststep.org
16 pocheck.pl [-acmpqst] po_file [po_file] ...
18 This script performs some consistency checks on po files.
20 We check for everything listed here, unless one or more of these
21 options is given, in which case we checks only for those requested.
22 -a: Check arguments, like %1\$s
23 -c: Check for colons at end
24 -m: Check for menu shortcuts
25 -p: Check for period at end
26 -q: Check Qt shortcuts
27 -s: Check for space at end
28 -t: Check for uniform translation
29 This option can be given with or without other options.
30 -w: Only report summary total of errors
34 getopts(":hacmpqstw", \%options);
36 if (defined($options{h})) {
41 my $only_total = defined($options{w});
42 delete $options{w} if $only_total;
44 my $check_args = (!%options or defined($options{a}));
45 my $check_colons = (!%options or defined($options{c}));
46 my $check_spaces = (!%options or defined($options{m}));
47 my $check_periods = (!%options or defined($options{p}));
48 my $check_qt = (!%options or defined($options{q}));
49 my $check_menu = (!%options or defined($options{s}));
50 my $check_trans = (!%options or defined($options{t}));
54 foreach my $pofilename ( @ARGV ) {
56 print "Processing po file '$pofilename'...\n";
58 open( INPUT, "<$pofilename" )
59 || die "Cannot read po file '$pofilename'";
64 keys( %trans ) = 10000;
66 my $noOfLines = $#pofile;
71 my ($msgid, $msgstr, $more);
73 while ($i <= $noOfLines) {
75 ( $msgid ) = ( $pofile[$i] =~ m/^msgid "(.*)"/ );
79 # some msgid's are more than one line long, so add those.
80 while ( ( $more ) = $pofile[$i] =~ m/^"(.*)"/ ) {
81 $msgid = $msgid . $more;
85 # now look for the associated msgstr.
86 until ( ( $msgstr ) = ( $pofile[$i] =~ m/^msgstr "(.*)"/ ) ) { $i++; };
88 # again collect any extra lines.
89 while ( ( $i <= $noOfLines ) &&
90 ( ( $more ) = $pofile[$i] =~ m/^"(.*)"/ ) ) {
91 $msgstr = $msgstr . $more;
95 # nothing to do if one of them is empty.
96 # (surely that is always $msgstr?)
97 next if ($msgid eq "" or $msgstr eq "");
99 # Check for matching %1$s, etc.
101 my @argstrs = ( $msgid =~ m/%(\d)\$s/g );
104 foreach my $arg (@argstrs) { $n = $arg if $arg > $n; }
106 print "Line $linenum: Problem finding arguments in:\n $msgid!\n"
108 ++$bad{"Missing arguments"};
111 foreach my $i (1..$n) {
112 my $arg = "%$i\\\$s";
113 if ( $msgstr !~ m/$arg/ ) {
114 print "Line $linenum: Missing argument `$arg'\n '$msgid' ==> '$msgstr'\n"
116 ++$bad{"Missing arguments"};
125 # Check colon at the end of a message
126 if ( ( $msgid =~ m/: *(\|.*)?$/ ) != ( $msgstr =~ m/: *(\|.*)?$/ ) ) {
127 print "Line $linenum: Missing or unexpected colon:\n '$msgid' => '$msgstr'\n"
129 ++$bad{"Bad colons"};
134 if ($check_periods) {
135 # Check period at the end of a message; uncomment code if you are paranoid
136 if ( ( $msgid =~ m/\. *(\|.*)?$/ ) != ( $msgstr =~ m/\. *(\|.*)?$/ ) ) {
137 print "Line $linenum: Missing or unexpected period:\n '$msgid' => '$msgstr'\n"
139 ++$bad{"Bad periods"};
145 # Check space at the end of a message
146 if ( ( $msgid =~ m/ *?(\|.*)?$/ ) != ( $msgstr =~ m/ *?(\|.*)?$/ ) ) {
147 print "Line $linenum: Missing or unexpected space:\n '$msgid' => '$msgstr'\n"
149 ++$bad{"Bad spaces"};
155 # Check for "&" shortcuts
156 if ( ( $msgid =~ m/&[^ ]/ ) != ( $msgstr =~ m/&[^ ]/ ) ) {
157 print "Line $linenum: Missing or unexpected Qt shortcut:\n '$msgid' => '$msgstr'\n"
159 ++$bad{"Bad Qt shortcuts"};
165 # Check for "|..." shortcuts
166 if ( ( $msgid =~ m/\|[^ ]/ ) != ( $msgstr =~ m/\|[^ ]/ ) ) {
167 print "Line $linenum: Missing or unexpected menu shortcut:\n '$msgid' => '$msgstr'\n"
169 ++$bad{"Bad menu shortcuts"};
174 next unless $check_trans;
176 # we now collect these translations in a hash.
177 # this will allow us to check below if we have translated
178 # anything more than one way.
179 my $msgid_clean = lc($msgid);
180 my $msgstr_clean = lc($msgstr);
182 $msgid_clean =~ s/(.*)\|.*?$/$1/; # strip menu shortcuts
183 $msgstr_clean =~ s/(.*)\|.*?$/$1/;
184 $msgid_clean =~ s/&([^ ])/$1/; # strip Qt shortcuts
185 $msgstr_clean =~ s/&([^ ])/$1/;
187 # this is a hash of hashes. the keys of the outer hash are
188 # cleaned versions of ORIGINAL strings. the keys of the inner hash
189 # are the cleaned versions of their TRANSLATIONS. The value for the
190 # inner hash is an array of the orignal string and translation.
191 $trans{$msgid_clean}{$msgstr_clean} = [ $msgid, $msgstr, $linenum ];
195 foreach $msgid ( keys %trans ) {
196 # so $ref is a reference to the inner hash.
197 my $ref = $trans{$msgid};
198 # @msgstrkeys is an array of the keys of that inner hash.
199 my @msgstrkeys = keys %$ref;
201 # do we have more than one such key?
202 if ( $#msgstrkeys > 0 ) {
204 print "Different translations for '$msgid':\n";
205 foreach $msgstr ( @msgstrkeys ) {
206 print "Line $ref->{$msgstr}[2]: '" .
207 $ref->{$msgstr}[0] . "' => '" .
208 $ref->{$msgstr}[1] . "'\n";
211 ++$bad{"Inconsistent translations"};
218 while (my ($k, $v) = each %bad) { print "$k: $v\n"; }
219 if (scalar(keys %bad) > 1) {
220 print "Total warnings: $warn\n";
223 print "No warnings!\n";