3 # Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 # Copyright (C) 2006 by Daniel Stenberg
13 # binary version for the binary lang file
14 my $langversion = 2; # 2 is the latest one used in the v1 format
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.
25 Usage: genlang2 [options] <langv2 file>
28 Make the tool create a [prefix].c and [prefix].h file.
31 Make the tool create a binary language (.lng) file namaed [outfile].
32 The use of this option requires that you also use -e.
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.
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.
44 Specify which target you want the translations/phrases for. Required when
48 Enables verbose (debug) output.
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
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
73 my $check = ($binary?
1:0) + ($prefix?
1:0) + ($update?
1:0);
76 print "Please use only one of -p, -u and -b\n";
80 print "Please use at least one of -p, -u and -b\n";
83 if(($binary || $update) && !$english) {
84 print "Please use -e too when you use -b or -u\n";
89 if(!$target && !$update) {
90 print "Please specify a target (with -t)!\n";
95 my %id; # string to num hash
96 my @idnum; # num to string array
98 my %source; # id string to source phrase hash
99 my %dest; # id string to dest phrase hash
100 my %voice; # id string to voice phrase hash
103 my $input = $ARGV[0];
109 my ($string, $pattern)=@_;
111 $pattern =~ s/\*/.?*/g;
112 $pattern =~ s/\?/./g;
114 return ($string =~ $pattern);
123 my ($full, $n, $v)=@_;
129 my ($full, $n, $v)=@_;
134 my ($debug, $strref, $full, $n, $v)=@_;
136 my @all= split(" *, *", $n);
139 # print "TEST ($debug) $target for $test\n";
140 if(match
($target, $test)) {
142 # print "MATCH: $test => $v\n";
153 parsetarget
("src", \
$src, @_);
158 parsetarget
("dest", \
$dest, @_);
163 parsetarget
("voice", \
$voice, @_);
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.
172 my $idnum=0; # start with a true number
174 open(ENG
, "<$english") || die "can't open $english";
179 # get rid of DOS newlines
182 if($_ =~ /^ *\<phrase\>/) {
183 # this is the start of a phrase
185 elsif($_ =~ /^ *\<\/phrase\
>/) {
186 # this is the end of a phrase, add it to the english hash
187 $english{$id}=join("", @phrase);
191 # gather everything related to this phrase
195 if($_ =~ /^ *id: ([^ \t\n]+)/i) {
197 # Skip voice-only entries
198 if($id =~ /^VOICE_/) {
202 # Assign an ID number to this entry
210 # a function that compares the english phrase with the translated one.
211 # compare source strings and desc
213 # Then output the updated version!
215 my ($idstr, $engref, $locref)=@_;
217 my ($esource, $lsource);
220 for my $l (@
$engref) {
221 if($l =~ /^ *desc: (.*)/) {
224 elsif($l =~ / *\<source\>/i) {
228 if($l =~ / *\<\/source\
>/i
) {
239 for my $l (@
$locref) {
240 if($l =~ /^ *desc: (.*)/) {
242 if($edesc ne $ldesc) {
243 $l = "### The 'desc' field differs from the english!\n### the previously used desc is commented below:\n### desc: $ldesc\n desc: $edesc\n";
247 elsif($l =~ / *\<source\>/i) {
252 if($l =~ / *\<\/source\
>/i
) {
255 if($esource ne $lsource) {
256 print "### The <source> section differs from the english!\n",
257 "### the previously used one is commented below:\n";
258 for(split("\n", $lsource)) {
266 undef @show; # start over
283 my $idcount; # counter for lang ID numbers
284 my $voiceid=0x8000; # counter for voice-only ID numbers
287 # Now start the scanning of the selected language string
290 open(LANG
, "<$input");
296 # get rid of DOS newlines
299 if($_ =~ /^( *\#|[ \t\n\r]*\z)/) {
300 # comment or empty line
310 # this is an XML-lookalike tag
316 # this was a closing tag
318 if($part eq "/phrase") {
321 my $idstr = $phrase{'id'};
324 if($dest =~ /^none\z/i) {
325 # "none" as dest means that this entire phrase is to be
327 print "dest is NONE!\n";
331 # Use the ID name to figure out which id number range we
332 # should use for this phrase. Voice-only strings are
335 if($idstr =~ /^VOICE/) {
342 $id{$idstr} = $idnum;
343 $idnum[$idnum]=$idstr;
345 $source{$idstr}=$src;
347 $voice{$idstr}=$voice;
350 print "id: $phrase{id} ($idnum)\n";
351 print "source: $src\n";
352 print "dest: $dest\n";
353 print "voice: $voice\n";
363 my $e = $english{$idstr};
366 # compare original english with this!
367 my @eng = split("\n", $english{$idstr});
369 compare
($idstr, \
@eng, \
@phrase);
371 $english{$idstr}=""; # clear it
374 print "### $idstr: The phrase is not used. Skipped\n";
381 # starts with a slash, this _ends_ this section
382 $m = pop @m; # get back old value, the previous level's tag
386 # This is an opening (sub) tag
388 push @m, $m; # store old value
393 if(/^ *([^:]+): *(.*)/) {
394 my ($name, $val)=($1, $2);
395 &$m($_, $name, $val);
405 "### This phrase below was not present in the translated file\n",
414 # We create a .c and .h file
416 open(HFILE
, ">$prefix.h");
417 open(CFILE
, ">$prefix.c");
420 /* This file was automatically generated using genlang2 */
422 * The str() macro/functions is how to access strings that might be
423 * translated. Use it like str(MACRO) and expect a string to be
426 #define str(x) language_strings[x]
428 /* this is the array for holding the string pointers.
429 It will be initialized at runtime. */
430 extern unsigned char *language_strings[];
431 /* this contains the concatenation of all strings, separated by \\0 chars */
432 extern const unsigned char language_builtin[];
434 /* The enum below contains all available strings */
440 /* This file was automaticly generated using genlang2, the strings come
445 unsigned char *language_strings[LANG_LAST_INDEX_IN_ARRAY];
446 const unsigned char language_builtin[] =
450 # Output the ID names for the enum in the header file
452 for $i (1 .. $idcount) {
453 my $name=$idnum[$i - 1]; # get the ID name
455 $name =~ s/\"//g; # cut off the quotes
457 printf HFILE
(" %s,\n", $name);
460 # Output separation marker for last string ID and the upcoming voice IDs
463 LANG_LAST_INDEX_IN_ARRAY, /* this is not a string, this is a marker */
464 /* --- below this follows voice-only strings --- */
465 VOICEONLY_DELIMITER = 0x8000,
469 # Output the ID names for the enum in the header file
471 for $i (0x8000 .. ($voiceid-1)) {
472 my $name=$idnum[$i]; # get the ID name
474 $name =~ s/\"//g; # cut off the quotes
476 printf HFILE
(" %s,\n", $name);
480 print HFILE
"\n};\n/* end of generated enum list */\n";
482 # Output the target phrases for the source file
483 for $i (1 .. $idcount) {
484 my $name=$idnum[$i - 1]; # get the ID
485 my $dest = $dest{$name}; # get the destination phrase
487 $dest =~ s
:\"$:\\0\":; # insert a \0 before the second quote
489 printf CFILE
(" %s\n", $dest);
492 # Output end of string chunk
495 /* end of generated string list */
501 } # end of the c/h file generation
503 # Creation of a binary lang file was requested
505 # We must first scan the english file to get the correct order of the id
506 # numbers used there, as that is what sets the id order for all language
507 # files. The english file is scanned before the translated file was
510 open(OUTF
, ">$binary") or die "Can't create $binary";
512 printf OUTF
("\x1a%c", $langversion); # magic lang file header
514 # loop over the target phrases
515 for $i (1 .. $idcount) {
516 my $name=$idnum[$i - 1]; # get the ID
517 my $dest = $dest{$name}; # get the destination phrase
520 $dest =~ s/^\"(.*)\"\s*$/$1/g; # cut off quotes
522 # Now, make sure we get the number from the english sort order:
523 $idnum = $idmap{$name};
525 printf OUTF
("%c%c%s\x00", ($idnum>>8), ($idnum&0xff), $dest);
527 printf("%02x => %s\n", $idnum, $value);
535 printf("%d ID strings scanned\n", $idcount);
539 printf "$_: %s\n", $head{$_};