summaryrefslogtreecommitdiffstats
path: root/po4a-translate
diff options
context:
space:
mode:
Diffstat (limited to 'po4a-translate')
-rwxr-xr-xpo4a-translate325
1 files changed, 325 insertions, 0 deletions
diff --git a/po4a-translate b/po4a-translate
new file mode 100755
index 0000000..87031c1
--- /dev/null
+++ b/po4a-translate
@@ -0,0 +1,325 @@
+#! /usr/bin/env perl
+eval 'exec perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+# po4a-translate -- translate doc files using a message catalog(ie, PO file)
+#
+# Copyright 2002-2023 by SPI, inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of GPL v2.0 or later (see COPYING).
+
+=encoding UTF-8
+
+=head1 NAME
+
+po4a-translate - convert a PO file back to documentation format
+
+=head1 SYNOPSIS
+
+B<po4a-translate> B<-f> I<fmt> B<-m> I<master.doc> B<-p> I<XX.po> B<-l> I<XX.doc>
+
+(I<XX.doc> is the output, all others are inputs)
+
+=head1 DESCRIPTION
+
+The po4a (PO for anything) project goal is to ease translations (and more
+interestingly, the maintenance of translations) using gettext tools on
+areas where they were not expected like documentation.
+
+The B<po4a-translate> script is in charge of converting the translation
+(which was done in a PO file) back into the documentation format. The
+provided PO file should be the translation of the POT file which was
+produced by L<po4a-gettextize(1)>.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-f>, B<--format>
+
+Format of the documentation you want to handle. Use the B<--help-format>
+option to see the list of available formats.
+
+=item B<-a>, B<--addendum>
+
+Add a file to the resulting file (to put translator's name or a section
+"About this translation", for example). The first line of the file to insert
+should be a PO4A header indicating where it should be added (see section
+B<HOWTO add extra text to translations> in L<po4a(7)>).
+
+=item B<-A>, B<--addendum-charset>
+
+Charset of the addenda. Note that all the addenda should be in the same
+charset.
+
+=item B<-m>, B<--master>
+
+File containing the master document to translate.
+
+=item B<-M>, B<--master-charset>
+
+Charset of the file containing the document to translate.
+
+=item B<-l>, B<--localized>
+
+File where the localized (translated) document should be written.
+
+=item B<-L>, B<--localized-charset>
+
+Charset of the file containing the localized document.
+
+=item B<-p>, B<--po>
+
+File from which the message catalog should be read.
+
+=item B<-o>, B<--option>
+
+Extra option(s) to pass to the format plugin. See the documentation of each
+plugin for more information about the valid options and their meanings. For
+example, you could pass '-o tablecells' to the AsciiDoc parser, while the
+text parser would accept '-o tabs=split'.
+
+=item B<-k>, B<--keep>
+
+Minimal threshold for translation percentage to keep (i.e. write) the
+resulting file (default: 80). I.e. by default, files have to be translated
+at least at 80% to get written.
+
+=item B<-w>, B<--width>
+
+Column at which we should wrap the resulting file if the format supports it
+(default: 76).
+
+=item B<-h>, B<--help>
+
+Show a short help message.
+
+=item B<--help-format>
+
+List the documentation formats understood by po4a.
+
+=item B<-V>, B<--version>
+
+Display the version of the script and exit.
+
+=item B<-v>, B<--verbose>
+
+Increase the verbosity of the program.
+
+=item B<-d>, B<--debug>
+
+Output some debugging information.
+
+=item B<--porefs> I<type>[,B<wrap>|B<nowrap>]
+
+Specify the reference format. Argument I<type> can be one of B<never>
+to not produce any reference, B<file> to only specify the file
+without the line number, B<counter> to replace line number by an
+increasing counter, and B<full> to include complete references (default: full).
+
+Argument can be followed by a comma and either B<wrap> or B<nowrap> keyword.
+References are written by default on a single line. The B<wrap> option wraps
+references on several lines, to mimic B<gettext> tools (B<xgettext> and
+B<msgmerge>). This option will become the default in a future release, because
+it is more sensible. The B<nowrap> option is available so that users who want
+to keep the old behavior can do so.
+
+=back
+
+=head1 Adding content (beside translations) to generated files
+
+To add some extra content to the generated document beside what you
+translated (like the name of the translator, or an "About this translation"
+section), you should use the B<--addendum> option.
+
+The first line of the addendum must be a header indicating where to put
+it in the document (it can be before or after a given part of the
+document). The rest of the file will be added verbatim to the resulting
+file without further processing.
+
+Note that if po4a-translate fails to add one of the given files, it discards
+the whole translation (because the missing file could be the one indicating
+the author, what would prevent the users to contact him to report bugs in
+the translation).
+
+The header has a pretty rigid syntax. For more information on how to use
+this feature and how it works, please refer to the L<po4a(7)> man page.
+
+=head1 SEE ALSO
+
+L<po4a-gettextize(1)>,
+L<po4a-normalize(1)>,
+L<po4a-updatepo(1)>,
+L<po4a(7)>
+
+=head1 AUTHORS
+
+ Denis Barbier <barbier@linuxfr.org>
+ Nicolas François <nicolas.francois@centraliens.net>
+ Martin Quinson (mquinson#debian.org)
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2002-2023 by SPI, inc.
+
+This program is free software; you may redistribute it and/or modify it
+under the terms of GPL v2.0 or later (see the COPYING file).
+
+=cut
+
+use 5.16.0;
+use strict;
+use warnings;
+
+use Locale::Po4a::Chooser;
+use Locale::Po4a::TransTractor;
+use Locale::Po4a::Common;
+
+use Pod::Usage qw(pod2usage);
+use Getopt::Long qw(GetOptions);
+
+Locale::Po4a::Common::textdomain("po4a");
+
+sub show_version {
+ Locale::Po4a::Common::show_version("po4a-translate");
+ exit 0;
+}
+
+Getopt::Long::Configure( 'no_auto_abbrev', 'no_ignore_case' );
+my ( $outfile, $width, $threshold ) = ( '-', 76, 80 );
+my ( $help, $help_fmt, @verbose, $debug, $ignored_wrappo, @addfiles, $format, @options, $no_deprecation );
+my ( $master_filename, $po_filename );
+my ( $mastchar, $locchar, $addchar );
+GetOptions(
+ 'help|h' => \$help,
+ 'help-format' => \$help_fmt,
+
+ 'master|m=s' => \$master_filename,
+ 'localized|l=s' => \$outfile,
+ 'po|p=s' => \$po_filename,
+ 'addendum|a=s' => \@addfiles,
+ 'format|f=s' => \$format,
+
+ 'master-charset|M=s' => \$mastchar,
+ 'localized-charset|L=s' => \$locchar,
+ 'addendum-charset|A=s' => \$addchar,
+
+ 'option|o=s' => \@options,
+
+ # undocumented option to silence the warning about po4a-translate being deprecated
+ 'no-deprecation' => \$no_deprecation,
+
+ # undocumented and ignored option that we must accept for the tests to pass it to the other scripts
+ 'wrap-po=s' => \$ignored_wrappo,
+
+ 'width|w=s' => \$width,
+ 'verbose|v' => \@verbose,
+ 'debug|d' => \$debug,
+ 'keep|k=s' => \$threshold,
+
+ 'version|V' => \&show_version
+) or pod2usage();
+
+$help && pod2usage( -verbose => 1, -exitval => 0 );
+$help_fmt && Locale::Po4a::Chooser::list(0);
+
+( defined($master_filename) && length($master_filename) ) || pod2usage();
+( defined($po_filename) && length($po_filename) ) || pod2usage();
+-e $master_filename || die wrap_msg( gettext("File %s does not exist."), $master_filename );
+-e $po_filename || die wrap_msg( gettext("File %s does not exist."), $po_filename );
+
+my ( @pos, @masters );
+push @pos, $po_filename;
+push @masters, $master_filename;
+
+my %options = (
+ "verbose" => scalar @verbose,
+ "debug" => $debug,
+ "wrapcol" => $width
+);
+
+foreach (@options) {
+ if (m/^([^=]*)=(.*)$/) {
+ $options{$1} = "$2";
+ } else {
+ $options{$_} = 1;
+ }
+}
+
+unless ($no_deprecation) {
+ print wrap_msg(
+ gettext(
+ "po4a-translate is deprecated. The unified po4a(1) program is more convenient and less error prone. "
+ . "Once configured, `po4a --no-update` can be used as a drop-in replacement to `po4a-translate`."
+ )
+ );
+}
+
+# parser
+my $doc = Locale::Po4a::Chooser::new( $format, %options );
+
+# Prepare the document to be used as translator, but not parser
+$doc->process(
+ 'po_in_name' => \@pos,
+ 'file_in_name' => \@masters,
+ 'file_in_charset' => $mastchar,
+ 'file_out_charset' => $locchar,
+ 'addendum_charset' => $addchar,
+);
+
+my ( $percent, $hit, $queries ) = $doc->stats();
+my $error = 0;
+
+print STDERR wrap_msg( gettext("%s is %s%% translated (%s of %s strings)."),
+ $master_filename, $percent, $hit, $queries )
+ if ( scalar @verbose ) && ( $percent >= $threshold );
+
+if ( $percent < $threshold ) {
+ print STDERR wrap_msg( gettext("Discard the translation of %s (only %s%% translated; need %s%%)."),
+ $master_filename, $percent, $threshold );
+ unlink($outfile) if ( -e $outfile );
+} else {
+ my %discarded = ();
+ my @files = ();
+ while (@addfiles) {
+ my $add = shift(@addfiles);
+ my $modifiers;
+ $add =~ s/^([@!?]+)// and $modifiers = $1;
+ next if defined( $discarded{$add} );
+ if ( defined $modifiers ) {
+ if ( $modifiers =~ m/!/ ) {
+ $discarded{$add} = 1;
+ next;
+ }
+ next if ( $modifiers =~ m/\?/ and not -e $add );
+ if ( $modifiers =~ m/@/ ) {
+ open LIST, "<", "$add" or die wrap_msg( gettext("Cannot open %s: %s"), $add, $! );
+ my @new_list = ();
+ while (<LIST>) {
+ chomp;
+ s/\s+$//;
+ next if length($_) == 0 or $_ =~ m/^\s*#/;
+ push( @new_list, $_ );
+ }
+ close LIST;
+ unshift( @addfiles, @new_list );
+ } else {
+ push @files, $add;
+ }
+ } else {
+ push @files, $add;
+ }
+ }
+ for my $add (@files) {
+ unless ( $doc->addendum($add) ) {
+ unlink($outfile) if ( -e $outfile );
+ die wrap_msg( gettext("Discard the translation of %s (addendum %s does not apply)."),
+ $master_filename, $add );
+ }
+ }
+ $doc->write( $outfile, $locchar // '' );
+}
+
+1;
+