}
}
-# 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,
sub change (@) {
my @rendered=@_;
- # All meta titles are first extracted at scan time, i.e. before we turn
- # PO files back into translated markdown; escaping of double-quotes in
- # PO files breaks the meta plugin's parsing enough to save ugly titles
- # to %pagestate at this time.
- #
- # 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.
- #
- # On the one hand, such a corner case only happens on rebuild: on
- # refresh, every rendered page is fixed to contain correct meta titles.
- # On the other hand, it can take some time to get every page fixed.
- # We therefore re-render every rendered page after a rebuild to fix them
- # at once. As this more or less doubles the time needed to rebuild the
- # wiki, we do so only when really needed.
-
- if (@rendered
- && exists $config{rebuild} && defined $config{rebuild} && $config{rebuild}
- && UNIVERSAL::can("IkiWiki::Plugin::meta", "getsetup")
- && exists $config{meta_overrides_page_title}
- && defined $config{meta_overrides_page_title}
- && $config{meta_overrides_page_title}) {
- debug(sprintf(gettext("rebuilding all pages to fix meta titles")));
- resetalreadyfiltered();
- require IkiWiki::Render;
- foreach my $file (@rendered) {
- IkiWiki::render($file, sprintf(gettext("building %s"), $file));
- }
- }
-
my $updated_po_files=0;
# Refresh/create POT and PO files as needed.
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"))) {
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;
foreach my $lang
($config{po_master_language}{code}, @slavelanguages) {
next if $lang eq $curlang;
- push @ret, $lang;
+ if ($lang eq $config{po_master_language}{code} ||
+ istranslatedto(masterpage($page), $lang)) {
+ push @ret, $lang;
+ }
}
return \@ret;
}
}
}
-use Test::More tests => 68;
+use Test::More tests => 91;
BEGIN { use_ok("IkiWiki"); }
$config{po_translatable_pages}='index or test1 or test2 or translatable';
$config{po_link_to}='negotiated';
IkiWiki::loadplugins();
+ok(IkiWiki::loadplugin('meta'), "meta plugin loaded");
ok(IkiWiki::loadplugin('po'), "po plugin loaded");
IkiWiki::checkconfig();
$pagesources{'index.fr'}='index.fr.po';
$pagesources{'index.es'}='index.es.po';
$pagesources{'test1'}='test1.mdwn';
+$pagesources{'test1.es'}='test1.es.po';
$pagesources{'test1.fr'}='test1.fr.po';
$pagesources{'test2'}='test2.mdwn';
$pagesources{'test2.es'}='test2.es.po';
}
### populate srcdir
-writefile('index.mdwn', $config{srcdir}, '[[translatable]] [[nontranslatable]]');
-writefile('test1.mdwn', $config{srcdir}, 'test1 content');
+writefile('index.mdwn', $config{srcdir},
+ "[[!meta title=\"index title\"]]\n[[translatable]] [[nontranslatable]]");
+writefile('test1.mdwn', $config{srcdir},
+ "[[!meta title=\"test1 title\"]]\ntest1 content");
writefile('test2.mdwn', $config{srcdir}, 'test2 content');
writefile('test3.mdwn', $config{srcdir}, 'test3 content');
writefile('translatable.mdwn', $config{srcdir}, '[[nontranslatable]]');
ok(IkiWiki::Plugin::po::istranslation('index.fr'), "index.fr is a translation");
ok(IkiWiki::Plugin::po::istranslation('index.es'), "index.es is a translation");
ok(IkiWiki::Plugin::po::istranslation('/index.fr'), "/index.fr is a translation");
+ok(IkiWiki::Plugin::po::istranslatable('test1'), "test1 is translatable");
+ok(IkiWiki::Plugin::po::istranslation('test1.es'), "test1.es is a translation");
+ok(IkiWiki::Plugin::po::istranslation('test1.fr'), "test1.fr is a translation");
ok(IkiWiki::Plugin::po::istranslatable('test2'), "test2 is translatable");
ok(! IkiWiki::Plugin::po::istranslation('test2'), "test2 is not a translation");
ok(! IkiWiki::Plugin::po::istranslatable('test3'), "test3 is not translatable");
is(IkiWiki::beautify_urlpath('test1/index.html'), './test1/', "$msgprefix test1/index.html");
is(IkiWiki::beautify_urlpath('test1/index.en.html'), './test1/', "$msgprefix test1/index.en.html");
is(IkiWiki::beautify_urlpath('test1/index.fr.html'), './test1/', "$msgprefix test1/index.fr.html");
+
+### re-scan
+refresh_n_scan('index.mdwn');
+is($pagestate{'index'}{meta}{title}, 'index title');
+is($pagestate{'index.es'}{meta}{title}, 'index title');
+is($pagestate{'index.fr'}{meta}{title}, 'index title');
+refresh_n_scan('test1.mdwn');
+is($pagestate{'test1'}{meta}{title}, 'test1 title');
+is($pagestate{'test1.es'}{meta}{title}, 'test1 title');
+is($pagestate{'test1.fr'}{meta}{title}, 'test1 title');
+
+### istranslatedto
+ok(IkiWiki::Plugin::po::istranslatedto('index', 'es'));
+ok(IkiWiki::Plugin::po::istranslatedto('index', 'fr'));
+ok(! IkiWiki::Plugin::po::istranslatedto('index', 'cz'));
+ok(IkiWiki::Plugin::po::istranslatedto('test1', 'es'));
+ok(IkiWiki::Plugin::po::istranslatedto('test1', 'fr'));
+ok(! IkiWiki::Plugin::po::istranslatedto('test1', 'cz'));
+ok(! IkiWiki::Plugin::po::istranslatedto('nontranslatable', 'es'));
+ok(! IkiWiki::Plugin::po::istranslatedto('nontranslatable', 'cz'));
+ok(! IkiWiki::Plugin::po::istranslatedto('test1.es', 'fr'));
+ok(! IkiWiki::Plugin::po::istranslatedto('test1.fr', 'es'));