]> git.sur5r.net Git - bacula/docs/blob - docs/tools/translatedoc.pl
282052650c45c972399edb23dc90cf72cf4b38d9
[bacula/docs] / docs / tools / translatedoc.pl
1 #!/usr/bin/perl -w
2 #
3 # Bacula Systems - Philippe Chauvat
4 # 27 jul 2012
5 #
6 # This script is designed to translate Bacula enterprise LaTeX2HTML
7 # documentation files to something more "tunable" / "adaptable" from a CSS
8 # point of view.
9 #
10 # $1 is an HTML file to analyze and translate
11 # The output is automatically send to $1.out
12 #
13 # - add some ids, class
14 # - re-order some piece of HTML code
15 #
16 # This script is based on HTML::Parser module
17 #
18 # args:
19 # -i: HTML input file
20 # -o: HTML output file
21 # -j: javascript directory
22 # -c: css directory
23 # -p: images (pictures) directory
24 # -n: Manual name
25 # -e: Request a menu extraction
26 # -r: Source directory (ako part of -i arg)
27 # -?: help / usage
28 # -d: debug requested
29 use HTML::Parser ;
30 use HTML::TreeBuilder ;
31 use HTML::PullParser ;
32 use Getopt::Long ;
33 use File::Basename ;
34 use Data::Dumper ;
35 sub usage {
36     print "translatedoc.pl -i | --input html-source-file
37  [ -o | --output html-destination-file ]
38  [ -j | --javascript javascript-diretory ]
39  [ -c | --css css-directory ]
40  [ -p | --pictures pictures-directory ]
41  [ -n | --name manual_name ]
42  [ -e | --extract ]
43  [ -d | --debug ]
44  [ -r | --source-directory the_original_root_directory ]
45  [ --help | -? ]\n" ;
46     exit 1 ;
47 }
48 #
49 # Send message to output in case of debug only
50 # ======================
51 sub debugdump {
52     my ($what,$msg) = @_ ;
53     if ($debug) {
54         print "\n===============================\nBegin of $msg\n" ;
55         $what->dump ;
56         print "\n===============================\nEnd of $msg\n\n" ;
57     }
58 }
59 #
60 # Args to Vars
61 our($inputfile,$outputfile,$help,$debug,$mytree,$extractmenu,$picturesdir,
62     $cssdir,$javascriptdir,$manualname,$sourcedir) ;
63 #
64 # Usage in case of missing arguments
65 usage() unless($#ARGV > -1) ;
66 #
67 # Input file / Output file
68 GetOptions("input|i=s" => \$inputfile,
69            "output|o=s" => \$outputfile,
70            "extract|e" => \$extractmenu,
71            "pictures|p=s" => \$picturesdir,
72            "css|c=s" => \$cssdir,
73            "source-directory|r=s" => \$sourcedir,
74            "javascript|j=s" => \$javascriptdir,
75            "name|n=s" => \$manualname,
76            "debug|d" => \$debug,
77            "help|?" => \$help) or usage() ;
78 usage() if ($help) ;
79 usage() unless (defined $inputfile) ;
80
81 die "$inputfile does not exists.\n" unless -e $inputfile ;
82
83 if (! defined $outputfile ) {
84     $outputfile = "./" . basename($inputfile) . ".out" ;
85 }
86
87 if (! defined $picturesdir ) {
88     $picturesdir = "../images" ;
89 }
90
91 if (! defined $cssdir ) {
92     $cssdir = "../css" ;
93 }
94
95 if (! defined $javascriptdir ) {
96     $javascriptdir = "../js" ;
97 }
98 if (! defined $manualname) {
99     $manualname = "main" ;
100 }
101 my $MENUFILE="./wholemenu_" . $manualname . ".html" ;
102 #
103 # Build HTML Tree of existing page
104 $mytree = HTML::TreeBuilder->new ;
105 $mytree->parse_file($inputfile) ;
106 #
107 # Find the beginning of the content
108 # Which is also a point where to put
109 # the menu
110 $beginning_of_content = $mytree->look_down('_tag','h1') ;
111 $beginning_of_content = $mytree->look_down('_tag','h2') unless ($beginning_of_content) ;
112 die "The only thing we could test is a <H1> / <H2> tags, which does not exist there...:$!\n"  unless($beginning_of_content) ;
113
114 #
115 # Look for the table of contents
116 # we must translate it at a position before the content itself
117 my $thecopy ;
118 if ($thecopy = $mytree->look_down('_tag', 'ul', 'class','ChildLinks')) {
119     $childlinks = $thecopy->detach() ;
120     debugdump($thecopy,"Navigation system copy 1") ;
121 #
122 # Clean up the content of table of contents
123     while ($d = $thecopy->look_down('_tag','br')) {
124         $d->detach() ;
125         $d->delete() ;
126     }
127     debugdump($thecopy,"Navigation system copy 2") ;
128 }
129 if ($childlinks = $mytree->look_down('_tag','a','name','CHILD_LINKS')) {
130     $childlinks->detach() ;
131     $childlinks->delete() ;
132     debugdump($thecopy,"Navigation system copy 3") ;
133 }
134 #
135 # Remove old navigation part.... (next, up, previous, and so on)
136 if ($childlinks = $mytree->look_down('_tag', 'div', 'class', 'navigation')) {
137     $childlinks->detach_content() ;
138     $childlinks->detach() ;
139     $childlinks->delete_content() ;
140     $childlinks->delete ;
141     debugdump($thecopy,"Navigation system copy 4") ;
142 }
143 # End removing navigation
144 #
145 #
146 # Remove every 'dirty' lines
147 # between <body> and <h1> tag
148 # What is "before" the <h1> tag (between <body> and <h1>) is just dropped
149 my @lefts = $beginning_of_content->left() ;
150 foreach my $l (@lefts) {
151     $l->detach_content() ;
152     $l->delete_content() ;
153     $l->detach() ;
154     $l->delete() ;
155 }
156 debugdump($thecopy,"Navigation system copy 5") ;
157 #
158 # Remove Bacula community logo
159 if ($childlinks = $beginning_of_content->look_down('_tag','img','alt','\\includegraphics{bacula-logo.eps}')) {
160     $childlinks->detach() ;
161     $childlinks->delete() ;
162 }
163 # End remove Bacula logo
164 #
165 # Remove 'address' tag
166 if ($childlinks = $mytree->look_down('_tag','address')) {
167     $childlinks->detach() ;
168     $childlinks->delete() ;
169 }
170 # End remove address
171 #
172 my $thebody = $mytree->look_down('_tag','body') ;
173 $thebody->attr('onload','menuonload(this);') ;
174 debugdump($thebody,"The body BEFORE") ; 
175 my @content = $thebody->detach_content() ;
176 # End remove dirty lines
177 #
178 # What do we do with the menu?
179 # If the menu file exists then just use it
180 if (-e $MENUFILE) {
181     #
182     # Build the menu file
183     $thecopy = HTML::TreeBuilder->new ;
184     $thecopy->parse_file($MENUFILE) ;
185 }
186 debugdump($thecopy,"Navigation system copy 6") ;
187
188 #
189 #
190 # Create a div to manage the whole page
191 my $mainpage = HTML::Element->new_from_lol(
192     ['div', { 'class' => "bsys_mainpageclass", 'id' => "bsys_mainpageid" },
193      [ 'div', {'class' => 'bsys_topclass', 'id' => 'bsys_topid'},
194        [ 'img', { 'src' => $picturesdir . '/bsys-logo.png', 'id' => 'bsys_logo','alt' => 'Bacula Systems Logo' }],
195        [ 'img', { 'src' => $picturesdir . '/bsys-doctitle.png', 'id' => 'bsys_doctitle', 'alt' => 'Bacula Enterprise Documentation text image'}]
196      ],
197      [ 'div', {'id' => 'bsys_breadnsearchid', 'class' => 'bsys_breadnsearchclass'},
198        ['div', { 'class' => 'bsys_searchclass', 'id' => 'bsys_searchid'},
199         ['span','Search' , {'class' => 'bsys_searchtitleclass','id' => 'bsys_searchtitleid'}],
200         [ 'input', { 'class' => 'bsys_searchfieldclass', 'id' => 'bsys_searchfieldid', 'type' => 'text', 'value' => 'Type your text here' }]
201        ],
202        [ 'div', { 'class' => 'bsys_breadcrumbsclass', 'id' => 'bsys_breadcrumbsid'},
203          [ 'p', { 'class' => 'bsys_breadcrumbscontentclass', 'id' => 'bsys_breadcrumbscontentid' }, 'Main' ],
204        ]
205      ],
206      [ 'div', { 'class' => "bsys_pageclass", 'id' => "bsys_pageid"},
207        [ 'div', { 'class' => "bsys_leftnavigationclass", 'id' => "bsys_leftnavigationid" },
208          $thecopy
209        ],
210        [ 'div', { 'class ' => 'bsys_contentclass', 'id' => 'bsys_contentid' },
211          # foreach (@content) {
212          #     ['div', {'class' => 'bsys_truecontent'}, $_ ]
213          # }
214          [ map (('div', {'class' => 'bsys_truecontent' }), $_ ), @content ]
215        ]
216      ]
217     ]
218     ) ;
219 debugdump($mainpage,"Main page build") ;
220 $beginning_of_content = $thebody->push_content($mainpage) ;
221 # Remove "Contents" links
222 if ($childlinks = $mytree->look_down('_tag','a','href','Contents.html')) {
223     $childlinks = $childlinks->parent() ;
224     $childlinks->delete() ;
225 }
226 debugdump($thecopy,"Navigation system copy 7") ;
227 #
228 # Now begins the modification for navigation
229 # ==========================================
230 # We must analyze what is below <ul class="Child_Links">
231 # At first level, we consider each <li> as part of the main menu
232 # At other levels, we consider each <li> as sub(sub | ...)menus
233 $childlinks = $mytree->look_down('_tag','ul','class','ChildLinks') ;
234 $childlinks->attr('id','childlinksid') ;
235 #
236 # This counter is for generating unique identifiers
237 my $ulcounter = 1 ;
238 my $ullevelcounter = 0 ;
239 my $ulpreviousdepth = 0 ;
240 #
241 # Browse all the <ul name="ChildLinks"> node
242 # ------------------------------------------
243 foreach my $d ($childlinks->descendants()) {
244     #
245     # Which tag are we checking ?
246     my $tag = $d->tag() ;
247     #
248     # Nothing to do with <a> tags
249     if ($tag =~ /a/) {
250         $d->attr('onclick',"menuonclick(this);") ;
251     }
252     #
253     # <ul>s represent "openable" menus
254     elsif ($tag =~ /ul/) {
255         if ($d->depth() > $ulpreviousdepth) {
256             $ullevelcounter++ ;
257         }
258         else {
259             $ullevelcounter-- ;
260         }
261         $ulpreviousdepth=$d->depth() ;
262         #
263         # We need to identify uniquely this <ul> start tag to be able to "open" or "close" it
264         my $ullevel= 'level' . $ullevelcounter ;
265         my $idf = 'bsys_ul_' . $ulcounter++ ;
266         $d->attr('class',$ullevel . ' expandingMenu expandingMenuNotSelected') ;
267         $d->attr('id', $idf) ;
268 #       $d->attr('style','display: none;') ;
269         #
270         # We now are knowing the previous <li> tag is a (sub)menu header too
271         # Adding the "onclick" behavior
272         my $previoustagli = $d->look_up('_tag','li') ; # <li> just above
273         $previoustagli->attr('pct_onmouseover',"over_expandingMenuHeader(this,\'" . $idf . "\')") ;
274         $previoustagli->attr('pct_onmouseout',"out_expandingMenuHeader(this,\'" . $idf . "\')") ;
275         my $previoustaga = $d->left('_tag','a') ; # <a> just above
276         $previoustaga->attr('onclick',"menuonclick(this);") ;
277         #
278         # Do not forgot what we defined earlier...
279         my $class = $previoustagli->attr('class') ;
280         $class = $class . ' expandingMenuHeader' ;
281         $previoustagli->attr('class', $class) ;
282     }
283     #
284     # <li>s represent at least menu items
285     # and sometimes menu headers (see <ul> treatment)
286     elsif ($tag =~ /li/) {
287         #
288         # At this stage we only know <li> is a menu item.
289         # nothing more...
290         $d->attr('class', 'expandingMenuItem') ;
291     }
292 }
293 #
294 # <head> treatment
295 # Add some stuff
296 if ($manualname eq "main") {
297     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
298         $childlinks->attr('content','Bacula Systems Enterprise Main Reference Manual') ;
299     }
300     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
301         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Main Reference Manual') ;
302     }
303     if ($childlinks = $mytree->look_down('_tag','link','href','main.css')) {
304         $childlinks->attr('href',$cssdir . '/main.css') ;
305         $childlinks->postinsert(
306             HTML::Element->new_from_lol(
307                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
308                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
309             )
310             ) ;
311     }
312 }
313 elsif ($manualname eq "developers") {
314     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
315         $childlinks->attr('content','Bacula Systems Enterprise Developer\'s Guide') ;
316     }
317     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
318         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Developer\'s Guide') ;
319     }
320     if ($childlinks = $mytree->look_down('_tag','link','href','developers.css')) {
321         $childlinks->attr('href',$cssdir . '/developers.css') ;
322         $childlinks->postinsert(
323             HTML::Element->new_from_lol(
324                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
325                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
326             )
327             ) ;
328     }
329 }
330 elsif ($manualname eq "console") {
331     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
332         $childlinks->attr('content','Bacula Enterprise Command Console and Operators Guide') ;
333     }
334     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
335         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Command Console and Operators Guide') ;
336     }
337     if ($childlinks = $mytree->look_down('_tag','link','href','console.css')) {
338         $childlinks->attr('href',$cssdir . '/console.css') ;
339         $childlinks->postinsert(
340             HTML::Element->new_from_lol(
341                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
342                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
343             )
344             ) ;
345     }
346 }
347 elsif ($manualname eq "utility") {
348     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
349         $childlinks->attr('content','Bacula Enterprise Utility Programs') ;
350     }
351     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
352         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Utility Programs') ;
353     }
354     if ($childlinks = $mytree->look_down('_tag','link','href','utility.css')) {
355         $childlinks->attr('href',$cssdir . '/utility.css') ;
356         $childlinks->postinsert(
357             HTML::Element->new_from_lol(
358                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
359                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
360             )
361             ) ;
362     }
363 }
364 elsif ($manualname eq "problems") {
365     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
366         $childlinks->attr('content','Bacula Enterprise Problem Resolution Guide') ;
367     }
368     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
369         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Problem Resolution Guide') ;
370     }
371     if ($childlinks = $mytree->look_down('_tag','link','href','problems.css')) {
372         $childlinks->attr('href',$cssdir . '/problems.css') ;
373         $childlinks->postinsert(
374             HTML::Element->new_from_lol(
375                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
376                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
377             )
378             ) ;
379     }
380 }
381 elsif ($manualname eq "misc") {
382     if ($childlinks = $mytree->look_down('_tag','meta','name','description')) {
383         $childlinks->attr('content','Bacula Enterprise Miscellaneous Guide') ;
384     }
385     if ($childlinks = $mytree->look_down('_tag','meta','name','keywords')) {
386         $childlinks->attr('content','Bacula Systems, Bacula Enterprise 6, Miscellaneous Guide') ;
387     }
388     if ($childlinks = $mytree->look_down('_tag','link','href','misc.css')) {
389         $childlinks->attr('href',$cssdir . '/misc.css') ;
390         $childlinks->postinsert(
391             HTML::Element->new_from_lol(
392                 ['link',{ 'href' => $cssdir . '/bsys.css', 'rel' => 'stylesheet' } ],
393                 ['script',{ 'type' => 'text/javascript', 'src' => $javascriptdir . '/bsys.js' } ]
394             )
395             ) ;
396     }
397 }
398 #
399 # Replace textregistered images with the HTML special char
400 my @images = $mytree->look_down('_tag','img') ;
401 foreach $childlinks (@images) {
402     my $alttext = $childlinks->attr('alt') ;
403 #    print "Alt: $alttext\n" ;
404     if ($alttext =~ /.*registe.*/) {
405         $childlinks->preinsert(HTML::Element->new_from_lol(['span', {'class' => 'expochar' }, '&reg;'])) ;
406         $childlinks->detach() ;
407         $childlinks->delete() ;
408     }
409     if ($alttext =~ /.*bacula.*-logo.*/) {
410         $childlinks->detach() ;
411         $childlinks->delete() ;
412     }
413 }
414 @images = $mytree->look_down('_tag','img') ;
415 foreach $childlinks (@images) {
416     my $img = $childlinks->attr('src') ;
417     if ($img =~ /^\.\//) {
418         $img =~ s/\.\/// ;
419         $img = $picturesdir . '/' . $img ;
420         $childlinks->attr('src',$img) ;
421 #       print "img: " . $img . "\n" ;
422     }
423 }
424 #
425 # Locate all <a name="whatever_but_SECTION...">
426 my @atags = $mytree->look_down('_tag','a') ;
427 local *AFH ;
428 open AFH, ">> list-of-anchors" or die "Unable to append to list-of-anchors file\n"; 
429 foreach $childlinks (@atags) {
430     my $atagname ;
431     if ($atagname = $childlinks->attr('name')) {
432         print AFH $manualname . "\t" . basename($inputfile) . "\t" . $atagname . "\n" ;
433     }
434 }
435 close AFH ;
436 # This li is at first level
437 if ($outputfile) {
438     local *FH ;
439     open FH, ">" . $outputfile or die "Unable to create $outputfile: $!\n" ;
440     print FH $mytree->as_HTML("<>","\t",{}) ;
441     close FH ;
442 }
443 else {
444     print $mytree->as_HTML("","\t",{}) ;
445 }
446 debugdump($thecopy,"TOC Copy") ;
447 if ($extractmenu) {
448     local *FH ;
449     open FH, ">" . $MENUFILE or die "Unable to create the menu file: $!\n" ;
450     print FH $thecopy->as_HTML("","\t",{}) ;
451     close FH ;
452 }
453
454 1;