[Po4a-commits] "po4a/lib/Locale/Po4a Xml.pm,1.38,1.39"
Nicolas FRANCOIS
nekral-guest at alioth.debian.org
Mon Mar 27 22:21:00 UTC 2006
Update of /cvsroot/po4a/po4a/lib/Locale/Po4a
In directory haydn:/tmp/cvs-serv9146/lib/Locale/Po4a
Modified Files:
Xml.pm
Log Message:
Implement placeholders: this permits to specify that footnotes must not be
translated inside a paragraph, but are translated separately and a
<placeholder0> tag will be put where the footnote must be installed.
This is still beta. The user can't specify what tags must be replaced by
<placeholder> tags: currently only <footnote>, and <quote> (the later for
testing purpose, so that I can try placeholders inside other
placeholders).
It's probably not very robust and need more testing.
Index: Xml.pm
===================================================================
RCS file: /cvsroot/po4a/po4a/lib/Locale/Po4a/Xml.pm,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -d -r1.38 -r1.39
--- Xml.pm 6 Dec 2005 16:32:06 -0000 1.38
+++ Xml.pm 27 Mar 2006 22:20:57 -0000 1.39
@@ -74,6 +74,43 @@
map {$self->parse_file($_)} @{$self->{DOCPOD}{infile}};
}
+# @save_holders is a stack of references to ('paragraph', 'translation',
+# 'sub_transmlations') hashes, where:
+# paragraph is a reference to an array (see paragraph in the
+# treat_content() subroutine) of strings followed by references.
+# It contains the @paragraph array as it was before the
+# processing was interrupted by a tag instroducing a
+# placeholder.
+# translation is the translation of this level up to now
+# sub_translations is a reference to an array of strings containing the
+# translations which must replace the placeholders.
+#
+# If @save_holders only has 1 holder, then we are not processing the
+# content of an holder, we are translating the document.
+my @save_holders;
+
+
+# If we are at the bottom of the stack and there is no <placeholder\d+> in
+# the current translation, we can push the translation in the translated
+# document.
+# Otherwise, we keep the translation in the current holder.
+sub pushline {
+ my ($self, $line) = (shift, shift);
+
+ my $holder_ref = pop @save_holders;
+ my %holder = %$holder_ref;
+ my $translation = $holder{'translation'};
+ $translation .= $line;
+ if ( (scalar @save_holders)
+ or ($translation =~ m/<placeholder\d+>/s)) {
+ $holder{'translation'} = $translation;
+ } else {
+ $self->SUPER::pushline($translation);
+ $holder{'translation'} = '';
+ }
+ push @save_holders, \%holder;
+}
+
=head1 TRANSLATING WITH PO4A::XML
This module can be used directly to handle generic XML documents. This will
@@ -180,6 +217,14 @@
my $self = shift;
my %options = @_;
+ # Initialize the stack of holders
+ my @paragraph = ();
+ my @sub_translations = ();
+ my %holder = ('paragraph' => \@paragraph,
+ 'translation' => "",
+ 'sub_translations' => \@sub_translations);
+ @save_holders = (\%holder);
+
$self->{options}{'nostrip'}=0;
$self->{options}{'wrap'}=0;
$self->{options}{'caseinsensitive'}=0;
@@ -187,6 +232,7 @@
$self->{options}{'tags'}='';
$self->{options}{'attributes'}='';
$self->{options}{'inline'}='';
+ $self->{options}{'placeholder'}='';
$self->{options}{'doctype'}='';
$self->{options}{'nodefault'}='';
@@ -208,6 +254,7 @@
$self->{attributes}=();
#It will maintain the list of the inline tags
$self->{inline}=();
+ $self->{placeholder}=();
#list of the tags that must not be set in the tags or inline category
#by this module or sub-module (unless specified in an option)
$self->{nodefault}=();
@@ -892,13 +939,82 @@
# the tag path
if ($tag_types[$type]->{'end'} eq "") {
if ($tag_types[$type]->{'beginning'} eq "") {
+ # Opening inline tag
+ if ($self->get_tag_name(@tag) =~ m/(footnote|quote)/) { # FIXME
+ # We enter a new holder.
+ # Append a <placeholder#> tag to the current
+ # paragraph, and save the @paragraph in the
+ # current holder.
+ my $holder_ref = pop @save_holders;
+ my %old_holder = %$holder_ref;
+ my $sub_translations_ref = $old_holder{'sub_translations'};
+ my @sub_translations = @$sub_translations_ref;
+
+ push @paragraph, ("<placeholder".($#sub_translations+1).">", $text[1]);
+ my @saved_paragraph = @paragraph;
+
+ $old_holder{'paragraph'} = \@saved_paragraph;
+ push @save_holders, \%old_holder;
+
+ # Then we must push a new holder
+ my @new_paragraph = ();
+ my @sub_translations = ();
+ my %new_holder = ('paragraph' => \@new_paragraph,
+ 'translation' => "",
+ 'sub_translations' => \@sub_translations);
+ push @save_holders, \%new_holder;
+
+ # The current @paragraph
+ # (for the current holder)
+ # is empty.
+ @paragraph = ();
+ }
push @path, $self->get_tag_name(@tag);
} elsif ($tag_types[$type]->{'beginning'} eq "/") {
+ # Closing inline tag
+
+ # Check if this is closing the
+ # last opening tag we detected.
my $test = pop @path;
if (!defined($test) ||
$test ne $tag[0] ) {
die wrap_ref_mod($tag[1], "po4a::xml", dgettext("po4a", "Unexpected closing tag </%s> found. The main document may be wrong."), $tag[0]);
}
+
+ if ($self->get_tag_name(@tag) =~ m/(footnote|quote)/) {
+ # This closes the current holder.
+
+ # We keep the closing tag in the holder paragraph.
+ push @paragraph, @text;
+ @text = ();
+
+ # Now translate this paragraph if needed.
+ # This will call pushline and append the
+ # translation to the current holder's translation.
+ $self->translate_paragraph($translate, @paragraph);
+
+ # Now that this holder is closed, we can remove
+ # the holder from the stack.
+ my $holder_ref = pop @save_holders;
+ # We need to keep the translation of this holder
+ my %holder = %$holder_ref;
+ my $translation = $holder{'translation'};
+ # Then we store the translation in the previous
+ # holder's sub_translations array
+ my $old_holder_ref = pop @save_holders;
+ my %old_holder = %$old_holder_ref;
+ my $sub_translations_ref = $old_holder{'sub_translations'};
+ my @sub_translations = @$sub_translations_ref;
+ push @sub_translations, $translation;
+ # We also need to restore the @paragraph array, as
+ # it was before we encountered the holder.
+ my $paragraph_ref = $old_holder{'paragraph'};
+ @paragraph = @$paragraph_ref;
+
+ # restore the holder in the stack
+ $old_holder{'sub_translations'} = \@sub_translations;
+ push @save_holders, \%old_holder;
+ }
}
}
push @paragraph, @text;
@@ -933,7 +1049,7 @@
my ($tmpeof, @tag) = $self->extract_tag($type,0);
if ($self->get_tag_name(@tag) eq $path[$#path]) {
# The next tag closes the last inline tag.
- # We nned to temporarily remove the tag from
+ # We need to temporarily remove the tag from
# the path before calling breaking_tag
my $t = pop @path;
if (!$tmpeof and !$self->breaking_tag) {
@@ -989,6 +1105,67 @@
}
# Translate the string when needed
+ # This will either push the translation in the translated document or
+ # in the current holder translation.
+ $self->translate_paragraph($translate, @paragraph);
+
+ # Now the paragraph is fully translated.
+ # If we have all the holders' translation, we can replace the
+ # placeholders by their translations.
+ # We must wait to have all the translations because the holders are
+ # numbered.
+ if (scalar @save_holders) {
+ my $holder_ref = pop @save_holders;
+ my %holder = %$holder_ref;
+ my $sub_translations_ref = $holder{'sub_translations'};
+ my $translation = $holder{'translation'};
+ my @sub_translations = @$sub_translations_ref;
+
+ # Count the number of <placeholder\d+> in $translation
+ my $count = 0;
+ my $str = $translation;
+ while ($str =~ m/^.*?<placeholder\d+>(.*)$/s) {
+ $count += 1;
+ $str = $1;
+ }
+
+ if (scalar(@sub_translations) == $count) {
+ # OK, all the holders of the current paragraph are
+ # closed (and translated).
+ # Replace them by their translation.
+ while ($translation =~ m/^(.*?)<placeholder(\d+)>(.*)$/s) {
+ # FIXME: we could also check that
+ # * the holder exists
+ # * all the holders are used
+ $translation = $1.$sub_translations[$2].$3;
+ }
+ # We have our translation
+ $holder{'translation'} = $translation;
+ # And there is no need for any holder in it.
+ @sub_translations = ();
+ $holder{'sub_translations'} = \@sub_translations;
+# FIXME: is it alright if a document ends by a placeholder?
+ }
+ # Either we don't have all the holders, either we have the
+ # final translation.
+ # We must keep the current holder at the top of the stack.
+ push @save_holders, \%holder;
+ }
+
+ # Push the trailing blanks
+ if ($blank ne "") {
+ $self->pushline($blank);
+ }
+ return $eof;
+}
+
+# Translate a @paragraph array of (string, reference).
+# The $translate argument indicates if the strings must be translated or
+# just pushed
+sub translate_paragraph {
+ my ($self, $translate) = (shift, shift);
+ my @paragraph = @_;
+
if ( length($self->join_lines(@paragraph)) > 0 ) {
my $struc = $self->get_path;
my $options = $self->tag_in_list($struc,@{$self->{tags}});
@@ -1008,18 +1185,10 @@
$self->pushline($self->recode_skipped_text($self->join_lines(@paragraph)));
}
}
-
- # Push the trailing blanks
- if ($blank ne "") {
- $self->pushline($blank);
- }
- return $eof;
}
-
-
=head2 WORKING WITH THE MODULE OPTIONS
=over 4
More information about the Po4a-commits
mailing list