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