diff options
author | Daniel Stenberg <daniel@haxx.se> | 2006-04-03 21:11:11 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2006-04-03 21:11:11 +0000 |
commit | c06e7772ff81ed4bbc78377a6e16456456f3e96c (patch) | |
tree | 0eee2026f47d5041461d2a35349f0c2175e97ab0 /tools/genlang2 | |
parent | a87203651e35f368bf1d8bca5a846a0b9fb657c1 (diff) | |
download | rockbox-c06e7772ff81ed4bbc78377a6e16456456f3e96c.tar.gz rockbox-c06e7772ff81ed4bbc78377a6e16456456f3e96c.zip |
langv2
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9470 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'tools/genlang2')
-rwxr-xr-x | tools/genlang2 | 595 |
1 files changed, 0 insertions, 595 deletions
diff --git a/tools/genlang2 b/tools/genlang2 deleted file mode 100755 index 07c866a288..0000000000 --- a/tools/genlang2 +++ /dev/null | |||
@@ -1,595 +0,0 @@ | |||
1 | #!/usr/bin/perl -s | ||
2 | # __________ __ ___. | ||
3 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | # \/ \/ \/ \/ \/ | ||
8 | # $Id$ | ||
9 | # | ||
10 | # Copyright (C) 2006 by Daniel Stenberg | ||
11 | # | ||
12 | |||
13 | # binary version for the binary lang file | ||
14 | my $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 | |||
23 | if(!$ARGV[0]) { | ||
24 | print <<MOO | ||
25 | Usage: genlang2 [options] <langv2 file> | ||
26 | |||
27 | -p=<prefix> | ||
28 | Make the tool create a [prefix].c and [prefix].h file. | ||
29 | |||
30 | -b=<outfile> | ||
31 | Make the tool create a binary language (.lng) file namaed [outfile]. | ||
32 | The use of this option requires that you also use -e. | ||
33 | |||
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. | ||
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 | -o | ||
48 | Voice mode output. Outputs all id: and voice: lines for the given target! | ||
49 | |||
50 | -v | ||
51 | Enables verbose (debug) output. | ||
52 | MOO | ||
53 | ; | ||
54 | exit; | ||
55 | } | ||
56 | |||
57 | # How update works: | ||
58 | # | ||
59 | # 1) scan the english file, keep the whole <phrase> for each phrase. | ||
60 | # 2) read the translated file, for each end of phrase, compare: | ||
61 | # A) all source strings, if there's any change there should be a comment about | ||
62 | # it output | ||
63 | # B) the desc fields | ||
64 | # | ||
65 | # 3) output the phrase with the comments from above | ||
66 | # 4) check which phrases that the translated version didn't have, and spit out | ||
67 | # the english version of those | ||
68 | # | ||
69 | |||
70 | my $prefix = $p; | ||
71 | my $binary = $b; | ||
72 | my $update = $u; | ||
73 | |||
74 | my $english = $e; | ||
75 | my $voiceout = $o; | ||
76 | |||
77 | my $check = ($binary?1:0) + ($prefix?1:0) + ($update?1:0) + ($voiceout?1:0); | ||
78 | |||
79 | if($check > 1) { | ||
80 | print "Please use only one of -p, -u, -o and -b\n"; | ||
81 | exit; | ||
82 | } | ||
83 | if(!$check) { | ||
84 | print "Please use at least one of -p, -u, -o and -b\n"; | ||
85 | exit; | ||
86 | } | ||
87 | if(($binary || $update || $voiceout) && !$english) { | ||
88 | print "Please use -e too when you use -b, -o or -u\n"; | ||
89 | exit; | ||
90 | } | ||
91 | |||
92 | my $target = $t; | ||
93 | if(!$target && !$update) { | ||
94 | print "Please specify a target (with -t)!\n"; | ||
95 | exit; | ||
96 | } | ||
97 | my $verbose=$v; | ||
98 | |||
99 | my %id; # string to num hash | ||
100 | my @idnum; # num to string array | ||
101 | |||
102 | my %source; # id string to source phrase hash | ||
103 | my %dest; # id string to dest phrase hash | ||
104 | my %voice; # id string to voice phrase hash | ||
105 | |||
106 | my $input = $ARGV[0]; | ||
107 | |||
108 | my @m; | ||
109 | my $m="blank"; | ||
110 | |||
111 | sub match { | ||
112 | my ($string, $pattern)=@_; | ||
113 | |||
114 | $pattern =~ s/\*/.?*/g; | ||
115 | $pattern =~ s/\?/./g; | ||
116 | |||
117 | return ($string =~ $pattern); | ||
118 | } | ||
119 | |||
120 | sub blank { | ||
121 | # nothing to do | ||
122 | } | ||
123 | |||
124 | my %head; | ||
125 | sub header { | ||
126 | my ($full, $n, $v)=@_; | ||
127 | $head{$n}=$v; | ||
128 | } | ||
129 | |||
130 | my %phrase; | ||
131 | sub phrase { | ||
132 | my ($full, $n, $v)=@_; | ||
133 | $phrase{$n}=$v; | ||
134 | } | ||
135 | |||
136 | sub parsetarget { | ||
137 | my ($debug, $strref, $full, $n, $v)=@_; | ||
138 | my $string; | ||
139 | my @all= split(" *, *", $n); | ||
140 | my $test; | ||
141 | for $test (@all) { | ||
142 | # print "TEST ($debug) $target for $test\n"; | ||
143 | if(match($target, $test)) { | ||
144 | $string = $v; | ||
145 | # print "MATCH: $test => $v\n"; | ||
146 | } | ||
147 | } | ||
148 | if($string) { | ||
149 | $$strref = $string; | ||
150 | } | ||
151 | return $string; | ||
152 | } | ||
153 | |||
154 | my $src; | ||
155 | sub source { | ||
156 | parsetarget("src", \$src, @_); | ||
157 | } | ||
158 | |||
159 | my $dest; | ||
160 | sub dest { | ||
161 | parsetarget("dest", \$dest, @_); | ||
162 | } | ||
163 | |||
164 | my $voice; | ||
165 | sub voice { | ||
166 | parsetarget("voice", \$voice, @_); | ||
167 | } | ||
168 | |||
169 | my %idmap; | ||
170 | my %english; | ||
171 | if($english) { | ||
172 | # For the cases where the english file needs to be scanned/read, we do | ||
173 | # it before we read the translated file. For -b it isn't necessary, but for | ||
174 | # -u it is convenient. | ||
175 | |||
176 | my $idnum=0; # start with a true number | ||
177 | my $vidnum=0x8000; # first voice id | ||
178 | open(ENG, "<$english") || die "can't open $english"; | ||
179 | my @phrase; | ||
180 | my $id; | ||
181 | while(<ENG>) { | ||
182 | |||
183 | # get rid of DOS newlines | ||
184 | $_ =~ s/\r//g; | ||
185 | |||
186 | if($_ =~ /^ *\<phrase\>/) { | ||
187 | # this is the start of a phrase | ||
188 | } | ||
189 | elsif($_ =~ /^ *\<\/phrase\>/) { | ||
190 | # this is the end of a phrase, add it to the english hash | ||
191 | $english{$id}=join("", @phrase); | ||
192 | undef @phrase; | ||
193 | } | ||
194 | elsif($_ ne "\n") { | ||
195 | # gather everything related to this phrase | ||
196 | push @phrase, $_; | ||
197 | } | ||
198 | |||
199 | if($_ =~ /^ *id: ([^ \t\n]+)/i) { | ||
200 | $id=$1; | ||
201 | # voice-only entries get a difference range | ||
202 | if($id =~ /^VOICE_/) { | ||
203 | # Assign an ID number to this entry | ||
204 | $idmap{$id}=$vidnum; | ||
205 | $vidnum++; | ||
206 | } | ||
207 | else { | ||
208 | # Assign an ID number to this entry | ||
209 | $idmap{$id}=$idnum; | ||
210 | $idnum++; | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | close(ENG); | ||
215 | } | ||
216 | |||
217 | # a function that compares the english phrase with the translated one. | ||
218 | # compare source strings and desc | ||
219 | |||
220 | # Then output the updated version! | ||
221 | sub compare { | ||
222 | my ($idstr, $engref, $locref)=@_; | ||
223 | my ($edesc, $ldesc); | ||
224 | my ($esource, $lsource); | ||
225 | my $mode=0; | ||
226 | |||
227 | for my $l (@$engref) { | ||
228 | if($l =~ /^ *desc: (.*)/) { | ||
229 | $edesc=$1; | ||
230 | } | ||
231 | elsif($l =~ / *\<source\>/i) { | ||
232 | $mode=1; | ||
233 | } | ||
234 | elsif($mode) { | ||
235 | if($l =~ / *\<\/source\>/i) { | ||
236 | last; | ||
237 | } | ||
238 | $esource .= "$l\n"; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | my @show; | ||
243 | my @source; | ||
244 | |||
245 | $mode = 0; | ||
246 | for my $l (@$locref) { | ||
247 | if($l =~ /^ *desc: (.*)/) { | ||
248 | $ldesc=$1; | ||
249 | if($edesc ne $ldesc) { | ||
250 | $l = "### The 'desc' field differs from the english!\n### the previously used desc is commented below:\n### desc: $ldesc\n desc: $edesc\n"; | ||
251 | } | ||
252 | push @show, $l; | ||
253 | } | ||
254 | elsif($l =~ / *\<source\>/i) { | ||
255 | $mode=1; | ||
256 | push @show, $l; | ||
257 | } | ||
258 | elsif($mode) { | ||
259 | if($l =~ / *\<\/source\>/i) { | ||
260 | $mode = 0; | ||
261 | print @show; | ||
262 | if($esource ne $lsource) { | ||
263 | print "### The <source> section differs from the english!\n", | ||
264 | "### the previously used one is commented below:\n"; | ||
265 | for(split("\n", $lsource)) { | ||
266 | print "### $_\n"; | ||
267 | } | ||
268 | print $esource; | ||
269 | } | ||
270 | else { | ||
271 | print $lsource; | ||
272 | } | ||
273 | undef @show; # start over | ||
274 | |||
275 | push @show, $l; | ||
276 | } | ||
277 | else { | ||
278 | $lsource .= "$l"; | ||
279 | } | ||
280 | } | ||
281 | else { | ||
282 | push @show, $l; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | |||
287 | print @show; | ||
288 | } | ||
289 | |||
290 | my $idcount; # counter for lang ID numbers | ||
291 | my $voiceid=0x8000; # counter for voice-only ID numbers | ||
292 | |||
293 | # | ||
294 | # Now start the scanning of the selected language string | ||
295 | # | ||
296 | |||
297 | open(LANG, "<$input"); | ||
298 | my @phrase; | ||
299 | while(<LANG>) { | ||
300 | |||
301 | $line++; | ||
302 | |||
303 | # get rid of DOS newlines | ||
304 | $_ =~ s/\r//g; | ||
305 | |||
306 | if($_ =~ /^( *\#|[ \t\n\r]*\z)/) { | ||
307 | # comment or empty line | ||
308 | next; | ||
309 | } | ||
310 | |||
311 | my $ll = $_; | ||
312 | |||
313 | # print "M: $m\n"; | ||
314 | |||
315 | push @phrase, $ll; | ||
316 | |||
317 | # this is an XML-lookalike tag | ||
318 | if(/ *<([^>]*)>/) { | ||
319 | my $part = $1; | ||
320 | #print "P: $part\n"; | ||
321 | |||
322 | if($part =~ /^\//) { | ||
323 | # this was a closing tag | ||
324 | |||
325 | if($part eq "/phrase") { | ||
326 | # closing the phrase | ||
327 | |||
328 | my $idstr = $phrase{'id'}; | ||
329 | my $idnum; | ||
330 | |||
331 | if($dest =~ /^none\z/i) { | ||
332 | # "none" as dest means that this entire phrase is to be | ||
333 | # ignored | ||
334 | #print "dest is NONE!\n"; | ||
335 | } | ||
336 | else { | ||
337 | |||
338 | # Use the ID name to figure out which id number range we | ||
339 | # should use for this phrase. Voice-only strings are | ||
340 | # separated. | ||
341 | |||
342 | if($idstr =~ /^VOICE/) { | ||
343 | $idnum = $voiceid++; | ||
344 | } | ||
345 | else { | ||
346 | $idnum = $idcount++; | ||
347 | } | ||
348 | |||
349 | $id{$idstr} = $idnum; | ||
350 | $idnum[$idnum]=$idstr; | ||
351 | |||
352 | $source{$idstr}=$src; | ||
353 | $dest{$idstr}=$dest; | ||
354 | $voice{$idstr}=$voice; | ||
355 | |||
356 | if($verbose) { | ||
357 | print "id: $phrase{id} ($idnum)\n"; | ||
358 | print "source: $src\n"; | ||
359 | print "dest: $dest\n"; | ||
360 | print "voice: $voice\n"; | ||
361 | } | ||
362 | |||
363 | undef $src; | ||
364 | undef $dest; | ||
365 | undef $voice; | ||
366 | undef %phrase; | ||
367 | } | ||
368 | |||
369 | if($update) { | ||
370 | my $e = $english{$idstr}; | ||
371 | |||
372 | if($e) { | ||
373 | # compare original english with this! | ||
374 | my @eng = split("\n", $english{$idstr}); | ||
375 | |||
376 | compare($idstr, \@eng, \@phrase); | ||
377 | |||
378 | $english{$idstr}=""; # clear it | ||
379 | } | ||
380 | else { | ||
381 | print "### $idstr: The phrase is not used. Skipped\n"; | ||
382 | } | ||
383 | } | ||
384 | undef @phrase; | ||
385 | |||
386 | } # end of </phrase> | ||
387 | |||
388 | # starts with a slash, this _ends_ this section | ||
389 | $m = pop @m; # get back old value, the previous level's tag | ||
390 | next; | ||
391 | } # end of tag close | ||
392 | |||
393 | # This is an opening (sub) tag | ||
394 | |||
395 | push @m, $m; # store old value | ||
396 | $m = $1; | ||
397 | next; | ||
398 | } | ||
399 | |||
400 | if(/^ *([^:]+): *(.*)/) { | ||
401 | my ($name, $val)=($1, $2); | ||
402 | &$m($_, $name, $val); | ||
403 | } | ||
404 | } | ||
405 | close(LANG); | ||
406 | |||
407 | if($update) { | ||
408 | my $any=0; | ||
409 | for(keys %english) { | ||
410 | if($english{$_}) { | ||
411 | print "###\n", | ||
412 | "### This phrase below was not present in the translated file\n", | ||
413 | "<phrase>\n"; | ||
414 | print $english{$_}; | ||
415 | print "</phrase>\n"; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | |||
420 | if($prefix) { | ||
421 | # We create a .c and .h file | ||
422 | |||
423 | open(HFILE, ">$prefix.h"); | ||
424 | open(CFILE, ">$prefix.c"); | ||
425 | |||
426 | print HFILE <<MOO | ||
427 | /* This file was automatically generated using genlang2 */ | ||
428 | /* | ||
429 | * The str() macro/functions is how to access strings that might be | ||
430 | * translated. Use it like str(MACRO) and expect a string to be | ||
431 | * returned! | ||
432 | */ | ||
433 | #define str(x) language_strings[x] | ||
434 | |||
435 | /* this is the array for holding the string pointers. | ||
436 | It will be initialized at runtime. */ | ||
437 | extern unsigned char *language_strings[]; | ||
438 | /* this contains the concatenation of all strings, separated by \\0 chars */ | ||
439 | extern const unsigned char language_builtin[]; | ||
440 | |||
441 | /* The enum below contains all available strings */ | ||
442 | enum \{ | ||
443 | MOO | ||
444 | ; | ||
445 | |||
446 | print CFILE <<MOO | ||
447 | /* This file was automaticly generated using genlang2, the strings come | ||
448 | from "$input" */ | ||
449 | |||
450 | #include "$prefix.h" | ||
451 | |||
452 | unsigned char *language_strings[LANG_LAST_INDEX_IN_ARRAY]; | ||
453 | const unsigned char language_builtin[] = | ||
454 | MOO | ||
455 | ; | ||
456 | |||
457 | # Output the ID names for the enum in the header file | ||
458 | my $i; | ||
459 | for $i (1 .. $idcount) { | ||
460 | my $name=$idnum[$i - 1]; # get the ID name | ||
461 | |||
462 | $name =~ s/\"//g; # cut off the quotes | ||
463 | |||
464 | printf HFILE (" %s,\n", $name); | ||
465 | } | ||
466 | |||
467 | # Output separation marker for last string ID and the upcoming voice IDs | ||
468 | |||
469 | print HFILE <<MOO | ||
470 | LANG_LAST_INDEX_IN_ARRAY, /* this is not a string, this is a marker */ | ||
471 | /* --- below this follows voice-only strings --- */ | ||
472 | VOICEONLY_DELIMITER = 0x8000, | ||
473 | MOO | ||
474 | ; | ||
475 | |||
476 | # Output the ID names for the enum in the header file | ||
477 | my $i; | ||
478 | for $i (0x8000 .. ($voiceid-1)) { | ||
479 | my $name=$idnum[$i]; # get the ID name | ||
480 | |||
481 | $name =~ s/\"//g; # cut off the quotes | ||
482 | |||
483 | printf HFILE (" %s,\n", $name); | ||
484 | } | ||
485 | |||
486 | # Output end of enum | ||
487 | print HFILE "\n};\n/* end of generated enum list */\n"; | ||
488 | |||
489 | # Output the target phrases for the source file | ||
490 | for $i (1 .. $idcount) { | ||
491 | my $name=$idnum[$i - 1]; # get the ID | ||
492 | my $dest = $dest{$name}; # get the destination phrase | ||
493 | |||
494 | $dest =~ s:\"$:\\0\":; # insert a \0 before the second quote | ||
495 | |||
496 | if(!$dest) { | ||
497 | # this is just to be on the safe side | ||
498 | $dest = '"\0"'; | ||
499 | } | ||
500 | |||
501 | printf CFILE (" %s\n", $dest); | ||
502 | } | ||
503 | |||
504 | # Output end of string chunk | ||
505 | print CFILE <<MOO | ||
506 | ; | ||
507 | /* end of generated string list */ | ||
508 | MOO | ||
509 | ; | ||
510 | |||
511 | close(HFILE); | ||
512 | close(CFILE); | ||
513 | } # end of the c/h file generation | ||
514 | elsif($binary) { | ||
515 | # Creation of a binary lang file was requested | ||
516 | |||
517 | # We must first scan the english file to get the correct order of the id | ||
518 | # numbers used there, as that is what sets the id order for all language | ||
519 | # files. The english file is scanned before the translated file was | ||
520 | # scanned. | ||
521 | |||
522 | open(OUTF, ">$binary") or die "Can't create $binary"; | ||
523 | binmode OUTF; | ||
524 | printf OUTF ("\x1a%c", $langversion); # magic lang file header | ||
525 | |||
526 | # loop over the target phrases | ||
527 | for $i (1 .. $idcount) { | ||
528 | my $name=$idnum[$i - 1]; # get the ID | ||
529 | my $dest = $dest{$name}; # get the destination phrase | ||
530 | |||
531 | if($dest) { | ||
532 | $dest =~ s/^\"(.*)\"\s*$/$1/g; # cut off quotes | ||
533 | |||
534 | # Now, make sure we get the number from the english sort order: | ||
535 | $idnum = $idmap{$name}; | ||
536 | |||
537 | printf OUTF ("%c%c%s\x00", ($idnum>>8), ($idnum&0xff), $dest); | ||
538 | if($debug) { | ||
539 | printf("%02x => %s\n", $idnum, $value); | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | elsif($voiceout) { | ||
545 | # voice output requested, display id: and voice: strings in a v1-like | ||
546 | # fashion | ||
547 | |||
548 | my @engl; | ||
549 | |||
550 | # This loops over the strings in the translated language file order | ||
551 | my @ids = ((0 .. ($idcount-1))); | ||
552 | push @ids, (0x8000 .. ($voiceid-1)); | ||
553 | |||
554 | #for my $id (@ids) { | ||
555 | # print "$id\n"; | ||
556 | #} | ||
557 | |||
558 | for $i (@ids) { | ||
559 | my $name=$idnum[$i]; # get the ID | ||
560 | my $dest = $voice{$name}; # get the destination voice string | ||
561 | |||
562 | if($dest) { | ||
563 | $dest =~ s/^\"(.*)\"\s*$/$1/g; # cut off quotes | ||
564 | |||
565 | # Now, make sure we get the number from the english sort order: | ||
566 | $idnum = $idmap{$name}; | ||
567 | |||
568 | $engl[$idnum] = $i; | ||
569 | |||
570 | # print "Input index $i output index $idnum\n"; | ||
571 | |||
572 | } | ||
573 | } | ||
574 | for my $i (@ids) { | ||
575 | |||
576 | my $o = $engl[$i]; | ||
577 | |||
578 | my $name=$idnum[$o]; # get the ID | ||
579 | my $dest = $voice{$name}; # get the destination voice string | ||
580 | |||
581 | print "#$i\nid: $name\nvoice: $dest\n"; | ||
582 | } | ||
583 | |||
584 | } | ||
585 | |||
586 | |||
587 | if($verbose) { | ||
588 | printf("%d ID strings scanned\n", $idcount); | ||
589 | |||
590 | print "* head *\n"; | ||
591 | for(keys %head) { | ||
592 | printf "$_: %s\n", $head{$_}; | ||
593 | } | ||
594 | } | ||
595 | |||