| 1 |
italian |
1.1 |
#!/usr/bin/perl -w
|
| 2 |
|
|
|
| 3 |
joy |
1.28 |
# This is a little utility designed to keep track of translations
|
| 4 |
|
|
# in the Debian web site CVS repository.
|
| 5 |
|
|
|
| 6 |
|
|
# For information about translation revisions please see
|
| 7 |
|
|
# http://www.debian.org/devel/website/uptodate
|
| 8 |
|
|
|
| 9 |
french |
1.41 |
# This is GPL'ed code.
|
| 10 |
|
|
# Copyright 1998 Paolo Molaro <lupus@debian.org>.
|
| 11 |
peterk |
1.55 |
# Copyright 1999-2003 Peter Karlsson <peterk@debian.org>.
|
| 12 |
french |
1.41 |
# Copyright 2000,2001 Martin Quinson <mquinson@ens-lyon.fr>.
|
| 13 |
italian |
1.1 |
|
| 14 |
joy |
1.28 |
# Invocation:
|
| 15 |
joy |
1.34 |
# check_trans.pl [-vqdlM] [-C dir] [-p pattern] [-s subtree]
|
| 16 |
barbier |
1.48 |
# [-m email -n N] [-c charset] [-g] [-t outputtype]
|
| 17 |
joy |
1.28 |
# [language]
|
| 18 |
|
|
|
| 19 |
|
|
# It needs to be run from the top level webwml directory.
|
| 20 |
|
|
# If you don't specify a language on the command line, the language name
|
| 21 |
|
|
# will be loaded from a file called language.conf, if such a file exists.
|
| 22 |
|
|
|
| 23 |
|
|
# For example:
|
| 24 |
|
|
# $ check_trans.pl -v italian
|
| 25 |
italian |
1.1 |
# You may also check only some subtrees as in:
|
| 26 |
joy |
1.28 |
# $ check_trans.pl -s devel italian
|
| 27 |
italian |
1.1 |
|
| 28 |
joy |
1.28 |
# Options:
|
| 29 |
joy |
1.56 |
# -Q enable really quiet mode
|
| 30 |
|
|
# -q just don't whine about missing files
|
| 31 |
joy |
1.28 |
# -v enable verbose mode
|
| 32 |
joy |
1.56 |
# -V enable very verbose mode
|
| 33 |
barbier |
1.31 |
# -C <dir> go to <dir> directory before running this script
|
| 34 |
joy |
1.28 |
# -d output CVS diffs
|
| 35 |
|
|
# -l output CVS log messages
|
| 36 |
french |
1.42 |
# -T output translated diffs
|
| 37 |
joy |
1.28 |
# -p <pattern> include only files matching <pattern>,
|
| 38 |
french |
1.41 |
# default is *.html|*.wml
|
| 39 |
joy |
1.28 |
# -s <subtree> check only that subtree
|
| 40 |
barbier |
1.31 |
# -t <type> choose output type (default is `text')
|
| 41 |
joy |
1.28 |
# -M display differences for all 'Makefile's
|
| 42 |
peterk |
1.57 |
# -a output age of translation (if older than 2 months)
|
| 43 |
joy |
1.28 |
|
| 44 |
|
|
# Options useful when sending mails:
|
| 45 |
|
|
# -m <email> sends mails to translation maintainers
|
| 46 |
|
|
# PLEASE CAREFULLY READ THE BELOW TEXT ABOUT MAKING MAILS!
|
| 47 |
|
|
# <email> is the default recipient
|
| 48 |
|
|
# (it should be the list used for organisation,
|
| 49 |
|
|
# e.g. debian-l10n-french@lists.debian.org)
|
| 50 |
|
|
# -g debuG
|
| 51 |
barbier |
1.48 |
# -c <charset> charset used in mails
|
| 52 |
joy |
1.28 |
# -n <1|2|3> send mails of priority upper or equal to
|
| 53 |
|
|
# 1 (monthly), 2 (weekly) or 3 (daily)
|
| 54 |
french |
1.13 |
|
| 55 |
|
|
# Making Mails
|
| 56 |
|
|
# If you want to, this script send mails to the maintainer of the mails.
|
| 57 |
joy |
1.28 |
# BEWARE, SOME PEOPLE DO NOT LIKE TO RECEIVE AUTOMATIC MAILS!
|
| 58 |
|
|
|
| 59 |
|
|
# PREREQUISITES:
|
| 60 |
french |
1.41 |
# You will need two databases:
|
| 61 |
joy |
1.28 |
# - one in which to see which translator maintains which file
|
| 62 |
french |
1.13 |
# it must be named "./$langto/international/$langto/current_status.pl"
|
| 63 |
joy |
1.28 |
# (where $langto equals "french", "italian" or so)
|
| 64 |
|
|
# See webwml/french/international/french/current_status.pl" for example.
|
| 65 |
|
|
# - one in which to get info about translators and the frequency at
|
| 66 |
|
|
# which they want to get mails. It must be named
|
| 67 |
|
|
# webwml/$langto/international/$langto/translator.db.pl
|
| 68 |
|
|
# Please refer to the French one for more info.
|
| 69 |
|
|
|
| 70 |
french |
1.13 |
# USAGE:
|
| 71 |
french |
1.41 |
# If you give the "-g" option, all mails are sent to the default addressee
|
| 72 |
joy |
1.28 |
# (i.e. the one given as value to the -m option), without respect to their
|
| 73 |
|
|
# normal addressee. It is useful if you want to run it for yourself,
|
| 74 |
|
|
# and for debugging.
|
| 75 |
french |
1.41 |
# Without that option, it sends real mails to real addresses.
|
| 76 |
|
|
# MAKE SURE THE ADDRESSEES REALLY WANT TO GET THESE MAILS
|
| 77 |
italian |
1.1 |
|
| 78 |
joy |
1.32 |
use strict;
|
| 79 |
italian |
1.1 |
use Getopt::Std;
|
| 80 |
swedish |
1.2 |
use IO::Handle;
|
| 81 |
barbier |
1.31 |
use Date::Parse;
|
| 82 |
|
|
|
| 83 |
barbier |
1.36 |
# These modules reside under webwml/Perl
|
| 84 |
|
|
use lib ($0 =~ m|(.*)/|, $1 or ".") ."/Perl";
|
| 85 |
|
|
use Local::Cvsinfo;
|
| 86 |
french |
1.41 |
use Local::WmlDiffTrans;
|
| 87 |
barbier |
1.36 |
use Webwml::TransCheck;
|
| 88 |
|
|
use Webwml::TransIgnore;
|
| 89 |
|
|
|
| 90 |
joy |
1.28 |
# TODO:
|
| 91 |
|
|
# get the revisions from $lang/intl/$lang so diffing works
|
| 92 |
|
|
# need to quote dirnames?
|
| 93 |
|
|
# use a file to bind a file to a translator?
|
| 94 |
french |
1.13 |
|
| 95 |
joy |
1.32 |
# global db variables
|
| 96 |
french |
1.13 |
my $translations_status;
|
| 97 |
|
|
my $translators;# the ref resulting of require
|
| 98 |
|
|
my %translators;# the real hash
|
| 99 |
|
|
|
| 100 |
joy |
1.32 |
# misc hardcoded things
|
| 101 |
|
|
my $maintainer = "mquinson\@ens-lyon.fr"; # the default e-mail at which to bitch :-)
|
| 102 |
italian |
1.1 |
|
| 103 |
joy |
1.32 |
# options (note: with perl 5.6, this could change to our())
|
| 104 |
peterk |
1.57 |
use vars qw($opt_C $opt_M $opt_Q $opt_c $opt_d $opt_g $opt_l $opt_m $opt_n
|
| 105 |
|
|
$opt_p $opt_q $opt_s $opt_t $opt_T $opt_v $opt_V $opt_a);
|
| 106 |
joy |
1.32 |
$opt_n = 5; # an invalid default
|
| 107 |
joy |
1.28 |
$opt_s = '';
|
| 108 |
barbier |
1.31 |
$opt_C = '.';
|
| 109 |
|
|
$opt_t = 'text';
|
| 110 |
joy |
1.28 |
|
| 111 |
peterk |
1.57 |
unless (getopts('vgdqQC:m:c:s:Tt:p:ln:MVa'))
|
| 112 |
peterk |
1.21 |
{
|
| 113 |
|
|
open SELF, "<$0" or die "Unable to display help: $!\n";
|
| 114 |
|
|
HELP: while (<SELF>)
|
| 115 |
|
|
{
|
| 116 |
|
|
print, next if /^$/;
|
| 117 |
|
|
last HELP if (/^use/);
|
| 118 |
|
|
s/^# ?//;
|
| 119 |
joy |
1.28 |
next if /^!/;
|
| 120 |
peterk |
1.21 |
print;
|
| 121 |
|
|
}
|
| 122 |
|
|
exit;
|
| 123 |
|
|
}
|
| 124 |
joy |
1.32 |
|
| 125 |
peterk |
1.57 |
if ($opt_a)
|
| 126 |
|
|
{
|
| 127 |
peterk |
1.58 |
require Date::Manip;
|
| 128 |
|
|
import Date::Manip;
|
| 129 |
peterk |
1.57 |
}
|
| 130 |
|
|
|
| 131 |
joy |
1.28 |
die "you can't have both verbose and quiet, doh!\n" if (($opt_v) && ($opt_Q));
|
| 132 |
joy |
1.56 |
die "you can't have both very verbose and quiet, doh!\n" if (($opt_V) && ($opt_Q));
|
| 133 |
|
|
|
| 134 |
|
|
$opt_v = 1 if ($opt_V);
|
| 135 |
italian |
1.1 |
|
| 136 |
joy |
1.23 |
warn "Checking subtree $opt_s only\n" if (($opt_v) && ($opt_s));
|
| 137 |
italian |
1.1 |
|
| 138 |
|
|
# include only files matching $filename
|
| 139 |
peterk |
1.57 |
my $filename = $opt_p || '(\.wml$)|(\.html$)|(\.src$)';
|
| 140 |
barbier |
1.36 |
|
| 141 |
barbier |
1.43 |
# Go to desired directory
|
| 142 |
|
|
chdir($opt_C) || die "Cannot go to $opt_C\n";
|
| 143 |
|
|
|
| 144 |
barbier |
1.36 |
my $cvs = Local::Cvsinfo->new();
|
| 145 |
|
|
$cvs->options(
|
| 146 |
|
|
recursive => 1,
|
| 147 |
|
|
matchfile => [ $filename ],
|
| 148 |
|
|
skipdir => [ "template" ],
|
| 149 |
|
|
);
|
| 150 |
|
|
# This object is used to retrieve information when original is
|
| 151 |
|
|
# not English
|
| 152 |
|
|
my $altcvs = $cvs->new();
|
| 153 |
|
|
|
| 154 |
|
|
# Global .transignore
|
| 155 |
|
|
my $globtrans = Webwml::TransIgnore->new(".");
|
| 156 |
barbier |
1.31 |
|
| 157 |
joy |
1.28 |
# language configuration
|
| 158 |
peterk |
1.53 |
my $defaultlanguage = '';
|
| 159 |
peterk |
1.50 |
if (exists $ENV{DWWW_LANG})
|
| 160 |
alfie |
1.44 |
{
|
| 161 |
|
|
$defaultlanguage = $ENV{DWWW_LANG};
|
| 162 |
peterk |
1.50 |
}
|
| 163 |
alfie |
1.44 |
elsif (open CONF, "<language.conf")
|
| 164 |
swedish |
1.6 |
{
|
| 165 |
kraai |
1.59 |
while (<CONF>)
|
| 166 |
|
|
{
|
| 167 |
|
|
next if /^#/;
|
| 168 |
|
|
$defaultlanguage = <CONF>;
|
| 169 |
|
|
chomp $defaultlanguage;
|
| 170 |
|
|
}
|
| 171 |
swedish |
1.6 |
close CONF;
|
| 172 |
|
|
}
|
| 173 |
|
|
|
| 174 |
joy |
1.28 |
my $from = 'english';
|
| 175 |
|
|
my $to = shift || $defaultlanguage;
|
| 176 |
|
|
$to =~ s%/$%%; # Remove slash from the end
|
| 177 |
italian |
1.1 |
|
| 178 |
peterk |
1.53 |
if ($to eq '')
|
| 179 |
|
|
{
|
| 180 |
peterk |
1.55 |
die "Language not defined in DWWW_LANG, language.conf or on command line\n";
|
| 181 |
peterk |
1.53 |
}
|
| 182 |
|
|
|
| 183 |
joy |
1.28 |
my $langto = $to;
|
| 184 |
french |
1.13 |
$langto =~ s,^([^/]*).*$,$1,;
|
| 185 |
peterk |
1.50 |
if (-e "./$langto/international/$langto/current_status.pl" &&
|
| 186 |
french |
1.13 |
-e "./$langto/international/$langto/translator.db.pl") {
|
| 187 |
|
|
print "READ PAGES DB: $langto/international/$langto/current_status.pl\n"
|
| 188 |
|
|
if $opt_v;
|
| 189 |
|
|
push(@INC,"./$langto/international/$langto");
|
| 190 |
|
|
require 'current_status.pl';
|
| 191 |
|
|
print "READ TRANSLATOR DB: $langto/international/$langto/translator.db.pl\n"
|
| 192 |
|
|
if $opt_v;
|
| 193 |
|
|
require 'translator.db.pl';
|
| 194 |
|
|
%translators=%{init_translators()};
|
| 195 |
barbier |
1.46 |
if (defined($translators{default})) {
|
| 196 |
|
|
my @field_list = keys %{$translators{default}};
|
| 197 |
|
|
foreach my $user (keys %translators) {
|
| 198 |
|
|
next unless $user =~ m/ /;
|
| 199 |
|
|
foreach my $f (@field_list) {
|
| 200 |
|
|
$translators{$user}{$f} = $translators{default}{$f}
|
| 201 |
|
|
unless defined($translators{$user}{$f});
|
| 202 |
|
|
}
|
| 203 |
|
|
}
|
| 204 |
|
|
}
|
| 205 |
french |
1.13 |
} else {
|
| 206 |
|
|
die "I need my DBs to send mails !\n Please read the comments in the script and try again\n" if $opt_m;
|
| 207 |
|
|
}
|
| 208 |
|
|
|
| 209 |
|
|
if ($opt_m) {
|
| 210 |
|
|
unless ($opt_n =~ m,[123],) {
|
| 211 |
|
|
die "Invalid priority. Please set -n value to 1, 2 or 3.\n".
|
| 212 |
|
|
"(assuming you know what you're doing)\n";
|
| 213 |
|
|
}
|
| 214 |
|
|
}
|
| 215 |
|
|
|
| 216 |
italian |
1.1 |
$from = "$from/$opt_s";
|
| 217 |
|
|
$to = "$to/$opt_s";
|
| 218 |
|
|
|
| 219 |
french |
1.13 |
init_mails();
|
| 220 |
barbier |
1.31 |
|
| 221 |
|
|
print "\$translations = {\n" if $opt_t eq 'perl';
|
| 222 |
|
|
|
| 223 |
peterk |
1.49 |
# Check the files in the English directory
|
| 224 |
|
|
|
| 225 |
joy |
1.56 |
my $V = $opt_V ? 1 : 0;
|
| 226 |
|
|
$cvs->readinfo($from, verbose => $V );
|
| 227 |
barbier |
1.36 |
foreach my $path (@{$cvs->dirs()}) {
|
| 228 |
|
|
my $tpath = $path;
|
| 229 |
|
|
$tpath =~ s/^$from/$to/o;
|
| 230 |
|
|
my $transignore = Webwml::TransIgnore->new($tpath);
|
| 231 |
|
|
next unless $transignore->found();
|
| 232 |
|
|
warn "Loading $tpath/.transignore\n" if $opt_v;
|
| 233 |
|
|
foreach (@{$transignore->local()}) {
|
| 234 |
|
|
s/^$to/$from/o;
|
| 235 |
|
|
$cvs->removefile($_);
|
| 236 |
|
|
}
|
| 237 |
|
|
}
|
| 238 |
|
|
|
| 239 |
peterk |
1.49 |
my %checkedfile;
|
| 240 |
|
|
|
| 241 |
barbier |
1.36 |
foreach (sort @{$cvs->files()}) {
|
| 242 |
barbier |
1.31 |
my ($path, $tpath);
|
| 243 |
italian |
1.1 |
$path = $_;
|
| 244 |
|
|
$tpath = $path;
|
| 245 |
|
|
$tpath =~ s/^$from/$to/o;
|
| 246 |
peterk |
1.49 |
$checkedfile{$tpath} = 1; # Remember which files we found here
|
| 247 |
french |
1.41 |
check_file($tpath,
|
| 248 |
|
|
$cvs->revision($path),
|
| 249 |
|
|
str2time($cvs->date($path)),
|
| 250 |
|
|
get_translators_from_db($tpath));
|
| 251 |
french |
1.13 |
}
|
| 252 |
|
|
|
| 253 |
peterk |
1.49 |
# Now check all the files in the translated directory as well, there may be
|
| 254 |
|
|
# some files that are not available in the English version.
|
| 255 |
|
|
|
| 256 |
|
|
$cvs->reset();
|
| 257 |
joy |
1.56 |
$cvs->readinfo($to, verbose => $V );
|
| 258 |
peterk |
1.49 |
foreach my $tpath (@{$cvs->dirs()})
|
| 259 |
|
|
{
|
| 260 |
|
|
my $transignore = Webwml::TransIgnore->new($tpath);
|
| 261 |
|
|
next unless $transignore->found();
|
| 262 |
|
|
warn "Loading $tpath/.transignore\n" if $opt_v;
|
| 263 |
|
|
foreach (@{$transignore->local()})
|
| 264 |
|
|
{
|
| 265 |
|
|
s/^$to/$from/o;
|
| 266 |
|
|
$cvs->removefile($_);
|
| 267 |
|
|
}
|
| 268 |
|
|
}
|
| 269 |
|
|
|
| 270 |
|
|
foreach (sort @{$cvs->files()})
|
| 271 |
|
|
{
|
| 272 |
|
|
my $tpath = $_;
|
| 273 |
|
|
next if defined $checkedfile{$tpath}; # Don't look at a file twice
|
| 274 |
|
|
warn "$tpath does not match anything in English\n" if $opt_v;
|
| 275 |
|
|
check_file($tpath, undef, undef, get_translators_from_db($tpath));
|
| 276 |
|
|
}
|
| 277 |
|
|
|
| 278 |
barbier |
1.31 |
print "}; 1;\n" if $opt_t eq 'perl';
|
| 279 |
|
|
|
| 280 |
french |
1.13 |
send_mails();
|
| 281 |
peterk |
1.21 |
|
| 282 |
french |
1.41 |
if ($opt_M) {
|
| 283 |
joy |
1.32 |
foreach my $makefile (split(/\n/, `find $from -name Makefile -print`)) {
|
| 284 |
peterk |
1.21 |
my $destination = $makefile;
|
| 285 |
|
|
$destination =~ s/^$from/$to/o;
|
| 286 |
|
|
if (-e $destination) {
|
| 287 |
peterk |
1.53 |
# First check if the destination makefile simply includes the english
|
| 288 |
|
|
# version
|
| 289 |
|
|
my $includes = 0;
|
| 290 |
|
|
if (open MK, "<$destination")
|
| 291 |
|
|
{
|
| 292 |
|
|
my $firstline = <MK>;
|
| 293 |
|
|
close MK;
|
| 294 |
|
|
$includes = 1 if $firstline =~ m'^include.*subst webwml/.*,webwml/english,.*CURDIR.*Makefile';
|
| 295 |
|
|
}
|
| 296 |
|
|
else
|
| 297 |
|
|
{
|
| 298 |
|
|
warn "Cannot read $from: $!\n";
|
| 299 |
|
|
}
|
| 300 |
|
|
unless ($includes)
|
| 301 |
|
|
{
|
| 302 |
|
|
# Otherwise show any differences
|
| 303 |
|
|
STDOUT->flush;
|
| 304 |
|
|
system("diff -u $destination $makefile");
|
| 305 |
|
|
STDOUT->flush;
|
| 306 |
|
|
}
|
| 307 |
peterk |
1.21 |
}
|
| 308 |
|
|
}
|
| 309 |
|
|
}
|
| 310 |
french |
1.13 |
|
| 311 |
|
|
sub verify_send {
|
| 312 |
joy |
1.15 |
return 1 unless ($opt_m);
|
| 313 |
french |
1.13 |
# returns true whether we have to send this part to this guy
|
| 314 |
|
|
my $name=shift;
|
| 315 |
|
|
my $part=shift;
|
| 316 |
|
|
$name =~ s,<.*?>,,;
|
| 317 |
|
|
$name =~ s,^ *(.*?) *$,$1,;
|
| 318 |
|
|
print "$name is unknown\n" unless defined($translators{$name});
|
| 319 |
|
|
# print "pri=$opt_n ; maint_pri=${translators{$name}{$part}}\n";
|
| 320 |
|
|
return $opt_m # if we have to send any mail
|
| 321 |
|
|
&& defined($translators{$name}) # if this guy is known
|
| 322 |
|
|
&& defined($translators{$name}{$part}) # we know something about the wanted frequency
|
| 323 |
|
|
&& ($opt_n <= $translators{$name}{$part}); # check if the frequency is ok
|
| 324 |
|
|
}
|
| 325 |
|
|
|
| 326 |
|
|
sub get_translators_from_db {
|
| 327 |
|
|
my $id=shift;
|
| 328 |
|
|
my $res='';
|
| 329 |
|
|
|
| 330 |
|
|
$id=~ s,^$langto/,,;
|
| 331 |
|
|
$id=~ s/\.wml$//;
|
| 332 |
|
|
if (defined(%{$$translations_status{$id}})
|
| 333 |
|
|
&& defined ($$translations_status{$id}{'translation_maintainer'})) {
|
| 334 |
|
|
foreach my $n (sort @{$$translations_status{$id}{'translation_maintainer'}}) {
|
| 335 |
|
|
$res .= " $n";
|
| 336 |
|
|
}
|
| 337 |
|
|
} else {
|
| 338 |
|
|
$res = "";
|
| 339 |
|
|
}
|
| 340 |
|
|
return $res;
|
| 341 |
|
|
}
|
| 342 |
|
|
|
| 343 |
|
|
sub init_mails {
|
| 344 |
|
|
return unless $opt_m;
|
| 345 |
joy |
1.16 |
eval q{use MIME::Lite};
|
| 346 |
french |
1.13 |
foreach my $name (keys %translators) {
|
| 347 |
|
|
return if defined $translators{$name}{"msg"};
|
| 348 |
barbier |
1.46 |
next if $name eq 'default' || $translators{$name}{email} eq '';
|
| 349 |
french |
1.13 |
$translators{$name}{"msg"} = MIME::Lite->new(
|
| 350 |
|
|
From => "Script watching translation state <$maintainer>",
|
| 351 |
|
|
To => ($opt_g ? $opt_m : $translators{$name}{"email"}),
|
| 352 |
barbier |
1.46 |
Subject => $translators{$name}{mailsubject},
|
| 353 |
french |
1.13 |
Type => 'multipart/mixed');
|
| 354 |
barbier |
1.46 |
my $str;
|
| 355 |
|
|
{
|
| 356 |
|
|
open (MAIL, "< $translators{$name}{mailbody}")
|
| 357 |
|
|
or die "$name: Unable to read \`$translators{$name}{mailbody}'";
|
| 358 |
|
|
local $/ = undef;
|
| 359 |
|
|
$str= <MAIL>;
|
| 360 |
|
|
close (MAIL);
|
| 361 |
|
|
}
|
| 362 |
|
|
1 while ($str =~ s/#(.*?)#/eval $1/ge);
|
| 363 |
french |
1.13 |
|
| 364 |
barbier |
1.48 |
my $part = MIME::Lite->new(
|
| 365 |
french |
1.13 |
Type => 'TEXT',
|
| 366 |
|
|
Data => $str);
|
| 367 |
barbier |
1.48 |
$part->attr('content-type.charset' => $opt_c) if $opt_c;
|
| 368 |
|
|
$translators{$name}{"msg"}->attach($part);
|
| 369 |
french |
1.13 |
$translators{$name}{"send"}=0;
|
| 370 |
|
|
}
|
| 371 |
|
|
}
|
| 372 |
|
|
|
| 373 |
|
|
sub send_mails {
|
| 374 |
|
|
#Makes the mails and send them
|
| 375 |
|
|
return unless $opt_m;
|
| 376 |
|
|
foreach my $name (sort keys %translators) {
|
| 377 |
barbier |
1.46 |
next if $name eq 'default' || $translators{$name}{email} eq '';
|
| 378 |
french |
1.13 |
$translators{$name}{"msg"}->attach(
|
| 379 |
|
|
Type => 'TEXT',
|
| 380 |
|
|
Filename => 'NeedToUpdate_summary',
|
| 381 |
|
|
Data => $translators{$name}{"part_summary"})
|
| 382 |
|
|
if defined($translators{$name}{"part_summary"});
|
| 383 |
|
|
$translators{$name}{"msg"}->attach(
|
| 384 |
|
|
Type => 'TEXT',
|
| 385 |
|
|
Filename => 'Missing_summary',
|
| 386 |
|
|
Data => $translators{$name}{"part_missing"})
|
| 387 |
|
|
if defined($translators{$name}{"part_missing"});
|
| 388 |
peterk |
1.50 |
foreach my $part (qw (file logs diff tdiff)) {
|
| 389 |
french |
1.13 |
if (defined($translators{$name}{"part_$part"})) {
|
| 390 |
|
|
foreach my $file (sort keys %{$translators{$name}{"part_$part"}}) {
|
| 391 |
|
|
$translators{$name}{"msg"}->attach(
|
| 392 |
|
|
Type => 'TEXT',
|
| 393 |
|
|
Filename => "$file.$part",
|
| 394 |
|
|
Data => $translators{$name}{"part_$part"}{$file});
|
| 395 |
|
|
}
|
| 396 |
|
|
}
|
| 397 |
italian |
1.1 |
}
|
| 398 |
french |
1.13 |
if ($translators{$name}{"send"}) {
|
| 399 |
barbier |
1.47 |
print "send mail to $name\n" unless $opt_Q;
|
| 400 |
french |
1.13 |
if (($name =~ m,mquinson,) || ($opt_g && $opt_m eq $maintainer)) {
|
| 401 |
barbier |
1.47 |
print "Well, detourned to $maintainer\n" unless $opt_Q;
|
| 402 |
french |
1.13 |
$translators{$name}{"msg"}->send;
|
| 403 |
|
|
}
|
| 404 |
|
|
# $translators{$name}{"msg"}->print_header;
|
| 405 |
|
|
$translators{$name}{"msg"}->send;
|
| 406 |
|
|
} else {
|
| 407 |
barbier |
1.47 |
print "didn't send mail to $name: nothing to say to him\n" unless $opt_Q;
|
| 408 |
peterk |
1.50 |
}
|
| 409 |
french |
1.41 |
}
|
| 410 |
italian |
1.1 |
}
|
| 411 |
|
|
|
| 412 |
french |
1.13 |
sub add_part {
|
| 413 |
|
|
my $name = shift;
|
| 414 |
|
|
my $part = shift;
|
| 415 |
peterk |
1.50 |
my $txt = shift;
|
| 416 |
french |
1.13 |
$name =~ s,<.*?>,,;
|
| 417 |
|
|
$name =~ s,^ *(.*?) *$,$1,;
|
| 418 |
|
|
if (verify_send($name,$part)) {
|
| 419 |
|
|
$translators{$name}{"part_$part"}.=$txt;
|
| 420 |
|
|
$translators{$name}{"send"}=1;
|
| 421 |
|
|
}
|
| 422 |
|
|
}
|
| 423 |
joy |
1.28 |
|
| 424 |
french |
1.13 |
sub add_sub_part {
|
| 425 |
|
|
my $name = shift;
|
| 426 |
|
|
my $part = shift;
|
| 427 |
|
|
my $subpart=shift;
|
| 428 |
french |
1.41 |
my $txt = shift;
|
| 429 |
french |
1.13 |
$name =~ s,<.*?>,,;
|
| 430 |
|
|
$name =~ s,^ *(.*?) *$,$1,;
|
| 431 |
french |
1.42 |
# print "add_sub_part($name)(part=$part)($subpart):$txt" if $opt_v;
|
| 432 |
french |
1.41 |
STDOUT->flush;
|
| 433 |
french |
1.13 |
if (verify_send($name,$part)) {
|
| 434 |
|
|
# print "YES\n";
|
| 435 |
french |
1.41 |
$translators{$name}{"part_$part"}{$subpart}.= "$txt";
|
| 436 |
french |
1.13 |
$translators{$name}{"send"}=1;
|
| 437 |
|
|
}
|
| 438 |
|
|
# print "no\n";
|
| 439 |
|
|
}
|
| 440 |
|
|
|
| 441 |
french |
1.41 |
sub get_diff_txt {
|
| 442 |
|
|
my ($oldr, $revision, $oldname, $name) = @_;
|
| 443 |
|
|
my $cmd;
|
| 444 |
|
|
|
| 445 |
|
|
# Get old revision file
|
| 446 |
french |
1.42 |
$cmd = "cvs -z3 update -r $oldr -p $oldname 2>/dev/null";
|
| 447 |
french |
1.41 |
# print "!get_diff_txt: cvs -z3 update -r ".$oldr." -p ".$oldname."\n";
|
| 448 |
|
|
my @old_rev_file_lines = qx($cmd);
|
| 449 |
|
|
|
| 450 |
|
|
# Get translation file
|
| 451 |
|
|
open (FILE,"$name") || die ("Can't open `$name' for read");
|
| 452 |
|
|
my @translation_file_lines;
|
| 453 |
|
|
while (<FILE>) {
|
| 454 |
|
|
$translation_file_lines[scalar @translation_file_lines] = $_;
|
| 455 |
|
|
}
|
| 456 |
|
|
close FILE || die ("Can't close $name after reading");
|
| 457 |
|
|
|
| 458 |
|
|
# Get diff lines
|
| 459 |
french |
1.42 |
$cmd = "cvs -z3 diff -u -r$oldr -r $revision $oldname 2>/dev/null";
|
| 460 |
|
|
# print "get_diff_txt: $cmd: cvs -z3 diff -u -r$oldr -r $revision $oldname\n";
|
| 461 |
french |
1.41 |
my @diff_lines = qx($cmd);
|
| 462 |
|
|
|
| 463 |
|
|
my $txt = Local::WmlDiffTrans::find_trans_parts(\@old_rev_file_lines,
|
| 464 |
|
|
\@translation_file_lines,
|
| 465 |
|
|
\@diff_lines);
|
| 466 |
|
|
|
| 467 |
|
|
return $txt;
|
| 468 |
|
|
}
|
| 469 |
french |
1.13 |
|
| 470 |
italian |
1.1 |
sub check_file {
|
| 471 |
barbier |
1.31 |
my ($name, $revision, $mtime, $translator) = @_;
|
| 472 |
barbier |
1.54 |
$revision ||= 'n/a';
|
| 473 |
peterk |
1.51 |
my ($oldr, $oldname, $original, $fromname);
|
| 474 |
joy |
1.28 |
warn "Checking $name, English revision $revision\n" if $opt_v;
|
| 475 |
barbier |
1.31 |
my $docname = $name;
|
| 476 |
|
|
$docname =~ s#^$langto/##;
|
| 477 |
|
|
$docname =~ s#\.wml$##;
|
| 478 |
italian |
1.1 |
unless (-r $name) {
|
| 479 |
peterk |
1.52 |
(my $iname = $name) =~ s/^$to//o;
|
| 480 |
barbier |
1.40 |
if (!$globtrans->is_global($iname)) {
|
| 481 |
joy |
1.28 |
unless (($opt_q) || ($opt_Q)) {
|
| 482 |
barbier |
1.31 |
if ($opt_t eq 'perl') {
|
| 483 |
|
|
print "'$docname' => {\n\t'type' => 'Web',\n";
|
| 484 |
|
|
print "\t'revision' => '$revision',\n";
|
| 485 |
barbier |
1.54 |
print "\t'mtime' => '$mtime',\n" if $mtime;
|
| 486 |
barbier |
1.31 |
print "\t'status' => 1,\n";
|
| 487 |
|
|
print "},\n";
|
| 488 |
|
|
} else {
|
| 489 |
|
|
print "Missing $name version $revision\n";
|
| 490 |
|
|
}
|
| 491 |
barbier |
1.46 |
add_part("untranslated","missing","Missing $name version $revision\n");
|
| 492 |
joy |
1.22 |
}
|
| 493 |
joy |
1.28 |
} else {
|
| 494 |
|
|
warn "Ignored $name\n" if $opt_v;
|
| 495 |
french |
1.13 |
}
|
| 496 |
italian |
1.1 |
return;
|
| 497 |
|
|
}
|
| 498 |
barbier |
1.36 |
my $transcheck = Webwml::TransCheck->new($name);
|
| 499 |
barbier |
1.38 |
$oldr = $transcheck->revision() || 0;
|
| 500 |
|
|
if (!$oldr && ($name =~ m#$langto/international/$langto#i)) {
|
| 501 |
|
|
# This document is original, check for
|
| 502 |
|
|
# english/international/$langto...
|
| 503 |
|
|
$name =~ s{^$to}{$from};
|
| 504 |
|
|
$transcheck = Webwml::TransCheck->new($name);
|
| 505 |
|
|
$oldr = $transcheck->revision() || 0;
|
| 506 |
|
|
}
|
| 507 |
barbier |
1.36 |
$translator = $transcheck->maintainer() || "";
|
| 508 |
|
|
$original = $transcheck->original();
|
| 509 |
|
|
warn "Found translation for $oldr\n" if $opt_v and $oldr;
|
| 510 |
|
|
warn "Translated by $translator\n" if $opt_v and $translator;
|
| 511 |
|
|
warn "Original is $original\n" if $opt_v and $original;
|
| 512 |
|
|
if ($original) {
|
| 513 |
peterk |
1.51 |
my ($fromdir);
|
| 514 |
barbier |
1.36 |
$fromname = $name;
|
| 515 |
|
|
$fromname =~ s{^[^/]+}{$original};
|
| 516 |
|
|
$fromdir = $fromname;
|
| 517 |
|
|
$fromdir =~ s{/+[^/]+$}{};
|
| 518 |
|
|
$altcvs->reset();
|
| 519 |
|
|
$altcvs->readinfo($fromdir, matchfile => [$fromname]);
|
| 520 |
|
|
$revision = $altcvs->revision($fromname);
|
| 521 |
|
|
warn "Original is $original, revision $revision\n" if $opt_v;
|
| 522 |
joy |
1.24 |
}
|
| 523 |
|
|
|
| 524 |
barbier |
1.36 |
$translator =~ s/^\s+//;
|
| 525 |
|
|
$translator =~ s/\s+$//;
|
| 526 |
french |
1.13 |
|
| 527 |
joy |
1.18 |
my $str;
|
| 528 |
peterk |
1.49 |
my $status = 8; # Unknown
|
| 529 |
|
|
(my $numrev) = $revision =~ m/^1\.(\d+)$/; $numrev ||= "0";
|
| 530 |
|
|
(my $numoldr) = $oldr =~ m/^1\.(\d+)$/; $numoldr ||= "0";
|
| 531 |
|
|
|
| 532 |
|
|
if ($revision ne 'n/a')
|
| 533 |
|
|
{
|
| 534 |
|
|
# The original version of this file exists (English or otherwise)
|
| 535 |
|
|
# - compare the translated version number to the original
|
| 536 |
|
|
if (!$oldr) {
|
| 537 |
peterk |
1.57 |
if ($name =~ /^english/)
|
| 538 |
|
|
{
|
| 539 |
|
|
# This is the original file
|
| 540 |
|
|
$status = 4; # Up-to-date
|
| 541 |
|
|
$oldr = $revision;
|
| 542 |
|
|
}
|
| 543 |
|
|
else
|
| 544 |
|
|
{
|
| 545 |
|
|
$oldr = '1.0';
|
| 546 |
|
|
$str = "Unknown status of $name (revision should be $revision)";
|
| 547 |
|
|
}
|
| 548 |
peterk |
1.49 |
} elsif ($oldr eq $revision) {
|
| 549 |
|
|
$status = 4; # Up-to-date
|
| 550 |
|
|
} elsif ($numoldr > $numrev) {
|
| 551 |
|
|
$str = "Broken revision number $oldr for $name, it should be $revision";
|
| 552 |
|
|
} else {
|
| 553 |
|
|
$str = "NeedToUpdate $name from version $oldr to version $revision";
|
| 554 |
|
|
$status = 3; # Needs update
|
| 555 |
|
|
}
|
| 556 |
|
|
}
|
| 557 |
|
|
else
|
| 558 |
|
|
{
|
| 559 |
|
|
# There is no English file matching this one.
|
| 560 |
|
|
if ($oldr eq '0')
|
| 561 |
|
|
{
|
| 562 |
|
|
# There is no translation-check header, so it must be the
|
| 563 |
|
|
# original version, and is thus always up-to-date.
|
| 564 |
|
|
$status = 4; # Up-to-date
|
| 565 |
|
|
}
|
| 566 |
|
|
else
|
| 567 |
|
|
{
|
| 568 |
|
|
# There is a translation-check header referencing an English
|
| 569 |
|
|
# version, which means that the English file has been removed.
|
| 570 |
|
|
$status = 7; # Obsolete
|
| 571 |
|
|
$str = "Obsolete $name";
|
| 572 |
|
|
}
|
| 573 |
|
|
}
|
| 574 |
|
|
|
| 575 |
french |
1.13 |
$str .= " (maintainer: $translator)" if $translator;
|
| 576 |
barbier |
1.31 |
if ($opt_t eq 'perl') {
|
| 577 |
|
|
print "'$docname' => {\n\t'type' => 'Web',\n";
|
| 578 |
|
|
print "\t'revision' => '$revision',\n";
|
| 579 |
barbier |
1.54 |
print "\t'mtime' => '$mtime',\n" if $mtime;
|
| 580 |
barbier |
1.31 |
print "\t'base_revision' => '$oldr',\n";
|
| 581 |
|
|
print "\t'translation_maintainer' => ['$translator'],\n" if $translator;
|
| 582 |
|
|
print "\t'status' => $status,\n";
|
| 583 |
|
|
print "},\n";
|
| 584 |
|
|
} elsif ($str && $oldr ne $revision) {
|
| 585 |
joy |
1.23 |
$str .= "\n";
|
| 586 |
|
|
print $str unless ($opt_Q);
|
| 587 |
|
|
}
|
| 588 |
|
|
|
| 589 |
peterk |
1.50 |
# Return if we're up-to-date or the original is missing
|
| 590 |
|
|
return if (defined($oldr) && ($oldr eq $revision || $revision eq 'n/a'));
|
| 591 |
barbier |
1.31 |
|
| 592 |
peterk |
1.51 |
if ($original)
|
| 593 |
|
|
{
|
| 594 |
|
|
# Source is non-English, use name we set up above
|
| 595 |
|
|
$oldname = $fromname;
|
| 596 |
|
|
}
|
| 597 |
|
|
else
|
| 598 |
|
|
{
|
| 599 |
|
|
# Source is English
|
| 600 |
|
|
$oldname = $name;
|
| 601 |
|
|
$oldname =~ s/^$to/$from/;
|
| 602 |
|
|
}
|
| 603 |
peterk |
1.17 |
|
| 604 |
|
|
my @logrev = split(/\./, $oldr);
|
| 605 |
|
|
$logrev[$#logrev] ++;
|
| 606 |
|
|
my $logoldr = join('.', @logrev);
|
| 607 |
barbier |
1.46 |
my $maxdelta = $transcheck->maxdelta() || $translators{maxdelta}{maxdelta} || 5;
|
| 608 |
peterk |
1.17 |
|
| 609 |
french |
1.13 |
if ($opt_m) {
|
| 610 |
barbier |
1.46 |
my @list_tr;
|
| 611 |
|
|
if ($translator eq "") {
|
| 612 |
|
|
if ($numrev - $numoldr >= $maxdelta) {
|
| 613 |
|
|
@list_tr = ("maxdelta");
|
| 614 |
|
|
} else {
|
| 615 |
|
|
@list_tr = ("unmaintained");
|
| 616 |
|
|
}
|
| 617 |
|
|
} elsif ($numrev - $numoldr >= $maxdelta) {
|
| 618 |
|
|
@list_tr = ($translator, "maxdelta");
|
| 619 |
|
|
} else {
|
| 620 |
|
|
@list_tr = ($translator);
|
| 621 |
|
|
}
|
| 622 |
|
|
foreach my $tname (@list_tr) {
|
| 623 |
|
|
add_part($tname,"summary",$str);
|
| 624 |
|
|
add_sub_part($tname,"diff",$name,
|
| 625 |
|
|
join("",qx(cvs -z3 diff -u -r'$oldr' -r $revision $oldname)));
|
| 626 |
|
|
add_sub_part($tname,"tdiff",$name,
|
| 627 |
|
|
get_diff_txt("$oldr","$revision","$oldname","$name"));
|
| 628 |
|
|
|
| 629 |
|
|
add_sub_part($tname,"logs",$name,
|
| 630 |
|
|
join("",qx(cvs -z3 log -r$logoldr:$revision $oldname)));
|
| 631 |
|
|
add_sub_part($tname,"file",$name,
|
| 632 |
|
|
join("",qx(cat $name)));
|
| 633 |
|
|
}
|
| 634 |
french |
1.13 |
}
|
| 635 |
peterk |
1.50 |
|
| 636 |
italian |
1.1 |
if ($opt_d) {
|
| 637 |
swedish |
1.2 |
STDOUT->flush;
|
| 638 |
barbier |
1.31 |
my $cvsline = "cvs -z3 log -r'$logoldr:$revision' '$oldname'";
|
| 639 |
joy |
1.32 |
warn "Running $cvsline\n" if (($opt_v) && ($opt_l));
|
| 640 |
|
|
system($cvsline) if $opt_l;
|
| 641 |
|
|
STDOUT->flush if $opt_l;
|
| 642 |
joy |
1.25 |
$cvsline = "cvs -z3 diff -u -r '$oldr' -r '$revision' '$oldname'";
|
| 643 |
|
|
warn "Running $cvsline\n" if $opt_v;
|
| 644 |
|
|
system($cvsline);
|
| 645 |
swedish |
1.2 |
STDOUT->flush;
|
| 646 |
peterk |
1.50 |
}
|
| 647 |
peterk |
1.57 |
|
| 648 |
|
|
if (3 == $status && $opt_a) {
|
| 649 |
|
|
# Check the age of this translation
|
| 650 |
|
|
STDOUT->flush;
|
| 651 |
|
|
my $cvsline = "cvs -z3 log -r'$logoldr' '$oldname'";
|
| 652 |
|
|
if (open CVSLOG, '-|', $cvsline)
|
| 653 |
|
|
{
|
| 654 |
|
|
CVSDATA: while (<CVSLOG>)
|
| 655 |
|
|
{
|
| 656 |
|
|
last CVSDATA if /^date:/;
|
| 657 |
|
|
}
|
| 658 |
|
|
close CVSLOG;
|
| 659 |
|
|
if (/^date: ([\d]{4}.[\d]{2}.[\d]{2})/)
|
| 660 |
|
|
{
|
| 661 |
|
|
# Got the date of the last translation
|
| 662 |
|
|
my $agestring = &DateCalc($1, 'today', 1, 1);
|
| 663 |
|
|
die "CVS date is in the future" if $agestring =~ /^\-/;
|
| 664 |
|
|
my ($years, $months, $weeks, $undef) = split /:/, substr($agestring, 1), 4;
|
| 665 |
|
|
my ($yearstring, $monthstring, $weekstring) = ('', '', '');
|
| 666 |
|
|
if ($years)
|
| 667 |
|
|
{
|
| 668 |
|
|
$yearstring = "$years year";
|
| 669 |
|
|
$yearstring .= 's' unless 1 == $years;
|
| 670 |
|
|
}
|
| 671 |
|
|
if ($months)
|
| 672 |
|
|
{
|
| 673 |
|
|
$monthstring = "$months month";
|
| 674 |
|
|
$monthstring .= 's' unless 1 == $months;
|
| 675 |
|
|
}
|
| 676 |
|
|
if ($weeks)
|
| 677 |
|
|
{
|
| 678 |
|
|
$weekstring = "$weeks week";
|
| 679 |
|
|
$weekstring .= 's' unless 1 == $weeks;
|
| 680 |
|
|
}
|
| 681 |
|
|
|
| 682 |
|
|
if ($weeks > 2 || $months || $years)
|
| 683 |
|
|
{
|
| 684 |
|
|
$monthstring .= ', '
|
| 685 |
|
|
if $monthstring ne '' && $weekstring ne '';
|
| 686 |
|
|
$yearstring .= ', '
|
| 687 |
|
|
if $yearstring ne '' && ($monthstring ne '' || $weekstring ne '');
|
| 688 |
|
|
print "$name is outdated by $yearstring$monthstring$weekstring\n";
|
| 689 |
|
|
}
|
| 690 |
|
|
}
|
| 691 |
|
|
}
|
| 692 |
|
|
STDOUT->flush;
|
| 693 |
|
|
}
|
| 694 |
french |
1.41 |
|
| 695 |
french |
1.42 |
if ($opt_T) {
|
| 696 |
french |
1.41 |
print get_diff_txt("$oldr", "$revision", "$oldname", "$name")."\n";
|
| 697 |
|
|
}
|
| 698 |
italian |
1.1 |
}
|