Chameleon

Chameleon Svn Source Tree

Root/tags/2.3/package/bin/po4a/lib/Locale/Po4a/Texinfo.pm

Source at commit 2862 created 7 years 24 days ago.
By ifabio, Tag 2.3 release, bump svn to 2.4
1#!/usr/bin/perl -w
2
3# Copyright (c) 2004-2007 by Nicolas FRANÇOIS <nicolas.francois@centraliens.net>
4#
5# This file is part of po4a.
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with po4a; if not, write to the Free Software
19# Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21#
22########################################################################
23
24=encoding UTF-8
25
26=head1 NAME
27
28Locale::Po4a::Texinfo - convert Texinfo documents and derivates from/to PO files
29
30=head1 DESCRIPTION
31
32The po4a (PO for anything) project goal is to ease translations (and more
33interestingly, the maintenance of translations) using gettext tools on
34areas where they were not expected like documentation.
35
36Locale::Po4a::Texinfo is a module to help the translation of Texinfo documents into
37other [human] languages.
38
39This module contains the definitions of common Texinfo commands and
40environments.
41
42=head1 STATUS OF THIS MODULE
43
44This module is still beta.
45Please send feedback and feature requests.
46
47=head1 SEE ALSO
48
49L<Locale::Po4a::TeX(3pm)|Locale::Po4a::TeX>,
50L<Locale::Po4a::TransTractor(3pm)|Locale::Po4a::TransTractor>,
51L<po4a(7)|po4a.7>
52
53=head1 AUTHORS
54
55 Nicolas François <nicolas.francois@centraliens.net>
56
57=head1 COPYRIGHT AND LICENSE
58
59Copyright 2004-2007 by Nicolas FRANÇOIS <nicolas.francois@centraliens.net>.
60
61This program is free software; you may redistribute it and/or modify it
62under the terms of GPL (see COPYING file).
63
64=cut
65
66package Locale::Po4a::Texinfo;
67
68use 5.006;
69use strict;
70use warnings;
71
72require Exporter;
73use vars qw($VERSION @ISA @EXPORT);
74$VERSION= $Locale::Po4a::TeX::VERSION;
75@ISA= qw(Locale::Po4a::TeX);
76@EXPORT= qw();
77
78use Locale::Po4a::Common;
79use Locale::Po4a::TeX;
80use subs qw(
81 &parse_definition_file
82 &register_generic_command &is_closed &translate_buffer
83 &register_verbatim_environment
84 &generic_command
85 &in_verbatim);
86*parse_definition_file = \&Locale::Po4a::TeX::parse_definition_file;
87*register_generic_command = \&Locale::Po4a::TeX::register_generic_command;
88*register_verbatim_environment = \&Locale::Po4a::TeX::register_verbatim_environment;
89*generic_command = \&Locale::Po4a::TeX::generic_command;
90*is_closed = \&Locale::Po4a::TeX::is_closed;
91*in_verbatim = \&Locale::Po4a::TeX::in_verbatim;
92*translate_buffer = \&Locale::Po4a::TeX::translate_buffer;
93use vars qw($RE_ESCAPE $ESCAPE
94 $RE_VERBATIM
95 $RE_COMMENT $RE_PRE_COMMENT
96 $no_wrap_environments $separated_commands
97 %commands %environments
98 %command_categories %separated
99 %env_separators %debug
100 %translate_buffer_env
101 @exclude_include @comments);
102*RE_ESCAPE = \$Locale::Po4a::TeX::RE_ESCAPE;
103*ESCAPE = \$Locale::Po4a::TeX::ESCAPE;
104*RE_VERBATIM = \$Locale::Po4a::TeX::RE_VERBATIM;
105*RE_COMMENT = \$Locale::Po4a::TeX::RE_COMMENT;
106*RE_PRE_COMMENT = \$Locale::Po4a::TeX::RE_PRE_COMMENT;
107*no_wrap_environments = \$Locale::Po4a::TeX::no_wrap_environments;
108*separated_commands = \$Locale::Po4a::TeX::separated_commands;
109*commands = \%Locale::Po4a::TeX::commands;
110*environments = \%Locale::Po4a::TeX::environments;
111*command_categories = \%Locale::Po4a::TeX::command_categories;
112*separated = \%Locale::Po4a::TeX::separated;
113*env_separators = \%Locale::Po4a::TeX::env_separators;
114*debug = \%Locale::Po4a::TeX::debug;
115*translate_buffer_env = \%Locale::Po4a::TeX::translate_buffer_env;
116*exclude_include = \@Locale::Po4a::TeX::exclude_include;
117*comments = \@Locale::Po4a::TeX::comments;
118
119$ESCAPE = "\@";
120$RE_ESCAPE = "\@";
121$RE_VERBATIM = "\@example";
122$RE_COMMENT = "\\\@(?:c|comment)\\b";
123$RE_PRE_COMMENT = "(?<!\@)(?:\@\@)*";
124
125my %break_line = ();
126
127# translate_line_command indicate if the arguments to the command handled
128# by line_command() should be translated:
129# undefined: arguments are not translated
130# 0: there should be no arguments
131# 1: arguments should be translated
132my %translate_line_command = ();
133
134foreach (qw/example smallexample tex display smalldisplay verbatim format smallformat
135 flushleft flushright lisp smalllisp ignore/) {
136 register_verbatim_environment($_);
137 $commands{$_} = \&environment_line_command;
138 $translate_line_command{$_} = 0; # There should be no arguments
139 $break_line{$_} = 1;
140}
141
142my $docheader_pushed = 0;
143# The header shall not be written before the Texinfo header (which include
144# the \input command that define the texinfo macros)
145sub docheader {
146 return "";
147}
148
149sub push_docheader {
150 return if $docheader_pushed;
151 my $self = shift;
152 $self->pushline(<<END);
153\@c ===========================================================================
154\@c
155\@c This file was generated with po4a. Translate the source file.
156\@c
157\@c ===========================================================================
158END
159 $docheader_pushed = 1;
160}
161
162sub parse {
163 my $self = shift;
164 my ($line,$ref);
165 my $paragraph = ""; # Buffer where we put the paragraph while building
166 my @env = (); # environment stack
167 my $t = "";
168 $docheader_pushed = 0;
169
170 LINE:
171 undef $self->{type};
172 ($line,$ref)=$self->shiftline();
173
174 while (defined($line)) {
175 chomp($line);
176 $self->{ref}="$ref";
177
178 if ($line =~ /^\s*@\s*po4a\s*:/) {
179 parse_definition_line($self, $line);
180 goto LINE;
181 }
182
183 my $closed = 1;
184 if (!in_verbatim(@env)) {
185 $closed = is_closed($paragraph);
186 }
187# if (not $closed) {
188# print "not closed. line: '$line'\n para: '$paragraph'\n";
189# }
190
191 if ($closed and $line =~ /^\s*$/) {
192 # An empty line. This indicates the end of the current
193 # paragraph.
194 $paragraph .= $line."\n";
195 if (length($paragraph)) {
196 ($t, @env) = translate_buffer($self,$paragraph,undef,@env);
197 $self->pushline($t);
198 $paragraph="";
199 }
200 } elsif ($line =~ m/^\\input /) {
201 if (length($paragraph)) {
202 ($t, @env) = translate_buffer($self,$paragraph,undef,@env);
203 $self->pushline($t);
204 $paragraph="";
205 }
206 $self->pushline($line."\n");
207 $self->push_docheader();
208 } elsif ($line =~ m/^$RE_COMMENT/) {
209 $self->push_docheader();
210 $self->pushline($line."\n");
211 } elsif ( $closed
212 and ($line =~ /^@([^ ]*?)(?: +(.*))?$/)
213 and (defined $commands{$1})
214 and ($break_line{$1})) {
215 if (length($paragraph)) {
216 ($t, @env) = translate_buffer($self,$paragraph,undef,@env);
217 $self->pushline($t);
218 $paragraph="";
219 }
220 my $arg = $2;
221 my @args = ();
222 if (defined $arg and length $arg) {
223 # FIXME: keep the spaces ?
224 $arg =~ s/\s*$//s;
225 @args= (" ", $arg);
226 }
227 ($t, @env) = &{$commands{$1}}($self, $1, "", \@args, \@env, 1);
228 $self->pushline($t."\n");
229 } else {
230 # continue the same paragraph
231 $paragraph .= $line."\n";
232 }
233
234 # Reinit the loop
235 ($line,$ref)=$self->shiftline();
236 undef $self->{type};
237 }
238
239 if (length($paragraph)) {
240 ($t, @env) = translate_buffer($self,$paragraph,undef,@env);
241 $self->pushline($t);
242 $paragraph="";
243 }
244} # end of parse
245
246sub line_command {
247 my $self = shift;
248 my ($command,$variant,$args,$env) = (shift,shift,shift,shift);
249 my $no_wrap = shift;
250 print "line_command($command,$variant,@$args,@$env,$no_wrap)="
251 if ($debug{'commands'});
252
253 my $translated = $ESCAPE.$command;
254 my $line = $args->[1];
255 if (defined $line and length $line) {
256 if ( defined $translate_line_command{$command}
257 and $translate_line_command{$command}) {
258 # $no_wrap could be forced to 1, but it should already be set
259 my ($t,$e) = $self->translate_buffer($line,$no_wrap,@$env,$command);
260 $translated .= " ".$t;
261 } else {
262 $translated .= " ".$line;
263 }
264 }
265 print "($translated,@$env)\n"
266 if ($debug{'commands'});
267 return ($translated,@$env);
268}
269
270sub defindex_line_command {
271 my $self = shift;
272 my ($command,$variant,$args,$env) = (shift,shift,shift,shift);
273 my $no_wrap = shift;
274 print "line_command($command,$variant,@$args,@$env,$no_wrap)="
275 if ($debug{'commands'});
276 my $idx = $$args[1]."index";
277 $commands{$idx} = \&line_command;
278 $break_line{$idx} = 1;
279 $translate_line_command{$idx} = 1;
280
281 return line_command($self,$command,$variant,$args,$env,$no_wrap);
282}
283
284sub translate_buffer_menu {
285 my ($self,$buffer,$no_wrap,@env) = (shift,shift,shift,@_);
286 print STDERR "translate_buffer_menu($buffer,$no_wrap,@env)="
287 if ($debug{'translate_buffer'});
288
289 my $translated_buffer = "";
290 my $spaces = "";
291 if ($buffer =~ m/(\s*)$/s) {
292 $spaces = $1;
293 }
294
295
296 while ($buffer =~ m/^(.*?)((?:\n|^)\* )(.*)$/s) {
297 my $sep = $2;
298 $buffer = $3;
299 my($t, @e) = $self->translate_buffer_menuentry($1, $no_wrap,
300 @env, "menuentry");
301 $translated_buffer .= $t.$sep;
302 }
303 my($t, @e) = $self->translate_buffer_menuentry($buffer, $no_wrap,
304 @env, "menuentry");
305 $translated_buffer .= $t;
306
307 $translated_buffer .= $spaces;
308
309 print STDERR "($translated_buffer,@env)\n"
310 if ($debug{'translate_buffer'});
311 return ($translated_buffer,@env);
312}
313$translate_buffer_env{"menu"} = \&translate_buffer_menu;
314$translate_buffer_env{"detailmenu"} = \&translate_buffer_menu;
315$translate_buffer_env{"direntry"} = \&translate_buffer_menu;
316
317my $menu_width = 78;
318my $menu_sep_width = 30;
319sub translate_buffer_menuentry {
320 my ($self,$buffer,$no_wrap,@env) = (shift,shift,shift,@_);
321 print STDERR "translate_buffer_menuentry($buffer,$no_wrap,@env)="
322 if ($debug{'translate_buffer'});
323
324 my $translated_buffer = "";
325
326 if ( $buffer =~ m/^(.*?)(::)\s+(.*)$/s
327 or $buffer =~ m/^(.*?: .*?)(\.)\s+(.*)$/s) {
328 my ($name, $sep, $description) = ($1, $2, $3);
329 my ($t, @e) = $self->translate_buffer($name, $no_wrap, @env);
330 $translated_buffer = $t.$sep." ";
331 my $l = length($translated_buffer) + 2;
332 if ($l < $menu_sep_width-1) {
333 $translated_buffer .= ' 'x($menu_sep_width-1-$l);
334 $l = $menu_sep_width-1;
335 }
336 ($t, @e) = $self->translate_buffer($description, $no_wrap, @env);
337 $t =~ s/\n//sg;
338 $t = Locale::Po4a::Po::wrap($t, $menu_width-$l-2);
339 my $spaces = ' 'x($l+2);
340 $t =~ s/\n/\n$spaces/sg;
341 $translated_buffer .= $t;
342 } else {
343# FIXME: no-wrap if a line start by a space
344 my ($t, @e) = $self->translate_buffer($buffer, $no_wrap, @env);
345 $translated_buffer = $t;
346 }
347
348 print STDERR "($translated_buffer,@env)\n"
349 if ($debug{'translate_buffer'});
350 return ($translated_buffer,@env);
351}
352
353sub translate_buffer_ignore {
354 my ($self,$buffer,$no_wrap,@env) = (shift,shift,shift,@_);
355 print STDERR "translate_buffer_ignore($buffer,$no_wrap,@env);\n"
356 if ($debug{'translate_buffer'});
357 return ($buffer,@env);
358}
359$translate_buffer_env{"ignore"} = \&translate_buffer_ignore;
360
361foreach (qw(appendix section cindex findex kindex opindex pindex vindex subsection
362 dircategory subtitle include
363 exdent center unnumberedsec
364 heading unnumbered unnumberedsubsec
365 unnumberedsubsubsec appendixsec appendixsubsec
366 appendixsubsubsec majorheading chapheading subheading
367 subsubheading shorttitlepage
368 subsubsection top item itemx chapter settitle
369 title author)) {
370 $commands{$_} = \&line_command;
371 $break_line{$_} = 1;
372 $translate_line_command{$_} = 1;
373}
374foreach (qw(c comment clear set setfilename setchapternewpage vskip synindex
375 syncodeindex need fonttextsize printindex headings finalout sp
376 definfoenclose)) {
377 $commands{$_} = \&line_command;
378 $break_line{$_} = 1;
379}
380foreach (qw(defcodeindex defindex)) {
381 $commands{$_} = \&defindex_line_command;
382 $break_line{$_} = 1;
383}
384# definfoenclose: command definition => translate?
385foreach (qw(insertcopying page bye summarycontents shortcontents contents
386 noindent)) {
387 $commands{$_} = \&line_command;
388 $break_line{$_} = 1;
389 $translate_line_command{$_} = 0;
390}
391
392foreach (qw(defcv deffn
393 defivar defmac defmethod defop
394 defopt defspec deftp deftypecv
395 deftypefn deftypefun
396 deftypeivar deftypemethod
397 deftypeop deftypevar deftypevr
398 defun defvar defvr)) {
399 $commands{$_} = \&environment_line_command;
400 $translate_line_command{$_} = 1;
401 $break_line{$_} = 1;
402}
403foreach (qw(defcvx deffnx defivarx defmacx defmethodx defopx defoptx
404 defspecx deftpx deftypecvx deftypefnx deftypefunx deftypeivarx
405 deftypemethodx deftypeopx deftypevarx deftypevrx defunx
406 defvarx defvrx)) {
407 $commands{$_} = \&line_command;
408 $translate_line_command{$_} = 1;
409 $break_line{$_} = 1;
410}
411
412foreach (qw(titlefont w i r b sansserif sc slanted strong t cite email
413 footnote indicateurl emph ref xref pxref inforef kbd key
414 acronym),
415# The following commands could cause problems since their arguments
416# have a semantic and a translator could decide not to translate code but
417# still translate theses short words if they appear in another context.
418 qw(file command dfn dmn option math code samp var)) {
419 register_generic_command("-$_,{_}");
420}
421
422register_generic_command("*anchor,{_}");
423register_generic_command("*refill,");
424
425$translate_line_command{'node'} = 1;
426$no_wrap_environments .= " node";
427$break_line{'node'} = 1;
428# @node Comments, Minimum, Conventions, Overview
429$commands{'node'} = sub {
430 my $self = shift;
431 my ($command,$variant,$args,$env) = (shift,shift,shift,shift);
432 my $no_wrap = shift;
433 print "node($command,$variant,@$args,@$env,$no_wrap)="
434 if ($debug{'commands'});
435
436 my $translated = $ESCAPE.$command;
437 my $line = $args->[1];
438 if (defined $line and length $line) {
439 my @pointers = split (/, */, $line);
440 my @t;
441 foreach (@pointers) {
442 push @t, $self->translate($_, $self->{ref}, $command, "wrap" => 0);
443 }
444 $translated .= " ".join(", ", @t);
445 }
446
447 print "($translated,@$env)\n"
448 if ($debug{'commands'});
449 return ($translated,@$env);
450};
451
452sub environment_command {
453 my $self = shift;
454 my ($command,$variant,$args,$env) = (shift,shift,shift,shift);
455 my $no_wrap = shift;
456 print "environment_command($command,$variant,@$args,@$env,$no_wrap)="
457 if ($debug{'commands'});
458 my ($t,@e)=("",());
459
460 ($t, @e) = generic_command($self,$command,$variant,$args,$env,$no_wrap);
461 @e = (@$env, $command);
462
463 print "($t,@e)\n"
464 if ($debug{'commands'});
465 return ($t,@e);
466}
467
468sub environment_line_command {
469 my $self = shift;
470 my ($command,$variant,$args,$env) = (shift,shift,shift,shift);
471 my $no_wrap = shift;
472 print "environment_command_line($command,$variant,@$args,@$env,$no_wrap)="
473 if ($debug{'commands'});
474 my ($t,@e)=("",());
475
476 ($t, @e) = line_command($self,$command,$variant,$args,$env,$no_wrap);
477 @e = (@$env, $command);
478
479 print "($t,@e)\n"
480 if ($debug{'commands'});
481 return ($t,@e);
482}
483
484## push the environment in the environment stack, and do not translate
485## the command
486#sub push_environment {
487# my $self = shift;
488# my ($command,$variant,$args,$env) = (shift,shift,shift,shift);
489# print "push_environment($command,$variant,@$args,@$env)="
490# if ($debug{'environments'});
491#
492# my ($t,@e) = generic_command($self,$command,$variant,$args,$env);
493#
494# print "($t,@e)\n"
495# if ($debug{'environments'});
496# return ($t,@e);
497#}
498#
499foreach (qw(detailmenu menu titlepage group copying
500 documentdescription cartouche
501 direntry
502 ifdocbook ifhtml ifinfo ifplaintext iftex ifxml
503 ifnotdocbook ifnothtml ifnotinfo ifnotplaintext ifnottex ifnotxml)) {
504 $commands{$_} = \&environment_line_command;
505 $translate_line_command{$_} = 0;
506 $break_line{$_} = 1;
507}
508foreach (qw(enumerate multitable ifclear ifset)) {
509 $commands{$_} = \&environment_line_command;
510 $break_line{$_} = 1;
511}
512foreach (qw(quotation)) {
513 $commands{$_} = \&environment_line_command;
514 $translate_line_command{$_} = 1;
515 $break_line{$_} = 1;
516}
517
518$env_separators{'format'} = "(?:(?:^|\n)\\\*|END-INFO-DIR-ENTRY|START-INFO-DIR-ENTRY)";
519$env_separators{'multitable'} = "(?:\@item|\@tab)";
520
521my $end_command=$commands{'end'};
522register_generic_command("*end, ");
523$commands{'end'} = $end_command;
524$break_line{'end'} = 1;
525
526register_generic_command("*macro, ");
527$commands{'macro'} = \&environment_command;
528$break_line{'macro'} = 1;
529register_generic_command("*itemize, ");
530$commands{'itemize'} = \&environment_command;
531$break_line{'itemize'} = 1;
532register_generic_command("*table, ");
533$commands{'table'} = \&environment_command;
534$break_line{'table'} = 1;
535
536# TODO: is_closed, use a regexp: \ does not escape the closing brace.
537# TBC on LaTeX.
538# In Texinfo, it appears with the "code" command. Maybe this command should
539# be used as verbatim. (Expressions.texi)
540
541# TODO: @include @ignore
542
543# TBC: node Indices
544
5451;
546

Archive Download this file

Revision: 2862