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. It will check
19 for everything listed under "Options" below, unless options are given, in
20 which case it checks only those requested.
23 -a: Check arguments, like %1\$s
24 -c: Check for colons at end
25 -m: Check for menu shortcuts
26 -p: Check for period at end
27 -q: Check Qt shortcuts
28 -s: Check for space at end
29 -t: Check for uniform translations
33 getopts(":hacmpqst", \%options);
35 if (defined($options{h})) {
40 my $check_args = (!%options or defined($options{a}));
41 my $check_colons = (!%options or defined($options{c}));
42 my $check_spaces = (!%options or defined($options{m}));
43 my $check_periods = (!%options or defined($options{p}));
44 my $check_qt = (!%options or defined($options{q}));
45 my $check_menu = (!%options or defined($options{s}));
46 my $check_trans = (!%options or defined($options{t}));
50 foreach my $pofilename ( @ARGV )
52 print "Processing po file '$pofilename'...\n";
54 open( INPUT, "<$pofilename" )
55 || die "Cannot read po file '$pofilename'";
60 keys( %trans ) = 10000;
62 my $noOfLines = $#pofile;
67 my ($msgid, $msgstr, $more);
69 while ($i <= $noOfLines) {
71 ( $msgid ) = ( $pofile[$i] =~ m/^msgid "(.*)"/ );
75 # some msgid's are more than one line long, so add those.
76 while ( ( $more ) = $pofile[$i] =~ m/^"(.*)"/ ) {
77 $msgid = $msgid . $more;
81 # now look for the associated msgstr.
82 until ( ( $msgstr ) = ( $pofile[$i] =~ m/^msgstr "(.*)"/ ) ) { $i++; };
84 # again collect any extra lines.
85 while ( ( $i <= $noOfLines ) &&
86 ( ( $more ) = $pofile[$i] =~ m/^"(.*)"/ ) ) {
87 $msgstr = $msgstr . $more;
91 # nothing to do if one of them is empty.
92 # (surely that is always $msgstr?)
93 next if ($msgid eq "" or $msgstr eq "");
95 # Check for matching %1$s, etc.
97 my @argstrs = ( $msgid =~ m/%(\d)\$s/g );
100 foreach my $arg (@argstrs) { $n = $arg if $arg > $n; }
102 print "Problem finding arguments in:\n $msgid!\non line $linenum.\n";
105 foreach my $i (1..$n) {
106 my $arg = "%$i\\\$s";
107 if ( $msgstr !~ m/$arg/ ) {
108 print "Line $linenum: Missing argument `$arg'\n '$msgid' ==> '$msgstr'\n";
117 # Check colon at the end of a message
118 if ( ( $msgid =~ m/: *(\|.*)?$/ ) != ( $msgstr =~ m/: *(\|.*)?$/ ) ) {
119 print( "Line $linenum: Missing or unexpected colon:\n" );
120 print( " '$msgid' => '$msgstr'\n" );
125 if ($check_periods) {
126 # Check period at the end of a message; uncomment code if you are paranoid
127 if ( ( $msgid =~ m/\. *(\|.*)?$/ ) != ( $msgstr =~ m/\. *(\|.*)?$/ ) ) {
128 print( "Line $linenum: Missing or unexpected period:\n" );
129 print( " '$msgid' => '$msgstr'\n" );
135 # Check space at the end of a message
136 if ( ( $msgid =~ m/ *?(\|.*)?$/ ) != ( $msgstr =~ m/ *?(\|.*)?$/ ) ) {
137 print( "Line $linenum: Missing or unexpected space:\n" );
138 print( " '$msgid' => '$msgstr'\n" );
144 # Check for "&" shortcuts
145 if ( ( $msgid =~ m/&[^ ]/ ) != ( $msgstr =~ m/&[^ ]/ ) ) {
146 print( "Line $linenum: Missing or unexpected Qt shortcut:\n" );
147 print( " '$msgid' => '$msgstr'\n" );
153 # Check for "|..." shortcuts
154 if ( ( $msgid =~ m/\|[^ ]/ ) != ( $msgstr =~ m/\|[^ ]/ ) ) {
155 print( "Line $linenum: Missing or unexpected menu shortcut:\n" );
156 print( " '$msgid' => '$msgstr'\n" );
161 next unless $check_trans;
163 # we now collect these translations in a hash.
164 # this will allow us to check below if we have translated
165 # anything more than one way.
166 my $msgid_clean = lc($msgid);
167 my $msgstr_clean = lc($msgstr);
169 $msgid_clean =~ s/(.*)\|.*?$/$1/; # strip menu shortcuts
170 $msgstr_clean =~ s/(.*)\|.*?$/$1/;
171 $msgid_clean =~ s/&([^ ])/$1/; # strip Qt shortcuts
172 $msgstr_clean =~ s/&([^ ])/$1/;
174 # this is a hash of hashes. the keys of the outer hash are
175 # cleaned versions of ORIGINAL strings. the keys of the inner hash
176 # are the cleaned versions of their TRANSLATIONS. The value for the
177 # inner hash is an array of the orignal string and translation.
178 $trans{$msgid_clean}{$msgstr_clean} = [ $msgid, $msgstr ];
182 foreach $msgid ( keys %trans ) {
183 # so $ref is a reference to the inner hash.
184 my $ref = $trans{$msgid};
185 # @msgstrkeys is an array of the keys of that inner hash.
186 my @msgstrkeys = keys %$ref;
188 # do we have more than one such key?
189 if ( $#msgstrkeys > 0 ) {
190 print( "Different translations for '$msgid':\n" );
191 foreach $msgstr ( @msgstrkeys ) {
192 print( " '" . $trans{$msgid}{$msgstr}[0] . "' => '" . $trans{$msgid}{$msgstr}[1] . "'\n" );
199 print( "\nTotal number of warnings: $warn\n\n" );