]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blobdiff - IkiWiki/Plugin/po.pm
Merge branch 'master' into commentreorg
[git.ikiwiki.info.git] / IkiWiki / Plugin / po.pm
index 6aacca53a6ca1635e57143e43847f3b793095ebb..7c979ebca3f88b111fcc10885751e695e937c85e 100644 (file)
@@ -10,7 +10,12 @@ use warnings;
 use strict;
 use IkiWiki 3.00;
 use Encode;
 use strict;
 use IkiWiki 3.00;
 use Encode;
-use Locale::Po4a::Common qw(nowrapi18n !/.*/);
+eval q{use Locale::Po4a::Common qw(nowrapi18n !/.*/)};
+if ($@) {
+       print STDERR gettext("warning: Old po4a detected! Recommend upgrade to 0.35.")."\n";
+       eval q{use Locale::Po4a::Common qw(!/.*/)};
+       die $@ if $@;
+}
 use Locale::Po4a::Chooser;
 use Locale::Po4a::Po;
 use File::Basename;
 use Locale::Po4a::Chooser;
 use Locale::Po4a::Po;
 use File::Basename;
@@ -56,6 +61,8 @@ sub import {
        inject(name => "IkiWiki::urlto", call => \&myurlto);
        $origsubs{'cgiurl'}=\&IkiWiki::cgiurl;
        inject(name => "IkiWiki::cgiurl", call => \&mycgiurl);
        inject(name => "IkiWiki::urlto", call => \&myurlto);
        $origsubs{'cgiurl'}=\&IkiWiki::cgiurl;
        inject(name => "IkiWiki::cgiurl", call => \&mycgiurl);
+       $origsubs{'rootpage'}=\&IkiWiki::rootpage;
+       inject(name => "IkiWiki::rootpage", call => \&myrootpage);
 }
 
 
 }
 
 
@@ -78,7 +85,8 @@ sub getsetup () {
        return
                plugin => {
                        safe => 0,
        return
                plugin => {
                        safe => 0,
-                       rebuild => 1,
+                       rebuild => 1, # format plugin
+                       section => "format",
                },
                po_master_language => {
                        type => "string",
                },
                po_master_language => {
                        type => "string",
@@ -94,7 +102,7 @@ sub getsetup () {
                        type => "string",
                        example => {
                                'fr' => 'Français',
                        type => "string",
                        example => {
                                'fr' => 'Français',
-                               'es' => 'Castellano',
+                               'es' => 'Español',
                                'de' => 'Deutsch'
                        },
                        description => "slave languages (PO files)",
                                'de' => 'Deutsch'
                        },
                        description => "slave languages (PO files)",
@@ -125,6 +133,7 @@ sub checkconfig () {
                                      $field, 'po'));
                }
        }
                                      $field, 'po'));
                }
        }
