Skip to content

Commit

Permalink
po4a: Do not pass empty PO files to msgmerge
Browse files Browse the repository at this point in the history
Fixes #442
  • Loading branch information
mquinson committed Jan 5, 2024
1 parent 885bc58 commit 5078a53
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 20 deletions.
7 changes: 7 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ t/cfg/split-yaml/i18n.pot
t/cfg/split-yaml/i18n.vi.po
t/cfg/split-yaml/po4a.cfg
t/cfg/split-yaml/vi.yaml
t/cfg/single-emptypo/_fr.po
t/cfg/single-emptypo/_output
t/cfg/single-emptypo/_single.man.fr.1
t/cfg/single-emptypo/fr.po
t/cfg/single-emptypo/po4a.conf
t/cfg/single-emptypo/single.man.1
t/cfg/single-emptypo/single.pot
t/cfg/single-nopotpo/single.man.1
t/cfg/single-nopotpo/po4a.conf
t/cfg/single-nopotpo/_single.pot
Expand Down
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ General:
po4a main script (the deprecated po4a-* scripts are still buggy):
* Deal properly with CRLF files coming from windows (GitHub's #409).
* Allow to escape spaces in file names, or to quote them (GitHub's #412).
* Do not pass empty PO files to msgmerge, as it stumbles on such things when
the POT file has UTF chars in the msgids. (GitHub's #442) [Mt]

po4a-translate:
* Remove the wrap-po option that was not used internally.
Expand Down
22 changes: 14 additions & 8 deletions lib/Locale/Po4a/Po.pm
Original file line number Diff line number Diff line change
Expand Up @@ -317,23 +317,28 @@ sub read {
my $self = shift;
my $filename = shift
or croak wrap_mod( "po4a::po", dgettext( "po4a", "Please provide a non-null filename" ) );

my $charset = shift // 'UTF-8';
$charset = 'UTF-8' if $charset eq "CHARSET";
warn "Read $filename with encoding: $charset" if $debug{'encoding'};

my $checkvalidity = shift // 1;

my $lang = basename($filename);
$lang =~ s/\.po$//;
$self->{lang} = $lang;

my $cmd = "msgfmt" . $Config{_exe} . " --check-format --check-domain -o /dev/null \"" . $filename . '"';
if ($checkvalidity) { # We sometimes need to read a file even if it may be invalid (eg to test whether it's empty)
my $cmd = "msgfmt" . $Config{_exe} . " --check-format --check-domain -o /dev/null \"" . $filename . '"';

my $locale = $ENV{'LC_ALL'};
$ENV{'LC_ALL'} = "C";
my $out = qx/$cmd 2>&1/;
$ENV{'LC_ALL'} = $locale;
my $locale = $ENV{'LC_ALL'};
$ENV{'LC_ALL'} = "C";
my $out = qx/$cmd 2>&1/;
$ENV{'LC_ALL'} = $locale;

die wrap_msg( dgettext( "po4a", "Invalid po file %s:\n%s" ), $filename, $out )
unless ( $? == 0 );
die wrap_msg( dgettext( "po4a", "Invalid po file %s:\n%s" ), $filename, $out )
unless ( $? == 0 );
}

my $fh;
if ( $filename eq '-' ) {
Expand All @@ -348,6 +353,7 @@ sub read {
while ( defined( my $textline = <$fh> ) ) {
$pofile .= $textline;
}
$pofile =~ s/\r\n/\n/sg; # Reading a DOS-encoded file from Linux (native files are handled in all cases)

# If we did not get the charset right, reload the file with the right one
if ( $pofile =~ /charset=(.*?)[\s\\]/ ) {
Expand All @@ -357,7 +363,7 @@ sub read {
{
warn "Reloading the PO file, changing the charset from '$charset' to '$detected_charset'"
if $debug{'encoding'};
$self->read( $filename, $detected_charset );
$self->read( $filename, $detected_charset, $checkvalidity );
return;
}
}
Expand Down
19 changes: 18 additions & 1 deletion po4a
Original file line number Diff line number Diff line change
Expand Up @@ -1756,7 +1756,16 @@ if ( not $po4a_opts{"no-update"} ) {
( find_input_file( $po_filename{$lang} ), find_output_file( $po_filename{$lang} ) );
my $updated_potfile = find_input_file($pot_filename);

my $usable_pofile = 0;
if ( -e $infile ) {

# Check that the po file is not empty, as msgmerge has issues in this case (see Debian's #1022216 and GitHub's #442)

my $pofile = Locale::Po4a::Po->new();
$pofile->read( $infile, undef, 0 ); # Guess the charset ; Don't fail if msgfmt spits an error
$usable_pofile = 1 if ( $pofile->count_entries() > 0 );
}
if ($usable_pofile) {
my $dir = dirname($outfile);
if ( not -d $dir ) {
mkdir $dir or die wrap_msg( gettext("Cannot create directory '%s': %s"), $dir, $! );
Expand All @@ -1765,7 +1774,7 @@ if ( not $po4a_opts{"no-update"} ) {
my $msgmerge_opt = $po4a_opts{"msgmerge-opt"};
$msgmerge_opt =~ s/\$lang\b/$lang/g if scalar @langs;
my $cmd = "msgmerge" . $Config{_exe} . " \"$infile\" \"$updated_potfile\" " . $msgmerge_opt;
if ( $infile eq $outfile ) { # in place
if ( $infile eq $outfile ) { # in place
$cmd .= " --backup=none --update";
} else {
$cmd .= " --output \"$outfile\"";
Expand All @@ -1785,6 +1794,14 @@ if ( not $po4a_opts{"no-update"} ) {
}

} else {
if ( $po4a_opts{"verbose"} ) {
if ( $po4a_opts{'split'} ) {
printf( gettext("Creating an empty PO file for the language %s.\n"), $lang );
} else {
printf( gettext("Creating an empty PO file in %s.\n"), $po_filename{$lang} );
}
}

my $read_pot_filename = find_input_file($pot_filename);
my $cmd =
"msginit$Config{_exe} -i \"$read_pot_filename\" --locale $lang -o \"$outfile\" --no-translator >$devnull";
Expand Down
2 changes: 1 addition & 1 deletion po4a-updatepo
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ while ( my $po_filename = shift @pofiles ) {
my $usable_pofile = 0;
if ( -e $po_filename ) {

# Check that the po file is not empty, as msgmerge has issues in this case (see Debian's #1022216)
# Check that the po file is not empty, as msgmerge has issues in this case (see Debian's #1022216 and GitHub's #442)
my $pofile = Locale::Po4a::Po->new();
$pofile->read($po_filename);
$usable_pofile = 1 if ( $pofile->count_entries() > 0 );
Expand Down
23 changes: 14 additions & 9 deletions t/cfg-single.t
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ push @tests, {
'po4a.conf' => 'cfg/single-podirectory-emptypot-emptypo/po4a.conf',
'closed_path' => 'cfg/*/',
'expected_files' => 'fr.po single.pot',
'tests' => [
'PODIFF -I#: $path/_fr.po.expected $tmppath/fr.po', #
'PODIFF -I#: $path/_single.pot.expected $tmppath/single.pot',
'rm $tmppath/single.pot && touch $tmppath/single.pot', # This file is empty on purpose
'rm $tmppath/fr.po && touch $tmppath/fr.po', # This file is empty on purpose
]
'tests' => [
'PODIFF -I#: $path/_fr.po.expected $tmppath/fr.po', #
'PODIFF -I#: $path/_single.pot.expected $tmppath/single.pot',
'rm $tmppath/single.pot && touch $tmppath/single.pot', # This file is empty on purpose
'rm $tmppath/fr.po && touch $tmppath/fr.po', # This file is empty on purpose
]

},
{
Expand All @@ -115,12 +115,17 @@ push @tests, {
'closed_path' => 'cfg/*/',
'expected_files' => 'po single.man.fr.1',
'tests' => [
'PODIFF -I#: $path/po/fr.po $tmppath/po/fr.po', #
'PODIFF -I#: $path/po/fr.po $tmppath/po/fr.po', #
'PODIFF -I#: $path/_single.pot $tmppath/po/single.pot',
'rm $tmppath/po/single.pot && touch $tmppath/po/single.pot'
, # The $path/po/single.pot exists, but it's empty (on purpose)
, # The $path/po/single.pot exists, but it's empty (on purpose)
]

},
{
'doc' => 'Single language, empty PO file and UTF in msgids (see Debian\'s #1022216)',
'po4a.conf' => 'cfg/single-emptypo/po4a.conf',
'closed_path' => 'cfg/*/',
'expected_files' => 'fr.po single.pot single.man.fr.1',
};

run_all_tests(@tests);
Expand Down
4 changes: 4 additions & 0 deletions t/cfg/multiple-nopo/_output
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Updating multiple.pot: (4 entries)
Creating an empty PO file in multiple.de.po.
Creating an empty PO file in multiple.es.po.
Creating an empty PO file in multiple.fr.po.
Creating an empty PO file in multiple.it.po.
Discard multiple.man.de.1 (0 of 4 strings; only 0% translated; need 80%).
Discard multiple.man.es.1 (0 of 4 strings; only 0% translated; need 80%).
Discard multiple.man.fr.1 (0 of 4 strings; only 0% translated; need 80%).
Expand Down
4 changes: 4 additions & 0 deletions t/cfg/multiple-nopotpo/_output
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Creating multiple.pot: (4 entries)
Creating an empty PO file in multiple.de.po.
Creating an empty PO file in multiple.es.po.
Creating an empty PO file in multiple.fr.po.
Creating an empty PO file in multiple.it.po.
Discard multiple.man.de.1 (0 of 4 strings; only 0% translated; need 80%).
Discard multiple.man.es.1 (0 of 4 strings; only 0% translated; need 80%).
Discard multiple.man.fr.1 (0 of 4 strings; only 0% translated; need 80%).
Expand Down
39 changes: 39 additions & 0 deletions t/cfg/single-emptypo/_fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# French translations for po package
# Copyright (C) 2020 Free Software Foundation, Inc.
# This file is distributed under the same license as the po package.
# Automatically generated, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: po 4a\n"
"POT-Creation-Date: 2005-04-24 2:54+0200\n"
"PO-Revision-Date: 2005-04-24 2:54+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. type: TH
#: single.man.1:1
#, no-wrap
msgid "test1"
msgstr ""

#. type: SH
#: single.man.1:2
#, no-wrap
msgid "NAME"
msgstr ""

#. type: Plain text
#: single.man.1:4
msgid "test - just a test"
msgstr ""

#. type: Plain text
#: single.man.1:5
msgid "UTF in msgid is sometimes difficult, but mandatory for some nämes."
msgstr ""
3 changes: 3 additions & 0 deletions t/cfg/single-emptypo/_output
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Updating single.pot: (4 entries)
Creating an empty PO file in fr.po.
single.man.fr.1 is 0% translated (0 of 4 strings).
10 changes: 10 additions & 0 deletions t/cfg/single-emptypo/_single.man.fr.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.\"*******************************************************************
.\"
.\" This file was generated with po4a. Translate the source file.
.\"
.\"*******************************************************************
.TH test1 1
.SH NAME
test \- just a test

UTF in msgid is sometimes difficult, but mandatory for some nämes.
Empty file added t/cfg/single-emptypo/fr.po
Empty file.
5 changes: 5 additions & 0 deletions t/cfg/single-emptypo/po4a.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[po4a_paths] single.pot fr:fr.po

[options] opt:"--verbose --keep 0 "

[type:man] single.man.1 fr:single.man.fr.1
5 changes: 5 additions & 0 deletions t/cfg/single-emptypo/single.man.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.TH test1 1
.SH NAME
test \- just a test

UTF in msgid is sometimes difficult, but mandatory for some nämes.
39 changes: 39 additions & 0 deletions t/cfg/single-emptypo/single.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SOME DESCRIPTIVE TITLE
# Copyright (C) YEAR Free Software Foundation, Inc.
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2005-04-24 2:54+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#. type: TH
#: single.man.1:1
#, no-wrap
msgid "test1"
msgstr ""

#. type: SH
#: single.man.1:2
#, no-wrap
msgid "NAME"
msgstr ""

#. type: Plain text
#: single.man.1:4
msgid "test - just a test"
msgstr ""

#. type: Plain text
#: single.man.1:5
msgid "UTF in msgid is sometimes difficult, but mandatory for some nämes."
msgstr ""
1 change: 1 addition & 0 deletions t/cfg/single-nopo/_output
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Updating single.pot: (4 entries)
Creating an empty PO file in single.fr.po.
Discard single.man.fr.1 (0 of 4 strings; only 0% translated; need 80%).
1 change: 1 addition & 0 deletions t/cfg/single-nopotpo/_output
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Creating single.pot: (4 entries)
Creating an empty PO file in single.fr.po.
Discard single.man.fr.1 (0 of 4 strings; only 0% translated; need 80%).
18 changes: 18 additions & 0 deletions t/cfg/single-podirectory-emptypot-emptypo/_fr.po.expected
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# French translations for po package
# Copyright (C) 2024 Free Software Foundation, Inc.
# This file is distributed under the same license as the po package.
# Automatically generated, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: po 4a\n"
"POT-Creation-Date: 2024-01-04 22:50+0100\n"
"PO-Revision-Date: 2024-01-04 22:50+0100\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. type: TH
#: single.man.1:1
#, no-wrap
Expand Down
2 changes: 1 addition & 1 deletion t/cfg/single-podirectory-emptypot-emptypo/_output
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ Using '.' as a po_directory.
Found language 'fr' in the provided po_directory: ./fr.po
Found POT file './single.pot' in the provided po_directory.
Updating ./single.pot: (4 entries)
Updating ./fr.po: 0 translated messages, 4 untranslated messages.
Creating an empty PO file in ./fr.po.
Discard single.man.fr.1 (0 of 4 strings; only 0% translated; need 80%).
2 changes: 2 additions & 0 deletions t/cfg/split-nopo/_output
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ The translation of master file 'first.man' in language 'de' is missing (file: fi
The translation of master file 'second.man' in language 'de' is missing (file: second.man.de.po) -- skipping.
The translation of master file 'first.man' in language 'fr' is missing (file: first.man.fr.po) -- skipping.
The translation of master file 'second.man' in language 'fr' is missing (file: second.man.fr.po) -- skipping.
Creating an empty PO file for the language de.
Creating an empty PO file for the language fr.
Discard first.man.de (0 of 5 strings; only 0% translated; need 80%).
Discard second.man.de (0 of 5 strings; only 0% translated; need 80%).
Discard first.man.fr (0 of 5 strings; only 0% translated; need 80%).
Expand Down
2 changes: 2 additions & 0 deletions t/cfg/split-nopotpo/_output
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ The translation of master file 'first.man' in language 'de' is missing (file: fi
The translation of master file 'second.man' in language 'de' is missing (file: second.man.de.po) -- skipping.
The translation of master file 'first.man' in language 'fr' is missing (file: first.man.fr.po) -- skipping.
The translation of master file 'second.man' in language 'fr' is missing (file: second.man.fr.po) -- skipping.
Creating an empty PO file for the language de.
Creating an empty PO file for the language fr.
Discard first.man.de (0 of 5 strings; only 0% translated; need 80%).
Discard second.man.de (0 of 5 strings; only 0% translated; need 80%).
Discard first.man.fr (0 of 5 strings; only 0% translated; need 80%).
Expand Down
1 change: 1 addition & 0 deletions t/core/porefs/_output
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Creating list.pot: (2 entries)
Creating an empty PO file in up.po.

0 comments on commit 5078a53

Please sign in to comment.