1#!/usr/bin/perl -w
2#
3# <@LICENSE>
4# Licensed to the Apache Software Foundation (ASF) under one or more
5# contributor license agreements.  See the NOTICE file distributed with
6# this work for additional information regarding copyright ownership.
7# The ASF licenses this file to you under the Apache License, Version 2.0
8# (the "License"); you may not use this file except in compliance with
9# the License.  You may obtain a copy of the License at:
10#
11#     http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18# </@LICENSE>
19
20use strict;
21use warnings;
22use FindBin;
23use Getopt::Std;
24
25# Lingua::Translate has a bunch of requirements (see bottom of its perldoc)
26use Lingua::Translate;
27
28# %rules and %scores from tmp/rules.pl
29our ($opt_c, $opt_e, $opt_h, $opt_n, $opt_r, %rules, %scores);
30
31sub usage {
32  die "generate-translation language output_file
33
34    -h       print this help
35    -e STR   use STR as destination character set (using Lingua::Translate)
36    -r STR   use STR as destination character set (using recode)
37    -n N     translate first N rules (used for testing)
38    -c DIR   use DIR as rules directory
39
40  language should be a two letter language code from this list:
41
42     zh: Chinese-simplified
43     zt: Chinese-traditional
44     nl: Dutch
45     fr: French
46     de: German
47     el: Greek
48     it: Italian
49     ja: Japanese
50     ko: Korean
51     pt: Portuguese
52     ru: Russian
53     es: Spanish
54
55  progress is displayed on standard error
56";
57}
58
59getopts("hc:e:n:r:");
60usage() if ($opt_h || @ARGV < 2);
61
62# options
63my $dest = shift @ARGV;
64my $output = shift @ARGV;
65my $cffile = $opt_c || "$FindBin::Bin/../rules";
66my $enc = $opt_e || "utf8";
67my $recode = $opt_r || "UTF-8";
68
69# rule => configuration hashes
70my %english;
71my %old;
72my %translation;
73
74# translation cache
75my %lang_cache;
76
77# do the work
78read_rules($cffile);
79generate_translation();
80print_translation();
81
82sub read_rules {
83  my ($cffile) = @_;
84
85  system("$FindBin::Bin/../build/parse-rules-for-masses -d \"$cffile\"")
86      and die "unable to parse rules\n";
87  require "$FindBin::Bin/tmp/rules.pl"
88      or die "unable to read tmp/rules.pl\n";
89}
90
91sub generate_translation {
92  my $fish = Lingua::Translate->new(src => "en",
93				    dest => $dest,
94				    dest_enc => $enc)
95      or die "no translation server available for en -> $dest\n";
96
97  # see if we had an old translation
98  if (-f "$FindBin::Bin/../rules/30_text_$dest.cf") {
99    open(OLD, "$FindBin::Bin/../rules/30_text_$dest.cf");
100    while(<OLD>) {
101      if (/^lang\s+$dest\s+describe\s+(\S+)\s+(.*?)\s*$/) {
102	$old{$1} = "lang $dest describe $1 $2\n";
103      }
104    }
105    close(OLD);
106  }
107
108  # try to generate new translation
109  my $count = 0;
110  for my $name (sort keys %rules) {
111    next if ($name eq '_scoreset');
112
113    my $lang_name = $name;
114    my $lang_describe = '';
115    if ($rules{$name}->{lang}) {
116      next;
117    }
118    if (defined $rules{$name}->{describe}) {
119      # translate name if it appears in the description
120      my $describe = $rules{$name}->{describe};
121      if ($describe =~ /$name/) {
122	eval {
123	  $lang_name = $fish->translate($name); # dies or croaks on error
124	};
125	if ($@) {
126	  $lang_name = '[A-Z]+[A-Z0-9_]+[A-Z0-9]';
127	}
128      }
129      # English version
130      $english{$name} = "describe $name\t$describe\n";
131      # translate description
132      eval {
133	if (defined $lang_cache{$describe}) {
134	  $lang_describe = $lang_cache{$describe};
135	}
136	else {
137	  # dies or croaks on error
138	  $lang_describe = $fish->translate($describe);
139	  $lang_describe =~ s/\s+/ /sg;
140	  $lang_describe =~ s/ $//g;
141	  $lang_cache{$describe} = $lang_describe;
142	}
143      };
144      # didn't work
145      if ($@) {
146	print STDERR "x";
147      }
148      else {
149	$lang_describe =~ s/$lang_name/$name/;
150	$translation{$name} = "lang $dest describe $name\t$lang_describe\n";
151	print STDERR ".";
152      }
153      $count++;
154      last if ($opt_n && $count == $opt_n);
155    }
156  }
157  print STDERR "\n" if $count > 0;
158}
159
160sub print_translation {
161  my $charset = $enc;
162  if ($opt_r) {
163    $charset = $recode;
164  }
165  $charset =~ s/utf-?8/utf-8/i;
166
167  open(OUTPUT, "> $output");
168  print OUTPUT <<'EOF';
169#
170# Please don't modify this file as your changes will be overwritten with
171# the next update. Use @@LOCAL_RULES_DIR@@/local.cf instead.
172# See 'perldoc Mail::SpamAssassin::Conf' for details.
173#
174# <@LICENSE>
175# Licensed to the Apache Software Foundation (ASF) under one or more
176# contributor license agreements.  See the NOTICE file distributed with
177# this work for additional information regarding copyright ownership.
178# The ASF licenses this file to you under the Apache License, Version 2.0
179# (the "License"); you may not use this file except in compliance with
180# the License.  You may obtain a copy of the License at:
181#
182#     http://www.apache.org/licenses/LICENSE-2.0
183#
184# Unless required by applicable law or agreed to in writing, software
185# distributed under the License is distributed on an "AS IS" BASIS,
186# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
187# See the License for the specific language governing permissions and
188# limitations under the License.
189# </@LICENSE>
190#
191###########################################################################
192
193# character set used in the following texts
194EOF
195  print OUTPUT <<EOF;
196lang $dest report_charset $charset
197
198# make me pretty
199EOF
200  open(MISC, "$FindBin::Bin/../rules/10_misc.cf");
201  while (<MISC>) {
202    if (/^(?:clear_report_template|report|clear_unsafe_report_template|unsafe_report)\b/) {
203      print OUTPUT "lang $dest $_";
204    }
205  }
206
207  print OUTPUT "\n\n";
208
209  for (sort keys %english) {
210    print OUTPUT "# $english{$_}";
211    print OUTPUT "# $translation{$_}" if $translation{$_};
212    print OUTPUT "# $old{$_}" if $old{$_};
213    print OUTPUT "\n";
214  }
215
216  system("/usr/bin/recode $enc..$recode $output") if $opt_r;
217}
218