+       delete $config{po_slave_languages}{$config{po_master_language}{code}};;
 
        map {
                islanguagecode($_)
 
        map {
                islanguagecode($_)
@@ -152,19 +161,22 @@ sub checkconfig () {
        push @{$config{wiki_file_prune_regexps}}, qr/\.pot$/;
 
        # Translated versions of the underlays are added if available.
        push @{$config{wiki_file_prune_regexps}}, qr/\.pot$/;
 
        # Translated versions of the underlays are added if available.
-       foreach my $underlay ("basewiki", map { m/^\Q$config{underlaydirbase}\E\/*(.*)/ } reverse @{$config{underlaydirs}}) {
+       foreach my $underlay ("basewiki",
+                             map { m/^\Q$config{underlaydirbase}\E\/*(.*)/ }
+                                 reverse @{$config{underlaydirs}}) {
                next if $underlay=~/^locale\//;
 
                next if $underlay=~/^locale\//;
 
-               # Add underlays containing the po files for slave languages.
+               # Underlays containing the po files for slave languages.
                foreach my $ll (keys %{$config{po_slave_languages}}) {
                foreach my $ll (keys %{$config{po_slave_languages}}) {
-                       add_underlay("locale/mo/$underlay")
-                               if -d "$config{underlaydirbase}/locale/mo/$underlay";
+                       add_underlay("po/$ll/$underlay")
+                               if -d "$config{underlaydirbase}/po/$ll/$underlay";
                }
        
                if ($config{po_master_language}{code} ne 'en') {
                        # Add underlay containing translated source files
                        # for the master language.
                }
        
                if ($config{po_master_language}{code} ne 'en') {
                        # Add underlay containing translated source files
                        # for the master language.
-                       add_underlay("locale/$config{po_master_language}{code}/$underlay");
+                       add_underlay("locale/$config{po_master_language}{code}/$underlay")
+                               if -d "$config{underlaydirbase}/locale/$config{po_master_language}{code}/$underlay";
                }
        }
 }
                }
        }
 }
@@ -197,10 +209,7 @@ sub scan (@) {
        if (istranslation($page)) {
                foreach my $destpage (@{$links{$page}}) {
                        if (istranslatable($destpage)) {
        if (istranslation($page)) {
                foreach my $destpage (@{$links{$page}}) {
                        if (istranslatable($destpage)) {
-                               # replace one occurence of $destpage in $links{$page}
-                               # (we only want to replace the one that was added by
-                               # IkiWiki::Plugin::link::scan, other occurences may be
-                               # there for other reasons)
+                               # replace the occurence of $destpage in $links{$page}
                                for (my $i=0; $i<@{$links{$page}}; $i++) {
                                        if (@{$links{$page}}[$i] eq $destpage) {
                                                @{$links{$page}}[$i] = $destpage . '.' . lang($page);
                                for (my $i=0; $i<@{$links{$page}}; $i++) {
                                        if (@{$links{$page}}[$i] eq $destpage) {
                                                @{$links{$page}}[$i] = $destpage . '.' . lang($page);
@@ -277,17 +286,16 @@ sub pagetemplate (@) {
                map add_depends($page, $_), (values %{otherlanguages($page)});
        }
        if ($config{discussion} && istranslation($page)) {
                map add_depends($page, $_), (values %{otherlanguages($page)});
        }
        if ($config{discussion} && istranslation($page)) {
-               my $discussionlink=gettext("discussion");
-               if ($page !~ /.*\/\Q$discussionlink\E$/i &&
+               if ($page !~ /.*\/\Q$config{discussionpage}\E$/i &&
                   (length $config{cgiurl} ||
                   (length $config{cgiurl} ||
-                   exists $links{$masterpage."/".$discussionlink})) {
+                   exists $links{$masterpage."/".lc($config{discussionpage})})) {
                        $template->param('discussionlink' => htmllink(
                                $page,
                                $destpage,
                        $template->param('discussionlink' => htmllink(
                                $page,
                                $destpage,
-                               $masterpage . '/' . gettext("Discussion"),
+                               $masterpage . '/' . $config{discussionpage},
                                noimageinline => 1,
                                forcesubpage => 0,
                                noimageinline => 1,
                                forcesubpage => 0,
-                               linktext => gettext("Discussion"),
+                               linktext => $config{discussionpage},
                ));
                }
        }
                ));
                }
        }
@@ -299,7 +307,10 @@ sub pagetemplate (@) {
            && $masterpage eq "index") {
                $template->param('parentlinks' => []);
        }
            && $masterpage eq "index") {
                $template->param('parentlinks' => []);
        }
-} # }}}
+       if (ishomepage($page) && $template->query(name => "title")) {
+               $template->param(title => $config{wikiname});
+       }
+}
 
 # Add the renamed page translations to the list of to-be-renamed pages.
 sub renamepages (@) {
 
 # Add the renamed page translations to the list of to-be-renamed pages.
 sub renamepages (@) {
@@ -374,41 +385,42 @@ sub change (@) {
            && exists $config{meta_overrides_page_title}
            && defined $config{meta_overrides_page_title}
            && $config{meta_overrides_page_title}) {
            && exists $config{meta_overrides_page_title}
            && defined $config{meta_overrides_page_title}
            && $config{meta_overrides_page_title}) {
-               debug(sprintf(gettext("re-rendering all pages to fix meta titles")));
+               debug(sprintf(gettext("rebuilding all pages to fix meta titles")));
                resetalreadyfiltered();
                require IkiWiki::Render;
                foreach my $file (@rendered) {
                resetalreadyfiltered();
                require IkiWiki::Render;
                foreach my $file (@rendered) {
-                       debug(sprintf(gettext("rendering %s"), $file));
-                       IkiWiki::render($file);
+                       IkiWiki::render($file, sprintf(gettext("building %s"), $file));
                }
        }
 
        my $updated_po_files=0;
 
        # Refresh/create POT and PO files as needed.
                }
        }
 
        my $updated_po_files=0;
 
        # Refresh/create POT and PO files as needed.
-       # (But avoid doing so if they are in an underlay directory.)
        foreach my $file (grep {istranslatablefile($_)} @rendered) {
                my $masterfile=srcfile($file);
                my $page=pagename($file);
                my $updated_pot_file=0;
        foreach my $file (grep {istranslatablefile($_)} @rendered) {
                my $masterfile=srcfile($file);
                my $page=pagename($file);
                my $updated_pot_file=0;
+
+               # Avoid touching underlay files.
+               next if $masterfile ne "$config{srcdir}/$file";
+
                # Only refresh POT file if it does not exist, or if
                # Only refresh POT file if it does not exist, or if
-               # $pagesources{$page} was changed: don't if only the HTML was
+               # the source was changed: don't if only the HTML was
                # refreshed, e.g. because of a dependency.
                # refreshed, e.g. because of a dependency.
-               if ($masterfile eq "$config{srcdir}/$file" &&
-                  ((grep { $_ eq $pagesources{$page} } @origneedsbuild)
-                   || ! -e potfile($masterfile))) {
+               if ((grep { $_ eq $pagesources{$page} } @origneedsbuild) ||
+                   ! -e potfile($masterfile)) {
                        refreshpot($masterfile);
                        $updated_pot_file=1;
                }
                my @pofiles;
                foreach my $po (pofiles($masterfile)) {
                        refreshpot($masterfile);
                        $updated_pot_file=1;
                }
                my @pofiles;
                foreach my $po (pofiles($masterfile)) {
-                       next if ! $updated_pot_file && -e $po;
+                       next if ! $updated_pot_file && -e $po;
                        next if grep { $po=~/\Q$_\E/ } @{$config{underlaydirs}};
                        push @pofiles, $po;
                }
                if (@pofiles) {
                        refreshpofiles($masterfile, @pofiles);
                        next if grep { $po=~/\Q$_\E/ } @{$config{underlaydirs}};
                        push @pofiles, $po;
                }
                if (@pofiles) {
                        refreshpofiles($masterfile, @pofiles);
-                       map { IkiWiki::rcs_add($_) } @pofiles if $config{rcs};
+                       map { s/^\Q$config{srcdir}\E\/*//; IkiWiki::rcs_add($_) } @pofiles if $config{rcs};
                        $updated_po_files=1;
                }
        }
                        $updated_po_files=1;
                }
        }
