X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/51badc960d933f6d0670cc76390c332a31b35d63..28b572a61e71187ecc01ed476e37fbafead11163:/IkiWiki/Plugin/po.pm diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm index 6c6bb2cd1..434d9cf4f 100644 --- a/IkiWiki/Plugin/po.pm +++ b/IkiWiki/Plugin/po.pm @@ -10,7 +10,7 @@ use warnings; use strict; use IkiWiki 3.00; use Encode; -use Locale::Po4a::Common qw(nowrapi18n); +use Locale::Po4a::Common qw(nowrapi18n !/.*/); use Locale::Po4a::Chooser; use Locale::Po4a::Po; use File::Basename; @@ -32,11 +32,10 @@ sub import { hook(type => "getsetup", id => "po", call => \&getsetup); hook(type => "checkconfig", id => "po", call => \&checkconfig); hook(type => "needsbuild", id => "po", call => \&needsbuild); - hook(type => "scan", id => "po", call => \&scan, last =>1); + hook(type => "scan", id => "po", call => \&scan, last => 1); hook(type => "filter", id => "po", call => \&filter); hook(type => "htmlize", id => "po", call => \&htmlize); hook(type => "pagetemplate", id => "po", call => \&pagetemplate, last => 1); - hook(type => "postscan", id => "po", call => \&postscan); hook(type => "rename", id => "po", call => \&renamepages, first => 1); hook(type => "delete", id => "po", call => \&mydelete); hook(type => "change", id => "po", call => \&change); @@ -55,8 +54,6 @@ sub import { inject(name => "IkiWiki::targetpage", call => \&mytargetpage); $origsubs{'urlto'}=\&IkiWiki::urlto; inject(name => "IkiWiki::urlto", call => \&myurlto); - $origsubs{'nicepagetitle'}=\&IkiWiki::nicepagetitle; - inject(name => "IkiWiki::nicepagetitle", call => \&mynicepagetitle); $origsubs{'cgiurl'}=\&IkiWiki::cgiurl; inject(name => "IkiWiki::cgiurl", call => \&mycgiurl); } @@ -106,7 +103,7 @@ sub getsetup () { }, po_translatable_pages => { type => "pagespec", - example => "!*/Discussion", + example => "* and !*/Discussion", description => "PageSpec controlling which pages are translatable", link => "ikiwiki/PageSpec", safe => 1, @@ -119,37 +116,21 @@ sub getsetup () { safe => 1, rebuild => 1, }, - po_translation_status_in_links => { - type => "boolean", - example => 1, - description => "display translation status in links to translations", - safe => 1, - rebuild => 1, - }, - po_strictly_refresh_backlinks => { - type => "boolean", - example => 1, - description => "refresh a page when a backlinked page is changed (can hit performance)", - safe => 1, - rebuild => 1, - }, } sub checkconfig () { - foreach my $field (qw{po_master_language po_slave_languages}) { + foreach my $field (qw{po_master_language}) { if (! exists $config{$field} || ! defined $config{$field}) { error(sprintf(gettext("Must specify %s when using the %s plugin"), $field, 'po')); } } - if (! (keys %{$config{po_slave_languages}})) { - error(gettext("At least one slave language must be defined ". - "in po_slave_languages when using the po plugin")); - } + map { islanguagecode($_) or error(sprintf(gettext("%s is not a valid language code"), $_)); } ($config{po_master_language}{code}, keys %{$config{po_slave_languages}}); + if (! exists $config{po_translatable_pages} || ! defined $config{po_translatable_pages}) { $config{po_translatable_pages}=""; @@ -158,9 +139,7 @@ sub checkconfig () { ! defined $config{po_link_to}) { $config{po_link_to}='default'; } - elsif (! grep { - $config{po_link_to} eq $_ - } ('default', 'current', 'negotiated')) { + elsif ($config{po_link_to} !~ /^(default|current|negotiated)$/) { warn(sprintf(gettext('%s is not a valid value for po_link_to, falling back to po_link_to=default'), $config{po_link_to})); $config{po_link_to}='default'; @@ -169,15 +148,27 @@ sub checkconfig () { warn(gettext('po_link_to=negotiated requires usedirs to be enabled, falling back to po_link_to=default')); $config{po_link_to}='default'; } - if (! exists $config{po_translation_status_in_links} || - ! defined $config{po_translation_status_in_links}) { - $config{po_translation_status_in_links}=1; - } - if (! exists $config{po_strictly_refresh_backlinks} || - ! defined $config{po_strictly_refresh_backlinks}) { - $config{po_strictly_refresh_backlinks}=1; - } + 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}}) { + next if $underlay=~/^locale\//; + + # Underlays containing the po files for slave languages. + foreach my $ll (keys %{$config{po_slave_languages}}) { + 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. + add_underlay("locale/$config{po_master_language}{code}/$underlay"); + } + } } sub needsbuild () { @@ -205,8 +196,6 @@ sub scan (@) { my $page=$params{page}; my $content=$params{content}; - return unless UNIVERSAL::can("IkiWiki::Plugin::link", "import"); - if (istranslation($page)) { foreach my $destpage (@{$links{$page}}) { if (istranslatable($destpage)) { @@ -289,22 +278,20 @@ sub pagetemplate (@) { $template->param(otherlanguages => [otherlanguagesloop($page)]); map add_depends($page, $_), (values %{otherlanguages($page)}); } - # Rely on IkiWiki::Render's genpage() to decide wether - # a discussion link should appear on $page; this is not - # totally accurate, though: some broken links may be generated - # when cgiurl is disabled. - # This compromise avoids some code duplication, and will probably - # prevent future breakage when ikiwiki internals change. - # Known limitations are preferred to future random bugs. - if ($template->param('discussionlink') && istranslation($page)) { - $template->param('discussionlink' => htmllink( - $page, - $destpage, - $masterpage . '/' . gettext("Discussion"), - noimageinline => 1, - forcesubpage => 0, - linktext => gettext("Discussion"), + if ($config{discussion} && istranslation($page)) { + my $discussionlink=gettext("discussion"); + if ($page !~ /.*\/\Q$discussionlink\E$/i && + (length $config{cgiurl} || + exists $links{$masterpage."/".$discussionlink})) { + $template->param('discussionlink' => htmllink( + $page, + $destpage, + $masterpage . '/' . gettext("Discussion"), + noimageinline => 1, + forcesubpage => 0, + linktext => gettext("Discussion"), )); + } } # Remove broken parentlink to ./index.html on home page's translations. # It works because this hook has the "last" parameter set, to ensure it @@ -316,23 +303,11 @@ sub pagetemplate (@) { } } # }}} -sub postscan (@) { - my %params = @_; - - return unless $config{po_strictly_refresh_backlinks}; - - my $page = $params{page}; - # backlinks involve back-dependencies, so that nicepagetitle effects, - # such as translation status displayed in links, are updated - use IkiWiki::Render; - map add_depends($page, $_), keys %{$IkiWiki::backlinks{$page}}; -} - # Add the renamed page translations to the list of to-be-renamed pages. -sub renamepages(@) { +sub renamepages (@) { my %params = @_; - my @torename = @{$params{torename}}; + my %torename = %{$params{torename}}; my $session = $params{session}; # Save the page(s) the user asked to rename, so that our @@ -342,35 +317,36 @@ sub renamepages(@) { # - a user trying to directly rename a translation # This is why this hook has to be run first, before the list of pages # to rename is modified by other plugins. - $session->param(po_orig_torename => \@torename); + my @orig_torename; + @orig_torename=@{$session->param("po_orig_torename")} + if defined $session->param("po_orig_torename"); + push @orig_torename, $torename{src}; + $session->param(po_orig_torename => \@orig_torename); IkiWiki::cgi_savesession($session); - my @ret=@torename; - # iterate on @torename and push onto @ret, so that we don't iterate - # on the items we added ourselves - foreach my $rename (@torename) { - next unless istranslatable($rename->{src}); - my %otherpages=%{otherlanguages($rename->{src})}; - while (my ($lang, $otherpage) = each %otherpages) { - push @ret, { - src => $otherpage, - srcfile => $pagesources{$otherpage}, - dest => otherlanguage($rename->{dest}, $lang), - destfile => $rename->{dest}.".".$lang.".po", - required => 0, - }; - } + return () unless istranslatable($torename{src}); + + my @ret; + my %otherpages=%{otherlanguages($torename{src})}; + while (my ($lang, $otherpage) = each %otherpages) { + push @ret, { + src => $otherpage, + srcfile => $pagesources{$otherpage}, + dest => otherlanguage($torename{dest}, $lang), + destfile => $torename{dest}.".".$lang.".po", + required => 0, + }; } return @ret; } -sub mydelete(@) { +sub mydelete (@) { my @deleted=@_; map { deletetranslations($_) } grep istranslatablefile($_), @deleted; } -sub change(@) { +sub change (@) { my @rendered=@_; # All meta titles are first extracted at scan time, i.e. before we turn @@ -378,14 +354,14 @@ sub change(@) { # PO files breaks the meta plugin's parsing enough to save ugly titles # to %pagestate at this time. # - # Then, at render time, every page's passes on row through the Great + # Then, at render time, every page passes in turn through the Great # Rendering Chain (filter->preprocess->linkify->htmlize), and the meta # plugin's preprocess hook is this time in a position to correctly # extract the titles from slave pages. # - # This is, unfortunately, too late: if the page A, linking to the page B, - # is rendered before B, it will display the wrongly-extracted meta title - # as the link text to B. + # This is, unfortunately, too late: if the page A, linking to the page + # B, is rendered before B, it will display the wrongly-extracted meta + # title as the link text to B. # # On the one hand, such a corner case only happens on rebuild: on # refresh, every rendered page is fixed to contain correct meta titles. @@ -412,22 +388,26 @@ sub change(@) { 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 $page=pagename($file); my $masterfile=srcfile($file); + my $page=pagename($file); my $updated_pot_file=0; - # 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 # refreshed, e.g. because of a dependency. - if ((grep { $_ eq $pagesources{$page} } @origneedsbuild) - || ! -e potfile($masterfile)) { + if ($masterfile eq "$config{srcdir}/$file" && + ((grep { $_ eq $pagesources{$page} } @origneedsbuild) + || ! -e potfile($masterfile))) { refreshpot($masterfile); $updated_pot_file=1; } my @pofiles; - map { - push @pofiles, $_ if ($updated_pot_file || ! -e $_); - } (pofiles($masterfile)); + foreach my $po (pofiles($masterfile)) { + next if ! $updated_pot_file && ! -e $po; + next if grep { $po=~/\Q$_\E/ } @{$config{underlaydirs}}; + push @pofiles, $po; + } if (@pofiles) { refreshpofiles($masterfile, @pofiles); map { IkiWiki::rcs_add($_) } @pofiles if $config{rcs}; @@ -461,8 +441,8 @@ sub canremove (@) { 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; } @@ -480,9 +460,9 @@ sub canrename (@) { # by looking for the master page in the list of to-be-renamed pages we # saved early in the renaming process. my $orig_torename = $session->param("po_orig_torename"); - unless (grep { $_->{src} eq $masterpage } @{$orig_torename}) { - return gettext("Can not rename a translation. Renaming the master page, ". - "though, renames its translations as well."); + unless (grep { $_ eq $masterpage } @{$orig_torename}) { + return gettext("Can not rename a translation. If the master page is renamed, ". + "however, its translations will be renamed as well."); } } return undef; @@ -636,18 +616,6 @@ sub myurlto ($$;$) { } } -sub mynicepagetitle ($;$) { - my ($page, $unescaped) = (shift, shift); - - my $res = $origsubs{'nicepagetitle'}->($page, $unescaped); - return $res unless istranslation($page); - return $res unless $config{po_translation_status_in_links}; - my @caller = caller(1); - return $res if (exists $caller[3] && defined $caller[3] - && $caller[3] eq "IkiWiki::Plugin::parentlinks::parentlinks"); - return $res.' ('.percenttranslated($page).' %)'; -} - sub mycgiurl (@) { my %params=@_; @@ -710,9 +678,9 @@ sub istranslatablefile ($) { my $file=shift; return 0 unless defined $file; - return 0 if defined pagetype($file) && pagetype($file) eq 'po'; + my $type=pagetype($file); + return 0 if ! defined $type || $type eq 'po'; return 0 if $file =~ /\.pot$/; - return 0 unless -e "$config{srcdir}/$file"; # underlay dirs may be read-only return 1 if pagespec_match(pagename($file), $config{po_translatable_pages}); return; } @@ -836,9 +804,10 @@ sub refreshpot ($) { $doc->{TT}{file_in_charset} = 'utf-8'; $doc->{TT}{file_out_charset} = 'utf-8'; $doc->read($masterfile); - # let's cheat a bit to force porefs option to be passed to Locale::Po4a::Po; - # this is undocument use of internal Locale::Po4a::TransTractor's data, - # compulsory since this module prevents us from using the porefs option. + # let's cheat a bit to force porefs option to be passed to + # Locale::Po4a::Po; this is undocument use of internal + # Locale::Po4a::TransTractor's data, compulsory since this module + # prevents us from using the porefs option. $doc->{TT}{po_out}=Locale::Po4a::Po->new({ 'porefs' => 'none' }); $doc->{TT}{po_out}->set_charset('utf-8'); # do the actual work @@ -859,7 +828,7 @@ sub refreshpofiles ($@) { foreach my $pofile (@pofiles) { IkiWiki::prep_writefile(basename($pofile),dirname($pofile)); if (-e $pofile) { - system("msgmerge", "-U", "--backup=none", $pofile, $potfile) == 0 + system("msgmerge", "-q", "-U", "--backup=none", $pofile, $potfile) == 0 or error("po(refreshpofiles) ". sprintf(gettext("failed to update %s"), $pofile)); @@ -956,10 +925,10 @@ sub otherlanguagesloop ($) { } } return sort { - return -1 if $a->{code} eq $config{po_master_language}{code}; - return 1 if $b->{code} eq $config{po_master_language}{code}; - return $a->{language} cmp $b->{language}; - } @ret; + return -1 if $a->{code} eq $config{po_master_language}{code}; + return 1 if $b->{code} eq $config{po_master_language}{code}; + return $a->{language} cmp $b->{language}; + } @ret; } sub homepageurl (;$) { @@ -1121,8 +1090,8 @@ sub isvalidpo ($) { 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")); } # ,----