summaryrefslogtreecommitdiff
path: root/tools/genlang2
diff options
context:
space:
mode:
Diffstat (limited to 'tools/genlang2')
-rwxr-xr-xtools/genlang2365
1 files changed, 296 insertions, 69 deletions
diff --git a/tools/genlang2 b/tools/genlang2
index 400b915482..7d363d4cf7 100755
--- a/tools/genlang2
+++ b/tools/genlang2
@@ -10,27 +10,84 @@
10# Copyright (C) 2006 by Daniel Stenberg 10# Copyright (C) 2006 by Daniel Stenberg
11# 11#
12 12
13# binary version for the binary lang file
14my $langversion = 2; # 2 is the latest one used in the v1 format
15
16# A note for future users and readers: The original v1 language system allowed
17# the build to create and use a different language than english built-in. We
18# removed that feature from our build-system, but the build scripts still had
19# the ability. But, starting now, this ability is no longer provided since I
20# figured it was boring and unnecessary to write support for now since we
21# don't use it anymore.
22
13if(!$ARGV[0]) { 23if(!$ARGV[0]) {
14 print <<MOO 24 print <<MOO
15Usage: genlang2 [-p=<prefix>][-t=<target>][-v] <language file> 25Usage: genlang2 [options] <langv2 file>
26
27 -p=<prefix>
28 Make the tool create a [prefix].c and [prefix].h file.
16 29
17<prefix>.h and <prefix>.c will be created in the current directory. <prefix> 30 -b=<outfile>
18is "lang" by default. 31 Make the tool create a binary language (.lng) file namaed [outfile].
32 The use of this option requires that you also use -e.
19 33
20Use -v for verbose (debug) output. 34 -u
35 Update language file. Given the translated file and the most recent english
36 file, you\'ll get an updated version sent to stdout. Suitable action to do
37 when you intend to update a translation.
21 38
39 -e=<english lang file>
40 Point out the english (original source) file, to use that as master
41 language template. Used in combination with -b or -u.
42
43 -t=<target>
44 Specify which target you want the translations/phrases for. Required when
45 -b or -p is used.
46
47 -v
48 Enables verbose (debug) output.
22MOO 49MOO
23; 50;
24 exit; 51 exit;
25} 52}
26 53
54# How update works:
55#
56# 1) scan the english file, keep the whole <phrase> for each phrase.
57# 2) read the translated file, for each end of phrase, compare:
58# A) all source strings, if there's any change there should be a comment about
59# it output
60# B) the desc fields
61#
62# 3) output the phrase with the comments from above
63# 4) check which phrases that the translated version didn't have, and spit out
64# the english version of those
65#
66
27my $prefix = $p; 67my $prefix = $p;
28if(!$prefix) { 68my $binary = $b;
29 $prefix="lang"; 69my $update = $u;
70
71my $english = $e;
72
73my $check = $binary?1:0 + $prefix?1:0 + $update?1:0;
74
75if($check > 1) {
76 print "Please use only one of -p, -u and -b\n";
77 exit;
78}
79if(!$check) {
80 print "Please use at least one of -p, -u and -b\n";
81 exit;
82}
83if(($binary || $update) && !$english) {
84 print "Please use -e too when you use -b or -u\n";
85 exit;
30} 86}
87
31my $target = $t; 88my $target = $t;
32if(!$target) { 89if(!$target && !$update) {
33 print "Please specify a target!\n"; 90 print "Please specify a target (with -t)!\n";
34 exit; 91 exit;
35} 92}
36my $verbose=$v; 93my $verbose=$v;
@@ -45,40 +102,6 @@ my %voice; # id string to voice phrase hash
45 102
46my $input = $ARGV[0]; 103my $input = $ARGV[0];
47 104
48open(HFILE, ">$prefix.h");
49open(CFILE, ">$prefix.c");
50
51print HFILE <<MOO
52/* This file was automatically generated using genlang2 */
53/*
54 * The str() macro/functions is how to access strings that might be
55 * translated. Use it like str(MACRO) and expect a string to be
56 * returned!
57 */
58#define str(x) language_strings[x]
59
60/* this is the array for holding the string pointers.
61 It will be initialized at runtime. */
62extern unsigned char *language_strings[];
63/* this contains the concatenation of all strings, separated by \\0 chars */
64extern const unsigned char language_builtin[];
65
66/* The enum below contains all available strings */
67enum {
68MOO
69 ;
70
71print CFILE <<MOO
72/* This file was automaticly generated using genlang2, the strings come
73 from "$input" */
74
75#include "$prefix.h"
76
77unsigned char *language_strings[LANG_LAST_INDEX_IN_ARRAY];
78const unsigned char language_builtin[] =
79MOO
80 ;
81
82my @m; 105my @m;
83my $m="blank"; 106my $m="blank";
84 107
@@ -140,29 +163,140 @@ sub voice {
140 parsetarget("voice", \$voice, @_); 163 parsetarget("voice", \$voice, @_);
141} 164}
142 165
143my $idcount; # counter for lang ID numbers 166my %english;
167if($english) {
168 # For the cases where the english file needs to be scanned/read, we do
169 # it before we read the translated file. For -b it isn't necessary, but for
170 # -u it is convenient.
171
172 my $idnum=0; # start with a true number
173 my %idmap;
174 open(ENG, "<$english") || die "can't open $english";
175 my @phrase;
176 my $id;
177 while(<ENG>) {
178
179 # get rid of DOS newlines
180 $_ =~ s/\r//g;
181
182 if($_ =~ /^ *\<phrase\>/) {
183 # this is the start of a phrase
184 }
185 elsif($_ =~ /^ *\<\/phrase\>/) {
186 # this is the end of a phrase, add it to the english hash
187 $english{$id}=join("", @phrase);
188 undef @phrase;
189 }
190 elsif($_ ne "\n") {
191 # gather everything related to this phrase
192 push @phrase, $_;
193 }
194
195 if($_ =~ /^ *id: ([^ \t\n]+)/i) {
196 $id=$1;
197 # Skip voice-only entries
198 if($id =~ /^VOICE_/) {
199 next;
200 }
201
202 # Assign an ID number to this entry
203 $idmap{$id}=$idnum;
204 $idnum++;
205 }
206 }
207 close(ENG);
208}
209
210# a function that compares the english phrase with the translated one.
211# compare source strings and desc
212sub compare {
213 my ($engref, $locref)=@_;
214 my ($edesc, $ldesc);
215 my ($esource, $lsource);
216 my $mode=0;
217
218 for my $l (@$engref) {
219 if($l =~ /^ *desc: (.*)/) {
220 $edesc=$1;
221 }
222 elsif($l =~ / *\<source\>/i) {
223 $mode=1;
224 }
225 elsif($mode) {
226 if($l =~ / *\<\/source\>/i) {
227 last;
228 }
229 $esource .= "$l\n";
230 }
231 }
232
233 $mode = 0;
234 for my $l (@$locref) {
235 if($l =~ /^ *desc: (.*)/) {
236 $ldesc=$1;
237 }
238 elsif($l =~ / *\<source\>/i) {
239 $mode=1;
240 }
241 elsif($mode) {
242 if($l =~ / *\<\/source\>/i) {
243 last;
244 }
245 $lsource .= "$l";
246 }
247 }
248
249 if($edesc ne $ldesc) {
250 print "### The 'desc' field differs from the english!\n";
251 }
252 if($esource ne $lsource) {
253 print "### The <source> section differs from the english!\n";
254 }
255}
256
257my $idcount; # counter for lang ID numbers
144my $voiceid=0x8000; # counter for voice-only ID numbers 258my $voiceid=0x8000; # counter for voice-only ID numbers
145 259
260#
261# Now start the scanning of the selected language string
262#
263
146open(LANG, "<$input"); 264open(LANG, "<$input");
265my @phrase;
147while(<LANG>) { 266while(<LANG>) {
267
148 $line++; 268 $line++;
149 if($_ =~ / *\#/) { 269
150 # comment
151 next;
152 }
153 # get rid of DOS newlines 270 # get rid of DOS newlines
154 $_ =~ s/\r//g; 271 $_ =~ s/\r//g;
155 272
273 if($_ =~ /^( *\#|[ \t\n\r]*\z)/) {
274 # comment or empty line
275 next;
276 }
277
278 my $ll = $_;
279
156 # print "M: $m\n"; 280 # print "M: $m\n";
157 281
282 push @phrase, $ll;
283
284 # this is an XML-lookalike tag
158 if(/ *<([^>]*)>/) { 285 if(/ *<([^>]*)>/) {
159 my $part = $1; 286 my $part = $1;
160 #print "P: $part\n"; 287 #print "P: $part\n";
288
161 if($part =~ /^\//) { 289 if($part =~ /^\//) {
290 # this was a closing tag
291
162 if($part eq "/phrase") { 292 if($part eq "/phrase") {
293 # closing the phrase
294
163 my $idstr = $phrase{'id'}; 295 my $idstr = $phrase{'id'};
164 my $idnum; 296 my $idnum;
165 297
298 # Use the ID name to figure out which id number range we should
299 # use for this phrase. Voice-only strings are separated.
166 if($idstr =~ /^VOICE/) { 300 if($idstr =~ /^VOICE/) {
167 $idnum = $voiceid++; 301 $idnum = $voiceid++;
168 } 302 }
@@ -188,13 +322,39 @@ while(<LANG>) {
188 undef $dest; 322 undef $dest;
189 undef $voice; 323 undef $voice;
190 undef %phrase; 324 undef %phrase;
191 } 325
326 if($update) {
327 my $e = $english{$idstr};
328
329 if($e) {
330 # compare original english with this!
331 my @eng = split("\n", $english{$idstr});
332
333 compare(\@eng, \@phrase);
334 }
335 else {
336 print "### This phrase is not used, remove it!\n";
337 }
338 }
339 undef @phrase;
340
341 } # end of </phrase>
342
192 # starts with a slash, this _ends_ this section 343 # starts with a slash, this _ends_ this section
193 $m = pop @m; # get back old value 344 $m = pop @m; # get back old value, the previous level's tag
345 if($update) {
346 print "$ll";
347 }
194 next; 348 next;
195 } 349 } # end of tag close
350
351 # This is an opening (sub) tag
352
196 push @m, $m; # store old value 353 push @m, $m; # store old value
197 $m = $1; 354 $m = $1;
355 if($update) {
356 print "$ll";
357 }
198 next; 358 next;
199 } 359 }
200 360
@@ -202,11 +362,51 @@ while(<LANG>) {
202 my ($name, $val)=($1, $2); 362 my ($name, $val)=($1, $2);
203 &$m($_, $name, $val); 363 &$m($_, $name, $val);
204 } 364 }
205 365 if($update) {
366 print "$ll";
367 }
368
206} 369}
207close(LANG); 370close(LANG);
208 371
209# Output the ID names for the enum in the header file 372if($prefix) {
373 # We create a .c and .h file
374
375 open(HFILE, ">$prefix.h");
376 open(CFILE, ">$prefix.c");
377
378 print HFILE <<MOO
379/* This file was automatically generated using genlang2 */
380/*
381 * The str() macro/functions is how to access strings that might be
382 * translated. Use it like str(MACRO) and expect a string to be
383 * returned!
384 */
385#define str(x) language_strings[x]
386
387/* this is the array for holding the string pointers.
388 It will be initialized at runtime. */
389extern unsigned char *language_strings[];
390/* this contains the concatenation of all strings, separated by \\0 chars */
391extern const unsigned char language_builtin[];
392
393/* The enum below contains all available strings */
394enum {
395MOO
396 ;
397
398print CFILE <<MOO
399/* This file was automaticly generated using genlang2, the strings come
400 from "$input" */
401
402#include "$prefix.h"
403
404unsigned char *language_strings[LANG_LAST_INDEX_IN_ARRAY];
405const unsigned char language_builtin[] =
406MOO
407 ;
408
409 # Output the ID names for the enum in the header file
210my $i; 410my $i;
211for $i (1 .. $idcount) { 411for $i (1 .. $idcount) {
212 my $name=$idnum[$i - 1]; # get the ID name 412 my $name=$idnum[$i - 1]; # get the ID name
@@ -235,23 +435,18 @@ for $i (0x8000 .. ($voiceid-1)) {
235 printf HFILE (" %s,\n", $name); 435 printf HFILE (" %s,\n", $name);
236} 436}
237 437
238
239# Output end of enum 438# Output end of enum
240print HFILE <<MOO 439 print HFILE "\n};\n/* end of generated enum list */\n";
241};
242/* end of generated enum list */
243MOO
244 ;
245 440
246# Output the target phrases for the source file 441 # Output the target phrases for the source file
247for $i (1 .. $idcount) { 442 for $i (1 .. $idcount) {
248 my $name=$idnum[$i - 1]; # get the ID 443 my $name=$idnum[$i - 1]; # get the ID
249 my $dest = $dest{$name}; # get the destination phrase 444 my $dest = $dest{$name}; # get the destination phrase
250 445
251 $dest =~ s:\"$:\\0\":; # insert a \0 before the second quote 446 $dest =~ s:\"$:\\0\":; # insert a \0 before the second quote
252 447
253 printf CFILE (" %s\n", $dest); 448 printf CFILE (" %s\n", $dest);
254} 449 }
255 450
256# Output end of string chunk 451# Output end of string chunk
257print CFILE <<MOO 452print CFILE <<MOO
@@ -260,8 +455,40 @@ print CFILE <<MOO
260MOO 455MOO
261 ; 456 ;
262 457
263close(HFILE); 458 close(HFILE);
264close(CFILE); 459 close(CFILE);
460} # end of the c/h file generation
461elsif($binary) {
462 # Creation of a binary lang file was requested
463
464 # We must first scan the english file to get the correct order of the id
465 # numbers used there, as that is what sets the id order for all language
466 # files. The english file is scanned before the translated file was
467 # scanned.
468
469 open(OUTF, ">$binary") or die "Can't create $binary";
470 binmode OUTF;
471 printf OUTF ("\x1a%c", $langversion); # magic lang file header
472
473 # loop over the target phrases
474 for $i (1 .. $idcount) {
475 my $name=$idnum[$i - 1]; # get the ID
476 my $dest = $dest{$name}; # get the destination phrase
477
478 if($dest) {
479 $dest =~ s/^\"(.*)\"\s*$/$1/g; # cut off quotes
480
481 # Now, make sure we get the number from the english sort order:
482 $idnum = $idmap{$name};
483
484 printf OUTF ("%c%c%s\x00", ($idnum>>8), ($idnum&0xff), $dest);
485 if($debug) {
486 printf("%02x => %s\n", $idnum, $value);
487 }
488 }
489 }
490}
491
265 492
266if($verbose) { 493if($verbose) {
267 printf("%d ID strings scanned\n", $idcount); 494 printf("%d ID strings scanned\n", $idcount);