@@ -439,8 +451,8 @@ sub canremove (@) {
        my %params = @_;
 
        if (istranslation($params{page})) {
        my %params = @_;
 
        if (istranslation($params{page})) {
-               return gettext("Can not remove a translation. Removing the master page, ".
-                              "though, removes its translations as well.");
+               return gettext("Can not remove a translation. If the master page is removed, ".
+                              "however, its translations will be removed as well.");
        }
        return undef;
 }
        }
        return undef;
 }
@@ -459,8 +471,8 @@ sub canrename (@) {
                # saved early in the renaming process.
                my $orig_torename = $session->param("po_orig_torename");
                unless (grep { $_ eq $masterpage } @{$orig_torename}) {
                # saved early in the renaming process.
                my $orig_torename = $session->param("po_orig_torename");
                unless (grep { $_ eq $masterpage } @{$orig_torename}) {
-                       return gettext("Can not rename a translation. Renaming the master page, ".
-                                      "though, renames its translations as well.");
+                       return gettext("Can not rename a translation. If the master page is renamed, ".
+                                      "however, its translations will be renamed as well.");
                }
        }
        return undef;
                }
        }
        return undef;
@@ -523,10 +535,23 @@ sub formbuilder (@) {
        if ($form->field("do") eq "create") {
                foreach my $field ($form->field) {
                        next unless "$field" eq "type";
        if ($form->field("do") eq "create") {
                foreach my $field ($form->field) {
                        next unless "$field" eq "type";
-                       if ($field->type eq 'select') {
-                               # remove po from the list of types
-                               my @types = grep { $_ ne 'po' } $field->options;
-                               $field->options(\@types) if @types;
+                       next unless $field->type eq 'select';
+                       my $orig_value = $field->value;
+                       # remove po from the list of types
+                       my @types = grep { $_->[0] ne 'po' } $field->options;
+                       $field->options(\@types) if @types;
+                       # favor the type of linking page's masterpage
+                       if ($orig_value eq 'po') {
+                               my ($from, $type);
+                               if (defined $form->field('from')) {
+                                       ($from)=$form->field('from')=~/$config{wiki_file_regexp}/;
+                                       $from = masterpage($from);
+                               }
+                               if (defined $from && exists $pagesources{$from}) {
+                                       $type=pagetype($pagesources{$from});
+                               }
+                               $type=$config{default_pageext} unless defined $type;
+                               $field->value($type) ;
                        }
                }
        }
                        }
                }
        }
@@ -541,11 +566,16 @@ sub mybestlink ($$) {
        my $page=shift;
        my $link=shift;
 
        my $page=shift;
        my $link=shift;
 
+       return $origsubs{'bestlink'}->($page, $link)
+               if defined $config{po_link_to} && $config{po_link_to} eq "default";
+
        my $res=$origsubs{'bestlink'}->(masterpage($page), $link);
        my $res=$origsubs{'bestlink'}->(masterpage($page), $link);
+       my @caller = caller(1);
        if (length $res
        if (length $res
-           && ($config{po_link_to} eq "current" || $config{po_link_to} eq "negotiated")
            && istranslatable($res)
            && istranslatable($res)
-           && istranslation($page)) {
+           && istranslation($page)
+           &&  !(exists $caller[3] && defined $caller[3]
+                 && ($caller[3] eq "IkiWiki::PageSpec::match_link"))) {
                return $res . "." . lang($page);
        }
        return $res;
                return $res . "." . lang($page);
        }
        return $res;
@@ -555,7 +585,7 @@ sub mybeautify_urlpath ($) {
        my $url=shift;
 
        my $res=$origsubs{'beautify_urlpath'}->($url);
        my $url=shift;
 
        my $res=$origsubs{'beautify_urlpath'}->($url);
-       if ($config{po_link_to} eq "negotiated") {
+       if (defined $config{po_link_to} && $config{po_link_to} eq "negotiated") {
                $res =~ s!/\Qindex.$config{po_master_language}{code}.$config{htmlext}\E$!/!;
                $res =~ s!/\Qindex.$config{htmlext}\E$!/!;
                map {
                $res =~ s!/\Qindex.$config{po_master_language}{code}.$config{htmlext}\E$!/!;
                $res =~ s!/\Qindex.$config{htmlext}\E$!/!;
                map {
@@ -596,17 +626,21 @@ sub myurlto ($$;$) {
        # so that one is redirected to the just-edited page rather than to the
        # negociated translation; to prevent unnecessary fiddling with caller/inject,
        # we only do so when our beautify_urlpath would actually do what we want to
        # so that one is redirected to the just-edited page rather than to the
        # negociated translation; to prevent unnecessary fiddling with caller/inject,
        # we only do so when our beautify_urlpath would actually do what we want to
-       # avoid, i.e. when po_link_to = negotiated
+       # avoid, i.e. when po_link_to = negotiated.
+       # also avoid doing so when run by cgi_goto, so that the links on recentchanges
+       # page actually lead to the exact page they pretend to.
        if ($config{po_link_to} eq "negotiated") {
                my @caller = caller(1);
        if ($config{po_link_to} eq "negotiated") {
                my @caller = caller(1);
-               my $run_by_editpage = 0;
-               $run_by_editpage = 1 if (exists $caller[3] && defined $caller[3]
-                                        && $caller[3] eq "IkiWiki::cgi_editpage");
+               my $use_orig = 0;
+               $use_orig = 1 if (exists $caller[3] && defined $caller[3]
+                                && ($caller[3] eq "IkiWiki::cgi_editpage" ||
+                                    $caller[3] eq "IkiWiki::Plugin::goto::cgi_goto")
+                                );
                inject(name => "IkiWiki::beautify_urlpath", call => $origsubs{'beautify_urlpath'})
                inject(name => "IkiWiki::beautify_urlpath", call => $origsubs{'beautify_urlpath'})
-                       if $run_by_editpage;
+                       if $use_orig;
                my $res = $origsubs{'urlto'}->($to,$from,$absolute);
                inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath)
                my $res = $origsubs{'urlto'}->($to,$from,$absolute);
                inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath)
-                       if $run_by_editpage;
+                       if $use_orig;
                return $res;
        }
        else {
                return $res;
        }
        else {
@@ -624,6 +658,22 @@ sub mycgiurl (@) {
        return $origsubs{'cgiurl'}->(%params);
 }
 
        return $origsubs{'cgiurl'}->(%params);
 }
 
+sub myrootpage (@) {
+       my %params=@_;
+
+       my $rootpage;
+       if (exists $params{rootpage}) {
+               $rootpage=$origsubs{'bestlink'}->($params{page}, $params{rootpage});
+               if (!length $rootpage) {
+                       $rootpage=$params{rootpage};
+               }
+       }
+       else {
+               $rootpage=masterpage($params{page});
+       }
+       return $rootpage;
+}
+
 # ,----
 # | Blackboxes for private data
 # `----
 # ,----
 # | Blackboxes for private data
 # `----
@@ -679,6 +729,7 @@ sub istranslatablefile ($) {
        my $type=pagetype($file);
        return 0 if ! defined $type || $type eq 'po';
        return 0 if $file =~ /\.pot$/;
        my $type=pagetype($file);
        return 0 if ! defined $type || $type eq 'po';
        return 0 if $file =~ /\.pot$/;
+       return 0 if ! defined $config{po_translatable_pages};
        return 1 if pagespec_match(pagename($file), $config{po_translatable_pages});
        return;
 }
        return 1 if pagespec_match(pagename($file), $config{po_translatable_pages});
        return;
 }
@@ -825,8 +876,23 @@ sub refreshpofiles ($@) {
 
        foreach my $pofile (@pofiles) {
                IkiWiki::prep_writefile(basename($pofile),dirname($pofile));
 
        foreach my $pofile (@pofiles) {
                IkiWiki::prep_writefile(basename($pofile),dirname($pofile));
+
+               if (! -e $pofile) {
+                       # If the po file exists in an underlay, copy it
+                       # from there.
+                       my ($pobase)=$pofile=~/^\Q$config{srcdir}\E\/?(.*)$/;
+                       foreach my $dir (@{$config{underlaydirs}}) {
+                               if (-e "$dir/$pobase") {
+                                       File::Copy::syscopy("$dir/$pobase",$pofile)
+                                               or error("po(refreshpofiles) ".
+                                                        sprintf(gettext("failed to copy underlay PO file to %s"),
+                                                                $pofile));
+                               }
+                       }
+               }
+
                if (-e $pofile) {
                if (-e $pofile) {
-                       system("msgmerge", "-q", "-U", "--backup=none", $pofile, $potfile) == 0
+                       system("msgmerge", "--previous", "-q", "-U", "--backup=none", $pofile, $potfile) == 0
                                or error("po(refreshpofiles) ".
                                         sprintf(gettext("failed to update %s"),
                                                 $pofile));
                                or error("po(refreshpofiles) ".
                                         sprintf(gettext("failed to update %s"),
                                                 $pofile));
@@ -913,7 +979,7 @@ sub otherlanguagesloop ($) {
                                master => 1,
                        };
                }
                                master => 1,
                        };
                }
-               else {
+               elsif (istranslation($otherpage)) {
                        push @ret, {
                                url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
                                code => $lang,
                        push @ret, {
                                url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
                                code => $lang,
@@ -935,6 +1001,14 @@ sub homepageurl (;$) {
        return urlto('', $page);
 }
 
        return urlto('', $page);
 }
 
+sub ishomepage ($) {
+       my $page = shift;
+
+       return 1 if $page eq 'index';
+       map { return 1 if $page eq 'index.'.$_ } keys %{$config{po_slave_languages}};
+       return undef;
+}
+
 sub deletetranslations ($) {
        my $deletedmasterfile=shift;
 
 sub deletetranslations ($) {
        my $deletedmasterfile=shift;
 
@@ -987,11 +1061,8 @@ sub commit_and_refresh ($$) {
        IkiWiki::saveindex();
 }
 
        IkiWiki::saveindex();
 }
 
-# on success, returns the filtered content.
-# on error, if $nonfatal, warn and return undef; else, error out.
-sub po_to_markup ($$;$) {
+sub po_to_markup ($$) {
        my ($page, $content) = (shift, shift);
        my ($page, $content) = (shift, shift);
-       my $nonfatal = shift;
 
        $content = '' unless defined $content;
        $content = decode_utf8(encode_utf8($content));
 
        $content = '' unless defined $content;
        $content = decode_utf8(encode_utf8($content));
@@ -1014,10 +1085,6 @@ sub po_to_markup ($$;$) {
 
        my $fail = sub ($) {
                my $msg = "po(po_to_markup) - $page : " . shift;
 
        my $fail = sub ($) {
                my $msg = "po(po_to_markup) - $page : " . shift;
-               if ($nonfatal) {
-                       warn $msg;
-                       return undef;
-               }
                error($msg, sub { unlink $infile, $outfile});
        };
 
                error($msg, sub { unlink $infile, $outfile});
        };
 
@@ -1038,8 +1105,7 @@ sub po_to_markup ($$;$) {
        $doc->write($outfile)
                or return $fail->(sprintf(gettext("failed to write %s"), $outfile));
 
        $doc->write($outfile)
                or return $fail->(sprintf(gettext("failed to write %s"), $outfile));
 
-       $content = readfile($outfile)
-               or return $fail->(sprintf(gettext("failed to read %s"), $outfile));
+       $content = readfile($outfile);
 
        # Unlinking should happen automatically, thanks to File::Temp,
        # but it does not work here, probably because of the way writefile()
 
        # Unlinking should happen automatically, thanks to File::Temp,
        # but it does not work here, probably because of the way writefile()
@@ -1088,8 +1154,8 @@ sub isvalidpo ($) {
        if ($res) {
            return IkiWiki::SuccessReason->new("valid gettext data");
        }
        if ($res) {
            return IkiWiki::SuccessReason->new("valid gettext data");
        }
-       return IkiWiki::FailReason->new("invalid gettext data, go back ".
-                                       "to previous page to go on with edit");
+       return IkiWiki::FailReason->new(gettext("invalid gettext data, go back ".
+                                       "to previous page to continue edit"));
 }
 
 # ,----
 }
 
 # ,----