diff options
author | Daniel Stenberg <daniel@haxx.se> | 2006-03-25 22:05:28 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2006-03-25 22:05:28 +0000 |
commit | a07a833c61c9bc1e044c151601d814d71558fddc (patch) | |
tree | d6c61bdb2e854d645080497435a6fdafec9d937e /tools/genlang2 | |
parent | a70c6b9b1e2bcf7a5a207017d6c40f5254f6ef98 (diff) | |
download | rockbox-a07a833c61c9bc1e044c151601d814d71558fddc.tar.gz rockbox-a07a833c61c9bc1e044c151601d814d71558fddc.zip |
settingling on options and even uplang support starts to function
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9254 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'tools/genlang2')
-rwxr-xr-x | tools/genlang2 | 365 |
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 | ||
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 | |||
13 | if(!$ARGV[0]) { | 23 | if(!$ARGV[0]) { |
14 | print <<MOO | 24 | print <<MOO |
15 | Usage: genlang2 [-p=<prefix>][-t=<target>][-v] <language file> | 25 | Usage: 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> |
18 | is "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 | ||
20 | Use -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. | ||
22 | MOO | 49 | MOO |
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 | |||
27 | my $prefix = $p; | 67 | my $prefix = $p; |
28 | if(!$prefix) { | 68 | my $binary = $b; |
29 | $prefix="lang"; | 69 | my $update = $u; |
70 | |||
71 | my $english = $e; | ||
72 | |||
73 | my $check = $binary?1:0 + $prefix?1:0 + $update?1:0; | ||
74 | |||
75 | if($check > 1) { | ||
76 | print "Please use only one of -p, -u and -b\n"; | ||
77 | exit; | ||
78 | } | ||
79 | if(!$check) { | ||
80 | print "Please use at least one of -p, -u and -b\n"; | ||
81 | exit; | ||
82 | } | ||
83 | if(($binary || $update) && !$english) { | ||
84 | print "Please use -e too when you use -b or -u\n"; | ||
85 | exit; | ||
30 | } | 86 | } |
87 | |||
31 | my $target = $t; | 88 | my $target = $t; |
32 | if(!$target) { | 89 | if(!$target && !$update) { |
33 | print "Please specify a target!\n"; | 90 | print "Please specify a target (with -t)!\n"; |
34 | exit; | 91 | exit; |
35 | } | 92 | } |
36 | my $verbose=$v; | 93 | my $verbose=$v; |
@@ -45,40 +102,6 @@ my %voice; # id string to voice phrase hash | |||
45 | 102 | ||
46 | my $input = $ARGV[0]; | 103 | my $input = $ARGV[0]; |
47 | 104 | ||
48 | open(HFILE, ">$prefix.h"); | ||
49 | open(CFILE, ">$prefix.c"); | ||
50 | |||
51 | print 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. */ | ||
62 | extern unsigned char *language_strings[]; | ||
63 | /* this contains the concatenation of all strings, separated by \\0 chars */ | ||
64 | extern const unsigned char language_builtin[]; | ||
65 | |||
66 | /* The enum below contains all available strings */ | ||
67 | enum { | ||
68 | MOO | ||
69 | ; | ||
70 | |||
71 | print CFILE <<MOO | ||
72 | /* This file was automaticly generated using genlang2, the strings come | ||
73 | from "$input" */ | ||
74 | |||
75 | #include "$prefix.h" | ||
76 | |||
77 | unsigned char *language_strings[LANG_LAST_INDEX_IN_ARRAY]; | ||
78 | const unsigned char language_builtin[] = | ||
79 | MOO | ||
80 | ; | ||
81 | |||
82 | my @m; | 105 | my @m; |
83 | my $m="blank"; | 106 | my $m="blank"; |
84 | 107 | ||
@@ -140,29 +163,140 @@ sub voice { | |||
140 | parsetarget("voice", \$voice, @_); | 163 | parsetarget("voice", \$voice, @_); |
141 | } | 164 | } |
142 | 165 | ||
143 | my $idcount; # counter for lang ID numbers | 166 | my %english; |
167 | if($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 | ||
212 | sub 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 | |||
257 | my $idcount; # counter for lang ID numbers | ||
144 | my $voiceid=0x8000; # counter for voice-only ID numbers | 258 | my $voiceid=0x8000; # counter for voice-only ID numbers |
145 | 259 | ||
260 | # | ||
261 | # Now start the scanning of the selected language string | ||
262 | # | ||
263 | |||
146 | open(LANG, "<$input"); | 264 | open(LANG, "<$input"); |
265 | my @phrase; | ||
147 | while(<LANG>) { | 266 | while(<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 | } |
207 | close(LANG); | 370 | close(LANG); |
208 | 371 | ||
209 | # Output the ID names for the enum in the header file | 372 | if($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. */ | ||
389 | extern unsigned char *language_strings[]; | ||
390 | /* this contains the concatenation of all strings, separated by \\0 chars */ | ||
391 | extern const unsigned char language_builtin[]; | ||
392 | |||
393 | /* The enum below contains all available strings */ | ||
394 | enum { | ||
395 | MOO | ||
396 | ; | ||
397 | |||
398 | print CFILE <<MOO | ||
399 | /* This file was automaticly generated using genlang2, the strings come | ||
400 | from "$input" */ | ||
401 | |||
402 | #include "$prefix.h" | ||
403 | |||
404 | unsigned char *language_strings[LANG_LAST_INDEX_IN_ARRAY]; | ||
405 | const unsigned char language_builtin[] = | ||
406 | MOO | ||
407 | ; | ||
408 | |||
409 | # Output the ID names for the enum in the header file | ||
210 | my $i; | 410 | my $i; |
211 | for $i (1 .. $idcount) { | 411 | for $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 |
240 | print HFILE <<MOO | 439 | print HFILE "\n};\n/* end of generated enum list */\n"; |
241 | }; | ||
242 | /* end of generated enum list */ | ||
243 | MOO | ||
244 | ; | ||
245 | 440 | ||
246 | # Output the target phrases for the source file | 441 | # Output the target phrases for the source file |
247 | for $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 |
257 | print CFILE <<MOO | 452 | print CFILE <<MOO |
@@ -260,8 +455,40 @@ print CFILE <<MOO | |||
260 | MOO | 455 | MOO |
261 | ; | 456 | ; |
262 | 457 | ||
263 | close(HFILE); | 458 | close(HFILE); |
264 | close(CFILE); | 459 | close(CFILE); |
460 | } # end of the c/h file generation | ||
461 | elsif($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 | ||
266 | if($verbose) { | 493 | if($verbose) { |
267 | printf("%d ID strings scanned\n", $idcount); | 494 | printf("%d ID strings scanned\n", $idcount); |