source: trunk/third/gnome-media/xml-i18n-merge.in @ 17496

Revision 17496, 11.0 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17495, which included commits to RCS files with non-trunk default branches.
Line 
1#!@XML_I18N_TOOLS_PERL@ -w
2
3#
4#  The XML Translation Merge Tool
5#
6#  Copyright (C) 2000 Free Software Foundation.
7#  Copyright (C) 2000, 2001 Eazel, Inc
8#
9#  This library is free software; you can redistribute it and/or
10#  modify it under the terms of the GNU General Public License as
11#  published by the Free Software Foundation; either version 2 of the
12#  License, or (at your option) any later version.
13#
14#  This script is distributed in the hope that it will be useful,
15#  but WITHOUT ANY WARRANTY; without even the implied warranty of
16#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17#  General Public License for more details.
18#
19#  You should have received a copy of the GNU General Public License
20#  along with this library; if not, write to the Free Software
21#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22#
23#  Authors:  Maciej Stachowiak <mjs@eazel.com>
24#            Kenneth Christiansen <kenneth@gnu.org>
25#            Darin Adler <darin@eazel.com>
26#
27
28
29## Release information
30my $PROGRAM      = "xml-i18n-merge";
31my $PACKAGE      = "xml-i18n-tools";
32my $VERSION      = "0.8.4";
33
34## Script options - Enable by setting value to 1
35my $ENABLE_XML   = "1";
36
37## Loaded modules
38use strict;
39use File::Basename;
40use Getopt::Long;
41
42## Scalars used by the option stuff
43my $HELP_ARG    = "0";
44my $VERSION_ARG = "0";
45my $OAF_STYLE_ARG = "0";
46my $XML_STYLE_ARG = "0";
47my $KEYS_STYLE_ARG = "0";
48my $DESKTOP_STYLE_ARG = "0";
49my $QUIET_ARG = "0";
50
51
52## Handle options
53GetOptions (
54            "help|h|?" => \$HELP_ARG,
55            "version|v" => \$VERSION_ARG,
56            "quiet|q" => \$QUIET_ARG,
57            "oaf-style|o" => \$OAF_STYLE_ARG,
58            "xml-style|x" => \$XML_STYLE_ARG,
59            "keys-style|k" => \$KEYS_STYLE_ARG,
60            "desktop-style|d" => \$DESKTOP_STYLE_ARG
61            ) or &error;
62
63
64my $PO_DIR;
65my $FILE;
66my $OUTFILE;
67
68my @languages;
69my %po_files_by_lang = ();
70my %translations = ();
71
72&split_on_argument;
73
74
75## Check for options.
76## This section will check for the different options.
77
78sub split_on_argument {
79
80    if ($VERSION_ARG) {
81        &version;
82
83    } elsif ($HELP_ARG) {
84        &help;
85    } elsif ($OAF_STYLE_ARG && @ARGV > 2) {
86        &place_normal;
87        &message;
88        &preparation;
89        &oaf_merge_translations;
90    } elsif ($XML_STYLE_ARG && @ARGV > 2) {
91        &place_normal;
92        &message;
93        &preparation;
94        &xml_merge_translations;
95    } elsif ($KEYS_STYLE_ARG && @ARGV > 2) {
96        &place_normal;
97        &message;
98        &preparation;
99        &keys_merge_translations;
100    } elsif ($DESKTOP_STYLE_ARG && @ARGV > 2) {
101        &place_normal;
102        &message;
103        &preparation;
104        &desktop_merge_translations;
105    } else {
106        &help;
107    } 
108}   
109
110
111sub place_normal {
112    $PO_DIR = $ARGV[0];
113    $FILE = $ARGV[1];
114    $OUTFILE = $ARGV[2];
115}   
116
117
118## Sub for printing release information
119sub version{
120    print "${PROGRAM} (${PACKAGE}) ${VERSION}\n";
121    print "Written by Maciej Stachowiak and Kenneth Christiansen, 2000.\n\n";
122    print "Copyright (C) 2000 Free Software Foundation, Inc.\n";
123    print "Copyright (C) 2000, 2001 Eazel, Inc.\n";
124    print "This is free software; see the source for copying conditions.  There is NO\n";
125    print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
126    exit;
127}
128
129## Sub for printing usage information
130sub help{
131    print "Usage: ${PROGRAM} [OPTIONS] PO_DIRECTORY FILENAME OUTPUT_FILE\n";
132    print "Generates an xml file that includes translated versions of some attributes,\n";
133    print "from an untranslated source and a po directory that includes translations.\n";
134    print "  -v, --version                shows the version\n";
135    print "  -h, --help                   shows this help page\n";
136    print "  -q, --quiet                  quiet mode\n";
137    print "  -o, --oaf-style              includes translations in the oaf style\n";
138    print "  -x, --xml-style              includes translations in the xml style\n";
139    print "  -k, --keys-style             includes translations in the keys style\n";
140    print "  -d, --desktop-style          includes translations in the desktop style\n";
141    print "\nReport bugs to <mjs\@eazel.com>.\n";
142    exit;
143}
144
145
146## Sub for printing error messages
147sub error{
148#   print "xml-i18n-merge: invalid option @ARGV\n";
149    print "Try `${PROGRAM} --help' for more information.\n";
150    exit;
151}
152
153
154sub message {
155    print "Merging translations into $OUTFILE.\n" unless $QUIET_ARG;
156}
157
158
159
160sub preparation {
161   &gather_po_files;
162   &create_translation_database;   
163}
164
165
166
167# General-purpose code for looking up translations in .po files
168
169sub gather_po_files
170{
171    my @po_files = glob("${PO_DIR}/*.po");
172
173    @languages = map (&po_file2lang, @po_files);
174
175    foreach my $lang (@languages) {
176        $po_files_by_lang{$lang} = shift (@po_files);
177    }
178}
179
180sub po_file2lang
181{
182    my $tmp = $_;
183    $tmp =~ s/^.*\/(.*)\.po$/$1/;
184    return $tmp;
185}
186
187
188sub create_translation_database
189{
190    foreach my $lang (@languages) {
191
192        my $po_file = $po_files_by_lang{$lang};
193
194        open PO_FILE, "<$po_file";     
195
196        while (<PO_FILE>) {
197            if (/^#,.*fuzzy/) {
198                $_ = <PO_FILE>; next;
199            }
200            if (/^msgid "(.*)"/ ) {
201                my $msgid = $1;
202                $_ = <PO_FILE>;
203               
204                if (/^msgstr "(.+)"/) {
205                    my $msgstr = $1;
206                    $translations{$lang . "|" . $msgid} = $msgstr;
207                    # print "[$lang]$msgstr\n";
208                }
209            }           
210        }
211    }
212}
213
214sub lookup_translations
215{
216    my ($value) = @_;
217 
218    my %transmap = ();
219
220    foreach my $lang (@languages) {
221        my $translation = lookup_translation ($value, $lang);
222           
223        if ($translation) {
224            $transmap{$lang} = $translation;
225        }
226    }
227
228    return %transmap;
229}
230
231
232sub lookup_translation
233{
234    my ($string, $lang) = @_;
235    $string =~ s/\+/\\+/g;
236 
237    my $salt = "$lang|$string";
238     
239    if ($translations{$salt}) {
240        return $translations{$salt};
241    }
242 
243    return "";
244}
245
246
247sub entity_encode_translations
248{
249    my %transmap = @_;
250
251    foreach my $key (keys %transmap) {
252        $transmap{$key} = entity_encode ($transmap{$key});
253    }
254
255    return %transmap;
256}
257
258
259sub entity_encode
260{
261    my ($pre_encoded) = @_;
262
263    $pre_encoded =~ s/\\(.)/$1/g;
264    my @list_of_chars = unpack ('C*', $pre_encoded);
265
266    return join ('', map (&entity_encode_int, @list_of_chars));
267}
268
269sub entity_encode_int
270{
271    if ($_ > 127 || $_ == 34 || $_ == 38) {
272        return "&#" . $_ . ";";
273    } else {
274        return chr $_;
275    }
276}
277
278
279## XML/OAF-specific merge code
280 
281sub oaf_merge_translations
282{
283    my $xml_source; {
284       local (*INPUT);
285       local $/; # slurp mode
286       open INPUT, "<$FILE" or die "can't open $FILE: $!";
287       $xml_source = <INPUT>;
288       close INPUT;
289    }
290
291    open OUTPUT, ">$OUTFILE";
292
293    while ($xml_source =~ /[ \t]*<[^<]*\s_\w+="[^"]*"[^<]*>/m) {
294        print OUTPUT $`;
295        my $orig_node = $&;
296        $xml_source = $';
297
298        my $non_translated_line = $orig_node;
299        $non_translated_line =~ s/_(\w+)="/$1="/;
300           
301        my $new_node = $non_translated_line;
302           
303        my $value_str = $orig_node;
304        $value_str =~ s/.*_\w+="([^"]*)".*/$1/s;
305
306        if ($value_str) {
307            my %value_translation_map = entity_encode_translations
308                (lookup_translations ($value_str));
309
310            foreach my $key (keys %value_translation_map) {
311                my $translation = $value_translation_map{$key};
312                   
313                my $translated_line = $orig_node;
314                $translated_line =~ s/name="([^"]*)"/name="$1-$key"/;
315                $translated_line =~ s/(\s*)_(\w+)="[^"]*"/$1$2="$translation"/;
316
317                $new_node .= "\n$translated_line";
318            }
319        }
320
321        $xml_source = $new_node . $xml_source;
322    }
323
324    print OUTPUT $xml_source;
325
326    close OUTPUT;
327}
328
329
330## XML (non-OAF) merge code
331 
332sub xml_merge_translations
333{
334    my $xml_source; {
335       local (*INPUT);
336       local $/; # slurp mode
337       open INPUT, "<$FILE" or die "can't open $FILE: $!";
338       $xml_source = <INPUT>;
339       close INPUT;
340    }
341
342    open OUTPUT, ">$OUTFILE";
343
344    # FIXME: support attribute translations
345
346    # First just unmark for translation all empty nodes
347    # for example <_foo/> is just replaced by <foo/>
348    $xml_source =~ s/<_(\w+)\/>/<$1\/>/mg;
349
350    # Support for XML <_foo>blah</_foo> style translations
351    while ($xml_source =~ /([ \t]*)<_(\w+)>([^<]+)<\/_\2>/m) {
352        print OUTPUT $`;
353        $xml_source = $';
354
355        my $spaces = $1;
356        my $tag_name = $2;
357        my $value_str = $3;
358
359        my $non_translated_line = "$spaces<$tag_name>$value_str</$tag_name>";
360           
361        my $new_node = $non_translated_line;
362
363        if ($value_str) {
364            my %value_translation_map = entity_encode_translations
365                (lookup_translations ($value_str));
366
367            foreach my $key (keys %value_translation_map) {
368                my $translation = $value_translation_map{$key};
369
370                $new_node .= "\n$spaces<$tag_name xml:lang=\"$key\">$translation</$tag_name>";
371            }
372        }
373
374        $xml_source = $new_node . $xml_source;
375    }
376
377    print OUTPUT $xml_source;
378
379    close OUTPUT;
380}
381
382sub keys_merge_translations
383{       
384    open INPUT, "<${FILE}";
385
386    open OUTPUT, ">${OUTFILE}";
387
388    while (<INPUT>) {
389        chomp;
390        if (/^\s*_\w+=.*/)  {
391            my $orig_line = $_;
392   
393            my $non_translated_line = $orig_line;
394            $non_translated_line =~ s/_([^="]*)=/$1=/;
395           
396            print OUTPUT "${non_translated_line}\n";
397           
398            my $value_str = $orig_line;
399            $value_str =~ s/.*_\w+=(.*)/$1/;
400           
401            if ($value_str) {
402                my %value_translation_map = lookup_translations ($value_str);
403           
404                foreach my $key (sort keys %value_translation_map) {
405                    my $translation = $value_translation_map{$key};
406
407                    my $translated_line = $orig_line; 
408                    $translated_line =~ s/_([^="]*)=([^\n]*)/\[$key]$1=$translation/;
409                    print OUTPUT "$translated_line\n";
410                }
411            }
412        } else {
413            print OUTPUT "$_\n";
414        }
415    }
416                 
417    close OUTPUT;
418    close INPUT;
419}
420
421sub desktop_merge_translations
422{
423    open INPUT, "<${FILE}";
424
425    open OUTPUT, ">${OUTFILE}";
426
427    while (<INPUT>) {
428        chomp;
429        if (/^\s*_\w+=.*/)  {
430            my $orig_line = $_;
431
432            my $non_translated_line = $orig_line;
433            $non_translated_line =~ s/_([^="]*)=/$1=/;
434
435            print OUTPUT "${non_translated_line}\n";
436
437            my $value_str = $orig_line;
438            $value_str =~ s/.*_\w+=(.*)/$1/;
439
440            if ($value_str) {
441                my %value_translation_map = lookup_translations ($value_str);
442
443                foreach my $key (sort keys %value_translation_map) {
444                    my $translation = $value_translation_map{$key};
445
446                    my $translated_line = $orig_line;
447                    $translated_line =~ s/^_([^="]*)=([^\n]*)/$1\[$key]=$translation/;
448                    print OUTPUT "$translated_line\n";
449                }
450            }
451        } else {
452            print OUTPUT "$_\n";
453        }
454    }
455
456    close OUTPUT;
457    close INPUT;
458
459}
Note: See TracBrowser for help on using the repository browser.