X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/5948bb01cb45f715befd107356873a3d3bb1d7d9..a0b55ac3cd4f840f62d0441e3b1fe9b95ec15007:/IkiWiki/Plugin/po.pm?ds=sidebyside diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm index a2010e1be..a79e7d7f0 100644 --- a/IkiWiki/Plugin/po.pm +++ b/IkiWiki/Plugin/po.pm @@ -25,10 +25,12 @@ use File::Temp; use Memoize; use UNIVERSAL; +my ($master_language_code, $master_language_name); my %translations; my @origneedsbuild; my %origsubs; my @slavelanguages; # language codes ordered as in config po_slave_languages +my %slavelanguages; # language code to name lookup memoize("istranslatable"); memoize("_istranslation"); @@ -39,7 +41,6 @@ sub import { 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 => "rescan", id => "po", call => \&rescan); hook(type => "filter", id => "po", call => \&filter); hook(type => "htmlize", id => "po", call => \&htmlize); hook(type => "pagetemplate", id => "po", call => \&pagetemplate, last => 1); @@ -90,16 +91,13 @@ sub import { sub getsetup () { return plugin => { - safe => 0, + safe => 1, rebuild => 1, # format plugin section => "format", }, po_master_language => { type => "string", - example => { - 'code' => 'en', - 'name' => 'English' - }, + example => "en|English", description => "master language (non-PO files)", safe => 1, rebuild => 1, @@ -111,7 +109,7 @@ sub getsetup () { 'es|Español', 'de|Deutsch' ], - description => "slave languages (PO files)", + description => "slave languages (translated via PO files) format: ll|Langname", safe => 1, rebuild => 1, }, @@ -133,39 +131,49 @@ sub getsetup () { } sub checkconfig () { - 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 (exists $config{po_master_language}) { + if (! ref $config{po_master_language}) { + ($master_language_code, $master_language_name)= + splitlangpair($config{po_master_language}); + } + else { + $master_language_code=$config{po_master_language}{code}; + $master_language_name=$config{po_master_language}{name}; + $config{po_master_language}=joinlangpair($master_language_code, $master_language_name); } } + if (! defined $master_language_code) { + $master_language_code='en'; + } + if (! defined $master_language_name) { + $master_language_name='English'; + } if (ref $config{po_slave_languages} eq 'ARRAY') { - my %slaves; foreach my $pair (@{$config{po_slave_languages}}) { - my ($code, $name) = ( $pair =~ /^([a-z]{2})\|(.+)$/ ); - if (!defined $code || !defined $name) { - error(sprintf(gettext("%s has invalid syntax: must use CODE|NAME"), - $pair)); + my ($code, $name)=splitlangpair($pair); + if (defined $code && ! exists $slavelanguages{$code}) { + push @slavelanguages, $code; + $slavelanguages{$code} = $name; } - $slaves{$code} = $name; - push @slavelanguages, $code; - } - $config{po_slave_languages} = \%slaves; } elsif (ref $config{po_slave_languages} eq 'HASH') { + %slavelanguages=%{$config{po_slave_languages}}; @slavelanguages = sort { $config{po_slave_languages}->{$a} cmp $config{po_slave_languages}->{$b}; - } keys %{$config{po_slave_languages}}; + } keys %slavelanguages; + $config{po_slave_languages}=[ + map { joinlangpair($_, $slavelanguages{$_}) } @slavelanguages + ] } - delete $config{po_slave_languages}{$config{po_master_language}{code}};; + delete $slavelanguages{$master_language_code}; map { islanguagecode($_) or error(sprintf(gettext("%s is not a valid language code"), $_)); - } ($config{po_master_language}{code}, @slavelanguages); + } ($master_language_code, @slavelanguages); if (! exists $config{po_translatable_pages} || ! defined $config{po_translatable_pages}) { @@ -199,11 +207,11 @@ sub checkconfig () { if -d "$config{underlaydirbase}/po/$ll/$underlay"; } - if ($config{po_master_language}{code} ne 'en') { + if ($master_language_code ne 'en') { # Add underlay containing translated source files # for the master language. - add_underlay("locale/$config{po_master_language}{code}/$underlay") - if -d "$config{underlaydirbase}/locale/$config{po_master_language}{code}/$underlay"; + add_underlay("locale/$master_language_code/$underlay") + if -d "$config{underlaydirbase}/locale/$master_language_code/$underlay"; } } } @@ -222,40 +230,65 @@ sub needsbuild () { foreach my $master (keys %translations) { map add_depends($_, $master), values %{otherlanguages_pages($master)}; } + + return $needsbuild; } -# Massage the recorded state of internal links so that: -# - it matches the actually generated links, rather than the links as written -# in the pages' source -# - backlinks are consistent in all cases sub scan (@) { my %params=@_; my $page=$params{page}; my $content=$params{content}; - - if (istranslation($page)) { - foreach my $destpage (@{$links{$page}}) { - if (istranslatable($destpage)) { - # 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); - last; - } - } + my $run_by_po=$params{run_by_po}; + + # Massage the recorded state of internal links so that: + # - it matches the actually generated links, rather than the links as + # written in the pages' source + # - backlinks are consistent in all cases + + # A second scan pass is made over translation pages, so as an + # optimization, we only do so on the second pass in this case, + # i.e. when this hook is called by itself. + if ($run_by_po && istranslation($page)) { + # replace the occurence of $destpage in $links{$page} + my @orig_links = @{$links{$page}}; + $links{$page} = []; + foreach my $destpage (@orig_links) { + if (istranslatedto($destpage, lang($page))) { + add_link($page, $destpage . '.' . lang($page)); + } + else { + add_link($page, $destpage); } } } - elsif (! istranslatable($page) && ! istranslation($page)) { + # No second scan pass is done for a non-translation page, so + # links massaging must happen on first pass in this case. + elsif (! $run_by_po && ! istranslatable($page) && ! istranslation($page)) { foreach my $destpage (@{$links{$page}}) { if (istranslatable($destpage)) { # make sure any destpage's translations has # $page in its backlinks - push @{$links{$page}}, - values %{otherlanguages_pages($destpage)}; + foreach my $link (values %{otherlanguages_pages($destpage)}) { + add_link($page, $link); + } } } } + + # Re-run the preprocess hooks in scan mode, then the scan hooks, + # over the po-to-markup converted content + return if $run_by_po; # avoid looping endlessly + return unless istranslation($page); + $content = po_to_markup($page, $content); + require IkiWiki; + IkiWiki::preprocess($page, $page, $content, 1); + IkiWiki::run_hooks(scan => sub { + shift->( + page => $page, + content => $content, + run_by_po => 1, + ); + }); } # We use filter to convert PO to the master page's format, @@ -273,26 +306,6 @@ sub filter (@) { return $content; } -# re-run the scan hooks and run the preprocess ones in scan -# mode on the po-to-markup converted content -sub rescan (@) { - my %params=@_; - my $page=$params{page}; - my $content=$params{content}; - - return unless istranslation($page); - - $content = po_to_markup($page, $content); - require IkiWiki; - IkiWiki::run_hooks(scan => sub { - shift->( - page => $page, - content => $content, - ); - }); - IkiWiki::preprocess($page, $page, $content, 1); -} - sub htmlize (@) { my %params=@_; @@ -508,7 +521,7 @@ sub formbuilder_setup (@) { if ($form->field("do") eq "create") { # Warn the user: new pages must be written in master language. my $template=template("pocreatepage.tmpl"); - $template->param(LANG => $config{po_master_language}{name}); + $template->param(LANG => $master_language_name); $form->tmpl_param(message => $template->output); } elsif ($form->field("do") eq "edit") { @@ -583,7 +596,7 @@ sub mybestlink ($$) { my $res=$origsubs{'bestlink'}->(masterpage($page), $link); my @caller = caller(1); if (length $res - && istranslatable($res) + && istranslatedto($res, lang($page)) && istranslation($page) && !(exists $caller[3] && defined $caller[3] && ($caller[3] eq "IkiWiki::PageSpec::match_link"))) { @@ -597,7 +610,7 @@ sub mybeautify_urlpath ($) { my $res=$origsubs{'beautify_urlpath'}->($url); 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.$master_language_code.$config{htmlext}\E$!/!; $res =~ s!/\Qindex.$config{htmlext}\E$!/!; map { $res =~ s!/\Qindex.$_.$config{htmlext}\E$!/!; @@ -764,6 +777,15 @@ sub istranslatable ($) { return; } +sub istranslatedto ($$) { + my $page=shift; + my $destlang = shift; + + $page=~s#^/##; + return 0 unless istranslatable($page); + exists $pagesources{otherlanguage_page($page, $destlang)}; +} + sub _istranslation ($) { my $page=shift; @@ -779,7 +801,7 @@ sub _istranslation ($) { return 0 unless defined $masterpage && defined $lang && length $masterpage && length $lang && defined $pagesources{$masterpage} - && defined $config{po_slave_languages}{$lang}; + && defined $slavelanguages{$lang}; return (maybe_add_leading_slash($masterpage, $hasleadingslash), $lang) if istranslatable($masterpage); @@ -811,7 +833,7 @@ sub lang ($) { if (1 < (my ($masterpage, $lang) = _istranslation($page))) { return $lang; } - return $config{po_master_language}{code}; + return $master_language_code; } sub islanguagecode ($) { @@ -824,7 +846,7 @@ sub otherlanguage_page ($$) { my $page=shift; my $code=shift; - return masterpage($page) if $code eq $config{po_master_language}{code}; + return masterpage($page) if $code eq $master_language_code; return masterpage($page) . '.' . $code; } @@ -838,9 +860,12 @@ sub otherlanguages_codes ($) { return \@ret unless istranslation($page) || istranslatable($page); my $curlang=lang($page); foreach my $lang - ($config{po_master_language}{code}, @slavelanguages) { + ($master_language_code, @slavelanguages) { next if $lang eq $curlang; - push @ret, $lang; + if ($lang eq $master_language_code || + istranslatedto(masterpage($page), $lang)) { + push @ret, $lang; + } } return \@ret; } @@ -992,10 +1017,10 @@ sub percenttranslated ($) { sub languagename ($) { my $code=shift; - return $config{po_master_language}{name} - if $code eq $config{po_master_language}{code}; - return $config{po_slave_languages}{$code} - if defined $config{po_slave_languages}{$code}; + return $master_language_name + if $code eq $master_language_code; + return $slavelanguages{$code} + if defined $slavelanguages{$code}; return; } @@ -1006,13 +1031,13 @@ sub otherlanguagesloop ($) { if (istranslation($page)) { push @ret, { url => urlto_with_orig_beautiful_urlpath(masterpage($page), $page), - code => $config{po_master_language}{code}, - language => $config{po_master_language}{name}, + code => $master_language_code, + language => $master_language_name, master => 1, }; } foreach my $lang (@{otherlanguages_codes($page)}) { - next if $lang eq $config{po_master_language}{code}; + next if $lang eq $master_language_code; my $otherpage = otherlanguage_page($page, $lang); push @ret, { url => urlto_with_orig_beautiful_urlpath($otherpage, $page), @@ -1217,6 +1242,27 @@ sub po4a_options($) { return %options; } +sub splitlangpair ($) { + my $pair=shift; + + my ($code, $name) = ( $pair =~ /^([a-z]{2})\|(.+)$/ ); + if (! defined $code || ! defined $name || + ! length $code || ! length $name) { + # not a fatal error to avoid breaking if used with web setup + warn sprintf(gettext("%s has invalid syntax: must use CODE|NAME"), + $pair); + } + + return $code, $name; +} + +sub joinlangpair ($$) { + my $code=shift; + my $name=shift; + + return "$code|$name"; +} + # ,---- # | PageSpecs # `----