]> git.lyx.org Git - lyx.git/blob - po/diff_po.pl
Colorized output, adapt for use in 'svn diff'
[lyx.git] / po / diff_po.pl
1 #! /usr/bin/env perl
2
3 # file diff_po.pl
4 # script to compare changes between translation files before merging them
5 #
6 # This file is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
10 #
11 # This software is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public
17 # License along with this software; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 #
20 # author: Kornel Benko, kornel@lyx.org
21 #
22 # TODO: Search for good correlations of deleted and inserted string
23 # using Text::Levenshtein or Algorithm::Diff
24
25 use strict;
26 use Term::ANSIColor;
27
28 my ($status, $foundline, $msgid, $msgstr, $fuzzy);
29
30 my %Messages = ();              # Used for original po-file
31 my %newMessages = ();           # new po-file
32 my %Untranslated = ();          # inside new po-file
33 my %Fuzzy = ();                 # inside new po-file
34 my $result = 0;                 # exit value
35 my @names = ();
36
37
38 while(defined($ARGV[0])) {
39   last if ($ARGV[0] !~ /^\-/);
40   my $param = shift(@ARGV);
41   if ($param eq "-L") {
42     my $name = shift(@ARGV);
43     push(@names, $name);
44   }
45 }
46 if (! defined($names[0])) {
47   push(@names, "original");
48 }
49 if (! defined($names[1])) {
50   push(@names, "new");
51 }
52
53 if (@ARGV != 2) {
54   die('"', join('" "', @names, @ARGV) . "\" Expected exactly 2 parameters");
55 }
56
57 &check($names[0], $ARGV[0]);
58 &check($names[1], $ARGV[1]);
59
60 &parse_po_file($ARGV[0], \%Messages);
61 &parse_po_file($ARGV[1], \%newMessages);
62
63 my @MsgKeys = &getLineSortedKeys(\%newMessages);
64
65 print "<<< \"$names[0]\"\n";
66 print ">>> \"$names[1]\"\n";
67 for my $k (@MsgKeys) {
68   if ($newMessages{$k}->{msgstr} eq "") {
69     # this is still untranslated string
70     $Untranslated{$newMessages{$k}->{line}} = $k;
71   }
72   elsif ($newMessages{$k}->{fuzzy}) {
73     #fuzzy string
74     $Fuzzy{$newMessages{$k}->{line}} = $k;
75   }
76   if (exists($Messages{$k})) {
77     &printIfDiff($k, $Messages{$k}, $newMessages{$k});
78     delete($Messages{$k});
79     delete($newMessages{$k});
80   }
81 }
82
83 @MsgKeys = &getLineSortedKeys(\%Messages);
84 for my $k (@MsgKeys) {
85   $result |= 8;
86   print "deleted message\n";
87   print "< line = " . $Messages{$k}->{line} . "\n";
88   print color 'red';
89   print "< fuzzy = " . $Messages{$k}->{fuzzy} . "\n";
90   print "< msgid = \"$k\"\n";
91   print "< msgstr = \"" . $Messages{$k}->{msgstr} . "\"\n";
92   print color 'reset';
93 }
94
95 @MsgKeys = &getLineSortedKeys(\%newMessages);
96 for my $k (@MsgKeys) {
97   $result |= 16;
98   print "new message\n";
99   print "> line = " . $newMessages{$k}->{line} . "\n";
100   print color 'green';
101   print "> fuzzy = " . $newMessages{$k}->{fuzzy} . "\n";
102   print "> msgid = \"$k\"\n";
103   print "> msgstr = \"" . $newMessages{$k}->{msgstr} . "\"\n";
104   print color 'reset';
105 }
106
107 &printExtraMessages("fuzzy", \%Fuzzy);
108 &printExtraMessages("untranslated", \%Untranslated);
109
110 exit($result);
111
112 sub check($$)
113 {
114   my ($spec, $filename) = @_;
115
116   if (! -e $filename ) {
117     die("$spec po file does not exist");
118   }
119   if ( ! -f $filename ) {
120     die("$spec po file is not regular");
121   }
122   if ( ! -r $filename ) {
123     die("$spec po file is not readable");
124   }
125 }
126
127 sub printDiff($$$$)
128 {
129   my ($k, $nk, $rM, $rnM) = @_;
130   print "diffline = " . $rM->{line} . "," . $rnM->{line} . "\n";
131   print " msgid = \"$k\"\n";
132   if ($rM->{fuzzy} eq $rnM->{fuzzy}) {
133     print " fuzzy = " . $rM->{fuzzy} . "\n";
134   }
135   else {
136     print color 'red';
137     print "< fuzzy = " . $rM->{fuzzy} . "\n";
138     print color 'reset';
139   }
140   print color 'red';
141   print "< msgstr = " . $rM->{msgstr} . "\n";
142   print color 'green';
143   if ($k ne $nk) {
144     print "> msgid = \"$nk\"\n";
145   }
146   if ($rM->{fuzzy} ne $rnM->{fuzzy}) {
147     print "> fuzzy = " . $rnM->{fuzzy} . "\n";
148   }
149   print "> msgstr = " . $rnM->{msgstr} . "\n";
150   print "\n";
151   print color 'reset';
152 }
153
154 sub printIfDiff($$$)
155 {
156   my ($k, $rM, $rnM) = @_;
157   my $doprint = 0;
158   $doprint = 1 if ($rM->{fuzzy} != $rnM->{fuzzy});
159   $doprint = 1 if ($rM->{msgstr} ne $rnM->{msgstr});
160   if ($doprint) {
161     $result |= 4;
162     &printDiff($k, $k, $rM, $rnM);
163   }
164 }
165
166 sub parse_po_file($$)
167 {
168   my ($file, $rMessages) = @_;
169   if (open(FI, '<', $file)) {
170     $status = "normal";
171     $fuzzy = 0;
172     my $lineno = 0;
173     while (my $line = <FI>) {
174       $lineno++;
175       &parse_po_line($line, $lineno, $rMessages);
176     }
177     &parse_po_line("", $lineno + 1, $rMessages);
178     close(FI);
179   }
180 }
181
182 sub parse_po_line($$$)
183 {
184   my ($line, $lineno, $rMessages) = @_;
185   chomp($line);
186
187   if ($status eq "normal") {
188     if ($line =~ /^#, fuzzy/) {
189       $fuzzy = 1;
190     }
191     elsif ($line =~ s/^msgid\s+//) {
192       $foundline = $lineno;
193       $status = "msgid";
194       $msgid = "";
195       &parse_po_line($line);
196     }
197   }
198   elsif ($status eq "msgid") {
199     if ($line =~ /^\s*"(.*)"\s*/) {
200       $msgid .= $1;
201     }
202     elsif ($line =~ s/^msgstr\s+//) {
203       $status = "msgstr";
204       $msgstr = "";
205       &parse_po_line($line);
206     }
207   }
208   elsif ($status eq "msgstr") {
209     if ($line =~ /^\s*"(.*)"\s*/) {
210       $msgstr .= $1;
211     }
212     else {
213       if ($msgid ne "") {
214         $rMessages->{$msgid}->{line} = $foundline;
215         $rMessages->{$msgid}->{fuzzy} = $fuzzy;
216         $rMessages->{$msgid}->{msgstr} = $msgstr;
217       }
218       $fuzzy = 0;
219       $status = "normal";
220     }
221   }
222   else {
223     die("invalid status");
224   }
225 }
226
227 sub getLineSortedKeys($)
228 {
229   my ($rMessages) = @_;
230
231   return sort {$rMessages->{$a}->{line} <=> $rMessages->{$b}->{line};} keys %{$rMessages};
232 }
233
234 sub printExtraMessages($$)
235 {
236   my ($type, $rExtra) = @_;
237   my @UntranslatedKeys = sort { $a <=> $b;} keys %{$rExtra};
238
239   if (@UntranslatedKeys > 0) {
240     print "Still " . 0 + @UntranslatedKeys . " $type messages found in $ARGV[1]\n";
241     for my $l (@UntranslatedKeys) {
242       print "> line $l: \"" . $rExtra->{$l} . "\"\n"; 
243     }
244   }
245 }