4 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
6 # (Except where explictly superceded by other copyright notices)
8 # This work is made available to you under the terms of Version 2 of
9 # the GNU General Public License. A copy of that license should have
10 # been provided with this software, but in any event can be snarfed
13 # This work is distributed in the hope that it will be useful, but
14 # WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # General Public License for more details.
18 # Unless otherwise specified, all modifications, corrections or
19 # extensions to this work which alter its source code become the
20 # property of Best Practical Solutions, LLC when submitted for
21 # inclusion in the work.
26 # Portions Copyright 2002 Autrijus Tang <autrijus@autrijus.org>
35 use vars qw($DEBUG $FILECAT);
39 @ARGV = <lib/RT/I18N/*.po> unless @ARGV;
43 # extract all strings and stuff them into $FILECAT
44 File::Find::find( { wanted => \&extract_strings_from_code, follow => 0 }, '.' );
46 # ensure proper escaping and [_1] => %1 transformation
47 foreach my $str ( sort keys %{$FILECAT} ) {
48 my $entry = $FILECAT->{$str};
53 $str =~ s/((?<!~)(?:~~)*)\[_(\d+)\]/$1%$2/g;
54 $str =~ s/((?<!~)(?:~~)*)\[([A-Za-z#*]\w*),([^\]]+)\]/"$1%$2(".escape($3).")"/eg;
55 $str =~ s/~([\[\]])/$1/g;
57 delete $FILECAT->{$oldstr};
58 $FILECAT->{$str} = $entry;
61 # update all language dictionaries
62 foreach my $dict (@ARGV) {
63 $dict = "lib/RT/I18N/$dict.po" unless -f $dict or $dict =~ m!/!;
73 # {{{ pull strings out of the code.
75 sub extract_strings_from_code {
80 return if ( $File::Find::dir =~ 'lib/blib|lib/t/autogen|var|m4|local' );
81 return if ( /\.po$|\.bak$|~|,D|,B$|extract-message-catalog$/ );
82 return if ( /^[\.#]/ );
83 return if ( -f "$_.in" );
85 print "Looking at $File::Find::name\n";
86 my $filename = $File::Find::name;
87 $filename =~ s'^\./'';
88 $filename =~ s'\.in$'';
90 unless (open _, $file) {
91 print "Cannot open $file for reading ($!), skipping.\n";
97 # Mason filter: <&|/l>...</&>
99 while (m!\G.*?<&\|/l(.*?)&>(.*?)</&>!sg) {
100 my ( $vars, $str ) = ( $1, $2 );
101 $line += ( () = ( $& =~ /\n/g ) ); # cryptocontext!
103 #print "STR IS $str\n";
104 push @{ $FILECAT->{$str} }, [ $filename, $line, $vars ];
107 # Localization function: loc(...)
110 while (m/\G.*?\bloc$RE{balanced}{-parens=>'()'}{-keep}/sg) {
112 $line += ( () = ( $& =~ /\n/g ) ); # cryptocontext!
116 /\(\s*($RE{delimited}{-delim=>q{'"}}{-keep})(.*?)\s*\)$/ ) {
118 $str = substr( $1, 1, -1 ); # $str comes before $vars now
125 $vars =~ s/[\n\r]//g;
128 push @{ $FILECAT->{$str} }, [ $filename, $line, $vars ];
131 # Comment-based mark: "..." # loc
134 while (m/\G.*?($RE{delimited}{-delim=>q{'"}}{-keep})[\}\)\],]*\s*\#\s*loc\s*$/smg) {
135 my $str = substr($1, 1, -1);
136 $line += ( () = ( $& =~ /\n/g ) ); # cryptocontext!
138 push @{ $FILECAT->{$str} }, [ $filename, $line, '' ];
141 # Comment-based pair mark: "..." => "..." # loc_pair
144 while (m/\G.*?(\w+)\s*=>\s*($RE{delimited}{-delim=>q{'"}}{-keep})[\}\)\],]*\s*\#\s*loc_pair\s*$/smg) {
146 my $val = substr($2, 1, -1);
147 $line += ( () = ( $& =~ /\n/g ) ); # cryptocontext!
150 push @{ $FILECAT->{$key} }, [ $filename, $line, '' ];
151 push @{ $FILECAT->{$val} }, [ $filename, $line, '' ];
156 # }}} extract from strings
161 my ( %Lexicon, %Header);
164 unless (!-e $file or -w $file) {
165 warn "Can't write to $lang, skipping...\n";
169 print "Updating $lang...\n";
172 @lines = (<LEXICON>) if open (LEXICON, $file);
173 @lines = grep { !/^(#(:|\.)\s*|$)/ } @lines;
176 $msghdr .= shift @lines while ( $lines[0] && $lines[0] !~ /^msgid/ );
177 my $msgid = shift @lines;
179 $msgstr .= shift @lines while ( $lines[0] && $lines[0] =~ /^(msgstr|")/ );
185 $msgid =~ s/^msgid "(.*)"$/$1/ or warn $msgid;
186 $msgstr =~ s/^msgstr "(.*)"$/$1/ms or warn $msgstr;
188 $Lexicon{$msgid} = $msgstr;
189 $Header{$msgid} = $msghdr;
192 my $is_english = ( $lang =~ /^en(?:[^A-Za-z]|$)/ );
194 foreach my $str ( sort keys %{$FILECAT} ) {
195 $Lexicon{$str} ||= '';;
197 foreach ( sort keys %Lexicon ) {
198 my $f = join ( ' ', sort map $_->[0].":".$_->[1], @{ $FILECAT->{$_} } );
202 if ( !$Lexicon{$_} and $Lexicon{$nospace} ) {
204 $Lexicon{$nospace} . ( ' ' x ( length($_) - length($nospace) ) );
207 next if !length( $Lexicon{$_} ) and $is_english;
210 $out .= $Header{$_} if exists $Header{$_};
211 if ( $f && $f !~ /^\s+$/ ) {
216 $out .= "#: NOT FOUND IN SOURCE\n";
218 foreach my $entry ( grep { $_->[2] } @{ $FILECAT->{$_} } ) {
219 my ( $file, $line, $var ) = @{$entry};
220 $var =~ s/^\s*,\s*//;
222 $out .= "#. ($var)\n" unless $seen{$var}++;
224 $out .= "msgid \"$_\"\nmsgstr \"$Lexicon{$_}\"\n\n";
227 open PO, ">$file" or die $!;
236 $text =~ s/\b_(\d+)/%$1/;
242 # c-indentation-style: bsd
244 # indent-tabs-mode: nil
246 # vim: expandtab shiftwidth=4: