447adfd
From b70d42ae5acf4b7fcc806935d97215b679ed843b Mon Sep 17 00:00:00 2001
447adfd
From: Martin Quinson <martin.quinson@ens-rennes.fr>
447adfd
Date: Fri, 1 Mar 2024 01:10:23 +0100
447adfd
Subject: [PATCH] Fix the --translate-only option
447adfd
447adfd
I added a lot of verbose messages to understand what's going on,
447adfd
rewrote a bit of code I didn't understant but was not recently
447adfd
modified, and the bug introduced last month was gone.
447adfd
447adfd
At the end, I'm not sure of what happened, but this
447adfd
fixes https://github.com/mquinson/po4a/issues/482
447adfd
447adfd
Thanks Alexander for the diagnostic and the reproducer!
447adfd
---
447adfd
 NEWS                                     |  3 +
447adfd
 po4a                                     | 78 +++++++++++++++++-------
447adfd
 t/Testhelper.pm                          |  2 +-
447adfd
 t/add/modifiers/_output                  |  1 +
447adfd
 t/cfg-multi.t                            | 22 ++++++-
447adfd
 t/cfg/args-alias-redef/_output           |  1 +
447adfd
 t/cfg/args-alias/_output                 |  1 +
447adfd
 t/cfg/args-alias/_output-keep100         |  1 +
447adfd
 t/cfg/args-global/_output                |  1 +
447adfd
 t/cfg/args-global/_output-keep100        |  1 +
447adfd
 t/cfg/args-master/_output                |  1 +
447adfd
 t/cfg/args-master/_output-keep100        |  1 +
447adfd
 t/cfg/multiple-fuzzied-noup/_output      |  1 +
447adfd
 t/cfg/multiple-nopo/_output-noupdate     |  1 +
447adfd
 t/cfg/multiple-uptodate/_output-only-one |  4 ++
447adfd
 t/cfg/multiple-uptodate/_output-only-two |  5 ++
447adfd
 t/cfg/single-fuzzied-noup/_output        |  1 +
447adfd
 t/cfg/single-nopo/_output-noupdate       |  1 +
447adfd
 18 files changed, 101 insertions(+), 25 deletions(-)
447adfd
 create mode 100644 t/cfg/multiple-uptodate/_output-only-one
447adfd
 create mode 100644 t/cfg/multiple-uptodate/_output-only-two
447adfd
447adfd
diff --git a/po4a b/po4a
447adfd
index 14222062f..72736013e 100755
447adfd
--- a/po4a
447adfd
+++ b/po4a
447adfd
@@ -1319,11 +1319,12 @@ while (<CONFIG>) {
447adfd
         }
447adfd
         if ( scalar @{ $po4a_opts{"partial"} } ) {
447adfd
             foreach my $file ( @{ $po4a_opts{"partial"} } ) {
447adfd
-                if ( grep ( m/(\S+):\Q$file\E\b/, @split_args ) ) {
447adfd
-                    $partial{'lang'}{$1}      = 1;
447adfd
-                    $partial{'master'}{$main} = 1;
447adfd
-                    $partial{'files'}{$file}  = 1;
447adfd
-                    last;
447adfd
+                foreach my $arg (@split_args) {
447adfd
+                    if ( $arg =~ m/(\S+):\Q$file\E\b/ ) {
447adfd
+                        $partial{'lang'}{$1}      = 1;
447adfd
+                        $partial{'master'}{$main} = 1;
447adfd
+                        $partial{'files'}{$file}  = 1;
447adfd
+                    }
447adfd
                 }
447adfd
             }
447adfd
         }
447adfd
@@ -1344,7 +1345,7 @@ while (<CONFIG>) {
447adfd
             $document{$main}{'format'} = $aliases{$1}{"module"};
447adfd
             if ( defined $aliases{$1}{"options"} ) {
447adfd
 
447adfd
-                #                print STDERR "Override the global options with the alias ones\n";
447adfd
+                # print STDERR "Override the global options with the alias ones\n";
447adfd
                 %options = %{ $aliases{$1}{"options"} };    # XXX not a merge, but overwrite
447adfd
             }
447adfd
         }
447adfd
@@ -1440,16 +1441,18 @@ while (<CONFIG>) {
447adfd
             }
447adfd
         }
447adfd
     } elsif ( $cmd =~ m/po4a_alias: *(.*)/ ) {
447adfd
-        my $name  = $1;
447adfd
+        my $name = $1;
447adfd
         shift @split_args;
447adfd
 
447adfd
-        if ( defined $aliases{$name} ) { # If that alias was previously defined
447adfd
-            die "Alias $name redefined from ".$aliases{$name}{"module"}." to $main\n"
447adfd
-                if ( $aliases{$name}{"module"} ne $main );  # Sanity checks
447adfd
-            # Concat the new content to the existing alias
447adfd
-            @split_args = map { parse_config_options( "$config_file:$nb", $_, \%{ $aliases{$name}{"options"} } ); } @split_args;
447adfd
-        } else {
447adfd
-            # Otherwise, define a new option set accordingly
447adfd
+        if ( defined $aliases{$name} ) {    # If that alias was previously defined
447adfd
+            die "Alias $name redefined from " . $aliases{$name}{"module"} . " to $main\n"
447adfd
+              if ( $aliases{$name}{"module"} ne $main );
447adfd
+
447adfd
+            # Concat the new content to the existing alias after a sanity check
447adfd
+            @split_args =
447adfd
+              map { parse_config_options( "$config_file:$nb", $_, \%{ $aliases{$name}{"options"} } ); } @split_args;
447adfd
+
447adfd
+        } else {                            # Otherwise, define a new option set accordingly
447adfd
             my %alias = ();
447adfd
             $alias{"module"} = $main;
447adfd
 
447adfd
@@ -1530,13 +1533,33 @@ if ( $pot_filename =~ m/\$master/ ) {
447adfd
 
447adfd
         # Skip documents not specified, strings are read directly from POT file
447adfd
         foreach my $master ( keys %document ) {
447adfd
-            next                      unless length $master;
447adfd
-            delete $document{$master} unless exists $partial{'master'}{$master};
447adfd
+            next unless length $master;
447adfd
+            if ( exists $partial{'master'}{$master} ) {
447adfd
+                print wrap_msg( gettext("Document %s kept for update (--translate-only)."), $master )
447adfd
+                  if ( $po4a_opts{"verbose"} );
447adfd
+            } else {
447adfd
+                print wrap_msg( gettext("Skip the update of %s as requested (--translate-only)."), $master )
447adfd
+                  if ( $po4a_opts{"verbose"} );
447adfd
+                delete $document{$master};
447adfd
+            }
447adfd
         }
447adfd
 
447adfd
         # Do not read PO files if no file is processed for this language
447adfd
-        foreach my $lang ( keys %po_filename ) {
447adfd
-            delete $po_filename{$lang} unless exists $partial{'lang'}{$lang};
447adfd
+        my $skipped_langs = "";
447adfd
+        my $kept_langs    = "";
447adfd
+        foreach my $lang ( sort keys %po_filename ) {
447adfd
+            if ( exists $partial{'lang'}{$lang} ) {
447adfd
+                $kept_langs .= " $lang";
447adfd
+            } else {
447adfd
+                $skipped_langs .= " $lang";
447adfd
+                delete $po_filename{$lang};
447adfd
+            }
447adfd
+        }
447adfd
+        if ( $po4a_opts{"verbose"} ) {
447adfd
+            $skipped_langs =~ s/^ //;
447adfd
+            $kept_langs    =~ s/^ //;
447adfd
+            print wrap_msg( gettext("Languages skipped because of --translate-only: %s; kept languages: %s."),
447adfd
+                $skipped_langs, $kept_langs );
447adfd
         }
447adfd
     }
447adfd
 
447adfd
@@ -1654,8 +1677,16 @@ if ($update_pot_file) {
447adfd
     print wrap_msg( gettext(" (%d entries)"), $potfile->count_entries() )
447adfd
       unless ( $po4a_opts{"quiet"} );
447adfd
 } else {
447adfd
-    print wrap_msg( gettext("POT file %s already up to date."), $pot_filename )
447adfd
-      if ( $po4a_opts{"verbose"} and not $po4a_opts{"no-update"} );
447adfd
+    if ( $po4a_opts{"no-update"} ) {
447adfd
+        print wrap_msg( gettext("NOT updating the POT file %s as requested (--no-update)."), $pot_filename )
447adfd
+          if ( $po4a_opts{"verbose"} );
447adfd
+    } elsif ( scalar @{ $po4a_opts{"partial"} } ) {
447adfd
+        print wrap_msg( gettext("NOT updating the POT file %s because of --translate-only."), $pot_filename )
447adfd
+          if ( $po4a_opts{"verbose"} );
447adfd
+    } else {
447adfd
+        print wrap_msg( gettext("POT file %s already up to date."), $pot_filename )
447adfd
+          if ( $po4a_opts{"verbose"} and not $po4a_opts{"no-update"} );
447adfd
+    }
447adfd
 }
447adfd
 
447adfd
 my %split_po;           # po_files: '$lang','$master' => '$path'
447adfd
@@ -1930,7 +1961,12 @@ if ( not $po4a_opts{"no-translations"} ) {
447adfd
             next if ( $master eq '' );
447adfd
             next unless defined $document{$master}{$lang};
447adfd
             if ( scalar @{ $po4a_opts{"partial"} } ) {
447adfd
-                next unless defined $partial{'files'}{ $document{$master}{$lang} };
447adfd
+                unless ( defined $partial{'files'}{ $document{$master}{$lang} } ) {
447adfd
+                    print wrap_msg( gettext("Skip master file %s in language %s because of --translate-only."),
447adfd
+                        $master, $lang )
447adfd
+                      if ( $po4a_opts{"verbose"} );
447adfd
+                    next;
447adfd
+                }
447adfd
             }
447adfd
 
447adfd
             unless ( $po4a_opts{"force"} ) {
447adfd
diff --git a/t/Testhelper.pm b/t/Testhelper.pm
447adfd
index 889128a4a..187a3f4fb 100644
447adfd
--- a/t/Testhelper.pm
447adfd
+++ b/t/Testhelper.pm
447adfd
@@ -270,7 +270,7 @@ sub run_one_po4aconf {
447adfd
     pass("Change directory back to $cwd");
447adfd
 
447adfd
     my $expected_outfile = $t->{'expected_outfile'} // "$path/_output";
447adfd
-    unless ( $t->{'diff_outfile'} ) {
447adfd
+    unless ( -e $expected_outfile ) {
447adfd
         $expected_outfile = "$path/$expected_outfile"
447adfd
           if ( not -e $expected_outfile ) && ( -e "$path/$expected_outfile" );
447adfd
         unless ( -e $expected_outfile ) {
447adfd
diff --git a/t/add/modifiers/_output b/t/add/modifiers/_output
447adfd
index 7a93e0caf..a6fcb4050 100644
447adfd
--- a/t/add/modifiers/_output
447adfd
+++ b/t/add/modifiers/_output
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating modifiers.pot as requested (--no-update).
447adfd
+NOT updating the POT file modifiers.pot as requested (--no-update).
447adfd
 with-1 is 100% translated (2 strings).
447adfd
 without-2 is 100% translated (2 strings).
447adfd
 without-3 is 100% translated (2 strings).
447adfd
diff --git a/t/cfg-multi.t b/t/cfg-multi.t
447adfd
index aec9dde00..80fbb56bc 100644
447adfd
--- a/t/cfg-multi.t
447adfd
+++ b/t/cfg-multi.t
447adfd
@@ -11,9 +11,9 @@ use Testhelper;
447adfd
 
447adfd
 my @tests;
447adfd
 push @tests, {
447adfd
-    'doc'         => 'Multiple languages, no pot no po',
447adfd
-    'po4a.conf'   => 'cfg/multiple-nopotpo/po4a.conf',
447adfd
-    'closed_path' => 'cfg/*/',                             # Do not use or modify the other tests
447adfd
+    'doc'            => 'Multiple languages, no pot no po',
447adfd
+    'po4a.conf'      => 'cfg/multiple-nopotpo/po4a.conf',
447adfd
+    'closed_path'    => 'cfg/*/',                             # Do not use or modify the other tests
447adfd
     'expected_files' => 'multiple.de.po multiple.es.po multiple.fr.po multiple.it.po multiple.pot',
447adfd
   },
447adfd
   {
447adfd
@@ -48,6 +48,22 @@ push @tests, {
447adfd
       . 'multiple.man.de.1 multiple.man.es.1 multiple.man.fr.1 multiple.man.it.1 multiple.pot',
447adfd
 
447adfd
   },
447adfd
+  {
447adfd
+    'doc'              => 'Multiple languages, translation uptodate, translate only one language',
447adfd
+    'po4a.conf'        => 'cfg/multiple-uptodate/po4a.conf',
447adfd
+    'options'          => ' --translate-only multiple.man.de.1',
447adfd
+    'closed_path'      => 'cfg/*/',
447adfd
+    'expected_outfile' => 'cfg/multiple-uptodate/_output-only-one',
447adfd
+    'expected_files'   => 'multiple.man.de.1',
447adfd
+  },
447adfd
+  {
447adfd
+    'doc'              => 'Multiple languages, translation uptodate, translate only two languages',
447adfd
+    'po4a.conf'        => 'cfg/multiple-uptodate/po4a.conf',
447adfd
+    'options'          => ' --translate-only multiple.man.de.1 --translate-only multiple.man.es.1',
447adfd
+    'closed_path'      => 'cfg/*/',
447adfd
+    'expected_outfile' => 'cfg/multiple-uptodate/_output-only-two',
447adfd
+    'expected_files'   => 'multiple.man.de.1 multiple.man.es.1',
447adfd
+  },
447adfd
   {
447adfd
     'doc'            => 'Multiple languages, translation already fuzzy',
447adfd
     'po4a.conf'      => 'cfg/multiple-fuzzy/po4a.conf',
447adfd
diff --git a/t/cfg/args-alias-redef/_output b/t/cfg/args-alias-redef/_output
447adfd
index d0467854e..b6bfe9945 100644
447adfd
--- a/t/cfg/args-alias-redef/_output
447adfd
+++ b/t/cfg/args-alias-redef/_output
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 man.de.1 is 20% translated (1 of 5 strings).
447adfd
 Discard man.es.1 (3 of 5 strings; only 60% translated; need 70%).
447adfd
 man.fr.1 is 80% translated (4 of 5 strings).
447adfd
diff --git a/t/cfg/args-alias/_output b/t/cfg/args-alias/_output
447adfd
index 0a88fc814..da4af66dc 100644
447adfd
--- a/t/cfg/args-alias/_output
447adfd
+++ b/t/cfg/args-alias/_output
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 man.de.1 is 20% translated (1 of 5 strings).
447adfd
 Discard man.de.2 (1 of 5 strings; only 20% translated; need 80%).
447adfd
 Discard man.es.1 (3 of 5 strings; only 60% translated; need 70%).
447adfd
diff --git a/t/cfg/args-alias/_output-keep100 b/t/cfg/args-alias/_output-keep100
447adfd
index ec49800ce..cacbc50f3 100644
447adfd
--- a/t/cfg/args-alias/_output-keep100
447adfd
+++ b/t/cfg/args-alias/_output-keep100
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 Discard man.de.1 (1 of 5 strings; only 20% translated; need 100%).
447adfd
 Discard man.de.2 (1 of 5 strings; only 20% translated; need 100%).
447adfd
 Discard man.es.1 (3 of 5 strings; only 60% translated; need 100%).
447adfd
diff --git a/t/cfg/args-global/_output b/t/cfg/args-global/_output
447adfd
index 32a9b921c..b649c4434 100644
447adfd
--- a/t/cfg/args-global/_output
447adfd
+++ b/t/cfg/args-global/_output
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 man.de.1 is 20% translated (1 of 5 strings).
447adfd
 man.es.1 is 60% translated (3 of 5 strings).
447adfd
 man.fr.1 is 80% translated (4 of 5 strings).
447adfd
diff --git a/t/cfg/args-global/_output-keep100 b/t/cfg/args-global/_output-keep100
447adfd
index c0b91f56c..2b9d1e4a1 100644
447adfd
--- a/t/cfg/args-global/_output-keep100
447adfd
+++ b/t/cfg/args-global/_output-keep100
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 Discard man.de.1 (1 of 5 strings; only 20% translated; need 100%).
447adfd
 Discard man.es.1 (3 of 5 strings; only 60% translated; need 100%).
447adfd
 Discard man.fr.1 (4 of 5 strings; only 80% translated; need 100%).
447adfd
diff --git a/t/cfg/args-master/_output b/t/cfg/args-master/_output
447adfd
index 208d3a1c7..db00cb6a9 100644
447adfd
--- a/t/cfg/args-master/_output
447adfd
+++ b/t/cfg/args-master/_output
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 Discard man.de.1 (1 of 5 strings; only 20% translated; need 22%).
447adfd
 Discard man.es.1 (3 of 5 strings; only 60% translated; need 66%).
447adfd
 man.fr.1 is 80% translated (4 of 5 strings).
447adfd
diff --git a/t/cfg/args-master/_output-keep100 b/t/cfg/args-master/_output-keep100
447adfd
index c0b91f56c..2b9d1e4a1 100644
447adfd
--- a/t/cfg/args-master/_output-keep100
447adfd
+++ b/t/cfg/args-master/_output-keep100
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT creating args.pot as requested (--no-update).
447adfd
+NOT updating the POT file args.pot as requested (--no-update).
447adfd
 Discard man.de.1 (1 of 5 strings; only 20% translated; need 100%).
447adfd
 Discard man.es.1 (3 of 5 strings; only 60% translated; need 100%).
447adfd
 Discard man.fr.1 (4 of 5 strings; only 80% translated; need 100%).
447adfd
diff --git a/t/cfg/multiple-fuzzied-noup/_output b/t/cfg/multiple-fuzzied-noup/_output
447adfd
index 9f3763842..a33da7709 100644
447adfd
--- a/t/cfg/multiple-fuzzied-noup/_output
447adfd
+++ b/t/cfg/multiple-fuzzied-noup/_output
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT updating multiple.pot as requested (--no-update).
447adfd
+NOT updating the POT file multiple.pot as requested (--no-update).
447adfd
 Discard multiple.man.de.1 (3 of 4 strings; only 75% translated; need 80%).
447adfd
 Discard multiple.man.es.1 (3 of 4 strings; only 75% translated; need 80%).
447adfd
 Discard multiple.man.fr.1 (3 of 4 strings; only 75% translated; need 80%).
447adfd
diff --git a/t/cfg/multiple-nopo/_output-noupdate b/t/cfg/multiple-nopo/_output-noupdate
447adfd
index bd913a32e..d3cc84a76 100644
447adfd
--- a/t/cfg/multiple-nopo/_output-noupdate
447adfd
+++ b/t/cfg/multiple-nopo/_output-noupdate
447adfd
@@ -1,4 +1,5 @@
447adfd
 NOT updating multiple.pot as requested (--no-update).
447adfd
+NOT updating the POT file multiple.pot as requested (--no-update).
447adfd
 PO file multiple.de.po for language de is missing -- skipping.
447adfd
 PO file multiple.es.po for language es is missing -- skipping.
447adfd
 PO file multiple.fr.po for language fr is missing -- skipping.
447adfd
diff --git a/t/cfg/multiple-uptodate/_output-only-one b/t/cfg/multiple-uptodate/_output-only-one
447adfd
new file mode 100644
447adfd
index 000000000..50b13626d
447adfd
--- /dev/null
447adfd
+++ b/t/cfg/multiple-uptodate/_output-only-one
447adfd
@@ -0,0 +1,4 @@
447adfd
+Document multiple.man.1 kept for update (--translate-only).
447adfd
+Languages skipped because of --translate-only: es fr it; kept languages: de.
447adfd
+NOT updating the POT file multiple.pot because of --translate-only.
447adfd
+multiple.man.de.1 is 100% translated (4 strings).
447adfd
diff --git a/t/cfg/multiple-uptodate/_output-only-two b/t/cfg/multiple-uptodate/_output-only-two
447adfd
new file mode 100644
447adfd
index 000000000..1c2f2fbdf
447adfd
--- /dev/null
447adfd
+++ b/t/cfg/multiple-uptodate/_output-only-two
447adfd
@@ -0,0 +1,5 @@
447adfd
+Document multiple.man.1 kept for update (--translate-only).
447adfd
+Languages skipped because of --translate-only: fr it; kept languages: de es.
447adfd
+NOT updating the POT file multiple.pot because of --translate-only.
447adfd
+multiple.man.de.1 is 100% translated (4 strings).
447adfd
+multiple.man.es.1 is 100% translated (4 strings).
447adfd
diff --git a/t/cfg/single-fuzzied-noup/_output b/t/cfg/single-fuzzied-noup/_output
447adfd
index fde8e19f8..9fb696e0b 100644
447adfd
--- a/t/cfg/single-fuzzied-noup/_output
447adfd
+++ b/t/cfg/single-fuzzied-noup/_output
447adfd
@@ -1,2 +1,3 @@
447adfd
 NOT updating single-fuzzied-noup.pot as requested (--no-update).
447adfd
+NOT updating the POT file single-fuzzied-noup.pot as requested (--no-update).
447adfd
 Discard single-fuzzied-noup.man.fr.1 (3 of 4 strings; only 75% translated; need 80%).
447adfd
diff --git a/t/cfg/single-nopo/_output-noupdate b/t/cfg/single-nopo/_output-noupdate
447adfd
index c8d15b4c8..223727166 100644
447adfd
--- a/t/cfg/single-nopo/_output-noupdate
447adfd
+++ b/t/cfg/single-nopo/_output-noupdate
447adfd
@@ -1,2 +1,3 @@
447adfd
 NOT updating single.pot as requested (--no-update).
447adfd
+NOT updating the POT file single.pot as requested (--no-update).
447adfd
 PO file single.fr.po for language fr is missing -- skipping.