summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--IkiWiki.pm15
-rw-r--r--IkiWiki/Plugin/editpage.pm2
-rw-r--r--IkiWiki/Plugin/inline.pm4
-rw-r--r--IkiWiki/Plugin/po.pm190
-rw-r--r--IkiWiki/Plugin/sidebar.pm2
-rw-r--r--IkiWiki/Render.pm4
-rw-r--r--doc/ikiwiki/pagespec/po.mdwn2
-rw-r--r--doc/plugins/po.mdwn28
-rw-r--r--doc/plugins/po/discussion.mdwn17
-rw-r--r--doc/plugins/write.mdwn4
10 files changed, 186 insertions, 82 deletions
diff --git a/IkiWiki.pm b/IkiWiki.pm
index 35b38df46..7b5fd283d 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
@@ -1074,6 +1074,13 @@ sub urlto ($$;$) {
return beautify_urlpath($link);
}
+sub isselflink ($$) {
+ my $page=shift;
+ my $link=shift;
+
+ return $page eq $link;
+}
+
sub htmllink ($$$;@) {
my $lpage=shift; # the page doing the linking
my $page=shift; # the page that will contain the link (different for inline)
@@ -1099,7 +1106,7 @@ sub htmllink ($$$;@) {
}
return "<span class=\"selflink\">$linktext</span>"
- if length $bestlink && $page eq $bestlink &&
+ if length $bestlink && isselflink($page, $bestlink) &&
! defined $opts{anchor};
if (! $destsources{$bestlink}) {
@@ -1389,14 +1396,16 @@ sub preprocess ($$$;$$) {
return $content;
}
-sub filter ($$$) {
+sub filter ($$$;$) {
my $page=shift;
my $destpage=shift;
my $content=shift;
+ my $fullpage=shift;
+ $fullpage = 0 unless defined $fullpage;
run_hooks(filter => sub {
$content=shift->(page => $page, destpage => $destpage,
- content => $content);
+ content => $content, fullpage => $fullpage);
});
return $content;
diff --git a/IkiWiki/Plugin/editpage.pm b/IkiWiki/Plugin/editpage.pm
index 1a04a72b5..706630203 100644
--- a/IkiWiki/Plugin/editpage.pm
+++ b/IkiWiki/Plugin/editpage.pm
@@ -187,7 +187,7 @@ sub cgi_editpage ($$) {
my $preview=htmlize($page, $page, $type,
linkify($page, $page,
preprocess($page, $page,
- filter($page, $page, $content), 0, 1)));
+ filter($page, $page, $content, 'fullpage'), 0, 1)));
run_hooks(format => sub {
$preview=shift->(
page => $page,
diff --git a/IkiWiki/Plugin/inline.pm b/IkiWiki/Plugin/inline.pm
index 715a3d652..a04dd6630 100644
--- a/IkiWiki/Plugin/inline.pm
+++ b/IkiWiki/Plugin/inline.pm
@@ -403,7 +403,7 @@ sub preprocess_inline (@) {
linkify($page, $params{destpage},
preprocess($page, $params{destpage},
filter($page, $params{destpage},
- readfile(srcfile($file)))));
+ readfile(srcfile($file)), 'fullpage')));
}
else {
$ret.="\n".
@@ -474,7 +474,7 @@ sub get_inline_content ($$) {
linkify($page, $destpage,
preprocess($page, $destpage,
filter($page, $destpage,
- readfile(srcfile($file))))));
+ readfile(srcfile($file)), 'fullpage'))));
$nested--;
if (isinternal($page)) {
# make inlined text of internal pages searchable
diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm
index 86d5087f4..552b6b51b 100644
--- a/IkiWiki/Plugin/po.pm
+++ b/IkiWiki/Plugin/po.pm
@@ -28,6 +28,7 @@ use UNIVERSAL;
my %translations;
my @origneedsbuild;
my %origsubs;
+my @slavelanguages; # orderer as in config po_slave_languages
memoize("istranslatable");
memoize("_istranslation");
@@ -64,6 +65,8 @@ sub import {
inject(name => "IkiWiki::cgiurl", call => \&mycgiurl);
$origsubs{'rootpage'}=\&IkiWiki::rootpage;
inject(name => "IkiWiki::rootpage", call => \&myrootpage);
+ $origsubs{'isselflink'}=\&IkiWiki::isselflink;
+ inject(name => "IkiWiki::isselflink", call => \&myisselflink);
}
}
@@ -102,11 +105,11 @@ sub getsetup () {
},
po_slave_languages => {
type => "string",
- example => {
+ example => [
'fr' => 'Français',
'es' => 'Español',
'de' => 'Deutsch'
- },
+ ],
description => "slave languages (PO files)",
safe => 1,
rebuild => 1,
@@ -135,6 +138,21 @@ sub checkconfig () {
$field, 'po'));
}
}
+
+ if (ref $config{po_slave_languages} eq 'ARRAY') {
+ my %slaves;
+ for (my $i=0; $i<@{$config{po_slave_languages}}; $i = $i + 2) {
+ $slaves{$config{po_slave_languages}->[$i]} = $config{po_slave_languages}->[$i + 1];
+ push @slavelanguages, $config{po_slave_languages}->[$i];
+ }
+ $config{po_slave_languages} = \%slaves;
+ }
+ elsif (ref $config{po_slave_languages} eq 'HASH') {
+ @slavelanguages = sort {
+ $config{po_slave_languages}->{$a} cmp $config{po_slave_languages}->{$b};
+ } keys %{$config{po_slave_languages}};
+ }
+
delete $config{po_slave_languages}{$config{po_master_language}{code}};;
map {
@@ -195,7 +213,7 @@ sub needsbuild () {
# make existing translations depend on the corresponding master page
foreach my $master (keys %translations) {
- map add_depends($_, $master), values %{otherlanguages($master)};
+ map add_depends($_, $master), values %{otherlanguages_pages($master)};
}
}
@@ -227,7 +245,7 @@ sub scan (@) {
# make sure any destpage's translations has
# $page in its backlinks
push @{$links{$page}},
- values %{otherlanguages($destpage)};
+ values %{otherlanguages_pages($destpage)};
}
}
}
@@ -241,6 +259,12 @@ sub filter (@) {
my $page = $params{page};
my $destpage = $params{destpage};
my $content = $params{content};
+ my $fullpage = $params{fullpage};
+
+ unless ($fullpage) {
+ return $content;
+ }
+
if (istranslation($page) && ! alreadyfiltered($page, $destpage)) {
$content = po_to_markup($page, $content);
setalreadyfiltered($page, $destpage);
@@ -285,7 +309,7 @@ sub pagetemplate (@) {
}
if ($template->query(name => "otherlanguages")) {
$template->param(otherlanguages => [otherlanguagesloop($page)]);
- map add_depends($page, $_), (values %{otherlanguages($page)});
+ map add_depends($page, $_), (values %{otherlanguages_pages($page)});
}
if ($config{discussion} && istranslation($page)) {
if ($page !~ /.*\/\Q$config{discussionpage}\E$/i &&
@@ -338,12 +362,12 @@ sub renamepages (@) {
return () unless istranslatable($torename{src});
my @ret;
- my %otherpages=%{otherlanguages($torename{src})};
+ my %otherpages=%{otherlanguages_pages($torename{src})};
while (my ($lang, $otherpage) = each %otherpages) {
push @ret, {
src => $otherpage,
srcfile => $pagesources{$otherpage},
- dest => otherlanguage($torename{dest}, $lang),
+ dest => otherlanguage_page($torename{dest}, $lang),
destfile => $torename{dest}.".".$lang.".po",
required => 0,
};
@@ -675,6 +699,17 @@ sub myrootpage (@) {
return $rootpage;
}
+sub myisselflink ($$) {
+ my $page=shift;
+ my $link=shift;
+
+ return 1 if $origsubs{'isselflink'}->($page, $link);
+ if (istranslation($page)) {
+ return $origsubs{'isselflink'}->(masterpage($page), $link);
+ }
+ return;
+}
+
# ,----
# | Blackboxes for private data
# `----
@@ -799,7 +834,7 @@ sub islanguagecode ($) {
return $code =~ /^[a-z]{2}$/;
}
-sub otherlanguage ($$) {
+sub otherlanguage_page ($$) {
my $page=shift;
my $code=shift;
@@ -807,17 +842,31 @@ sub otherlanguage ($$) {
return masterpage($page) . '.' . $code;
}
-sub otherlanguages ($) {
+# Returns the list of other languages codes: the master language comes first,
+# then the codes are ordered the same way as in po_slave_languages, if it is
+# an array, or in the language name lexical order, if it is a hash.
+sub otherlanguages_codes ($) {
my $page=shift;
- my %ret;
- return \%ret unless istranslation($page) || istranslatable($page);
+ my @ret;
+ return \@ret unless istranslation($page) || istranslatable($page);
my $curlang=lang($page);
foreach my $lang
- ($config{po_master_language}{code}, keys %{$config{po_slave_languages}}) {
+ ($config{po_master_language}{code}, @slavelanguages) {
next if $lang eq $curlang;
- $ret{$lang}=otherlanguage($page, $lang);
+ push @ret, $lang;
}
+ return \@ret;
+}
+
+sub otherlanguages_pages ($) {
+ my $page=shift;
+
+ my %ret;
+ map {
+ $ret{$_} = otherlanguage_page($page, $_)
+ } otherlanguages_codes($page);
+
return \%ret;
}
@@ -848,18 +897,18 @@ sub refreshpot ($) {
my $masterfile=shift;
my $potfile=potfile($masterfile);
- my %options = ("markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0);
- my $doc=Locale::Po4a::Chooser::new('text',%options);
+ my $doc=Locale::Po4a::Chooser::new(po4a_type($masterfile),
+ po4a_options($masterfile));
$doc->{TT}{utf_mode} = 1;
- $doc->{TT}{file_in_charset} = 'utf-8';
- $doc->{TT}{file_out_charset} = 'utf-8';
+ $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.
$doc->{TT}{po_out}=Locale::Po4a::Po->new({ 'porefs' => 'none' });
- $doc->{TT}{po_out}->set_charset('utf-8');
+ $doc->{TT}{po_out}->set_charset('UTF-8');
# do the actual work
$doc->parse;
IkiWiki::prep_writefile(basename($potfile),dirname($potfile));
@@ -940,15 +989,13 @@ sub percenttranslated ($) {
return gettext("N/A") unless istranslation($page);
my $file=srcfile($pagesources{$page});
my $masterfile = srcfile($pagesources{masterpage($page)});
- my %options = (
- "markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0,
- );
- my $doc=Locale::Po4a::Chooser::new('text',%options);
+ my $doc=Locale::Po4a::Chooser::new(po4a_type($masterfile),
+ po4a_options($masterfile));
$doc->process(
'po_in_name' => [ $file ],
'file_in_name' => [ $masterfile ],
- 'file_in_charset' => 'utf-8',
- 'file_out_charset' => 'utf-8',
+ 'file_in_charset' => 'UTF-8',
+ 'file_out_charset' => 'UTF-8',
) or error("po(percenttranslated) ".
sprintf(gettext("failed to translate %s"), $page));
my ($percent,$hit,$queries) = $doc->stats();
@@ -970,30 +1017,25 @@ sub otherlanguagesloop ($) {
my $page=shift;
my @ret;
- my %otherpages=%{otherlanguages($page)};
- while (my ($lang, $otherpage) = each %otherpages) {
- if (istranslation($page) && masterpage($page) eq $otherpage) {
- push @ret, {
- url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
- code => $lang,
- language => languagename($lang),
- master => 1,
- };
- }
- elsif (istranslation($otherpage)) {
- push @ret, {
- url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
- code => $lang,
- language => languagename($lang),
- percent => percenttranslated($otherpage),
- }
+ 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},
+ master => 1,
+ };
+ }
+ foreach my $lang (@{otherlanguages_codes($page)}) {
+ next if $lang eq $config{po_master_language}{code};
+ my $otherpage = otherlanguage_page($page, $lang);
+ push @ret, {
+ url => urlto_with_orig_beautiful_urlpath($otherpage, $page),
+ code => $lang,
+ language => languagename($lang),
+ percent => percenttranslated($otherpage),
}
}
- 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 @ret;
}
sub homepageurl (;$) {
@@ -1094,15 +1136,13 @@ sub po_to_markup ($$) {
or return $fail->(sprintf(gettext("failed to write %s"), $infile));
my $masterfile = srcfile($pagesources{masterpage($page)});
- my %options = (
- "markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0,
- );
- my $doc=Locale::Po4a::Chooser::new('text',%options);
+ my $doc=Locale::Po4a::Chooser::new(po4a_type($masterfile),
+ po4a_options($masterfile));
$doc->process(
'po_in_name' => [ $infile ],
'file_in_name' => [ $masterfile ],
- 'file_in_charset' => 'utf-8',
- 'file_out_charset' => 'utf-8',
+ 'file_in_charset' => 'UTF-8',
+ 'file_out_charset' => 'UTF-8',
) or return $fail->(gettext("failed to translate"));
$doc->write($outfile)
or return $fail->(sprintf(gettext("failed to write %s"), $outfile));
@@ -1160,6 +1200,37 @@ sub isvalidpo ($) {
"to previous page to continue edit"));
}
+sub po4a_type ($) {
+ my $file = shift;
+
+ my $pagetype = pagetype($file);
+ if ($pagetype eq 'html') {
+ return 'xhtml';
+ }
+ return 'text';
+}
+
+sub po4a_options($) {
+ my $file = shift;
+
+ my %options;
+ my $pagetype = pagetype($file);
+
+ if ($pagetype eq 'html') {
+ # how to disable options is not consistent across po4a modules
+ $options{includessi} = '';
+ $options{includeexternal} = 0;
+ }
+ elsif ($pagetype eq 'mdwn') {
+ $options{markdown} = 1;
+ }
+ else {
+ $options{markdown} = 0;
+ }
+
+ return %options;
+}
+
# ,----
# | PageSpecs
# `----
@@ -1220,4 +1291,19 @@ sub match_currentlang ($$;@) {
}
}
+sub match_needstranslation ($$;@) {
+ my $page=shift;
+
+ my $percenttranslated=IkiWiki::Plugin::po::percenttranslated($page);
+ if ($percenttranslated eq 'N/A') {
+ return IkiWiki::FailReason->new("file is not a translation page");
+ }
+ elsif ($percenttranslated < 100) {
+ return IkiWiki::SuccessReason->new("file has $percenttranslated translated");
+ }
+ else {
+ return IkiWiki::FailReason->new("file is fully translated");
+ }
+}
+
1
diff --git a/IkiWiki/Plugin/sidebar.pm b/IkiWiki/Plugin/sidebar.pm
index 2d495db2c..100015cee 100644
--- a/IkiWiki/Plugin/sidebar.pm
+++ b/IkiWiki/Plugin/sidebar.pm
@@ -89,7 +89,7 @@ sub sidebar_content ($) {
return IkiWiki::htmlize($sidebar_page, $page, $sidebar_type,
IkiWiki::linkify($sidebar_page, $page,
IkiWiki::preprocess($sidebar_page, $page,
- IkiWiki::filter($sidebar_page, $page, $content))));
+ IkiWiki::filter($sidebar_page, $page, $content, 'fullpage'))));
}
}
diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
index a653ab2da..233d093ed 100644
--- a/IkiWiki/Render.pm
+++ b/IkiWiki/Render.pm
@@ -232,7 +232,7 @@ sub render ($$) {
linkify($page, $page,
preprocess($page, $page,
filter($page, $page,
- readfile($srcfile)))));
+ readfile($srcfile), 'fullpage'))));
my $output=htmlpage($page);
writefile($output, $config{destdir}, genpage($page, $content));
@@ -837,7 +837,7 @@ sub commandline_render () {
my $content=readfile($srcfile);
my $page=pagename($file);
$pagesources{$page}=$file;
- $content=filter($page, $page, $content);
+ $content=filter($page, $page, $content, 'fullpage');
$content=preprocess($page, $page, $content);
$content=linkify($page, $page, $content);
$content=htmlize($page, $page, $type, $content);
diff --git a/doc/ikiwiki/pagespec/po.mdwn b/doc/ikiwiki/pagespec/po.mdwn
index 40ed9efb6..f8b398575 100644
--- a/doc/ikiwiki/pagespec/po.mdwn
+++ b/doc/ikiwiki/pagespec/po.mdwn
@@ -11,6 +11,8 @@ wiki:
specified as a ISO639-1 (two-letter) language code.
* "`currentlang()`" - tests whether a page is written in the same
language as the current page.
+* "`needstranslation()`" - tests whether a page needs translation
+ work. Only slave pages match this PageSpec.
Note that every non-po page is considered to be written in
`po_master_language`, as specified in `ikiwiki.setup`.
diff --git a/doc/plugins/po.mdwn b/doc/plugins/po.mdwn
index dd85edf3d..30bac7068 100644
--- a/doc/plugins/po.mdwn
+++ b/doc/plugins/po.mdwn
@@ -54,10 +54,10 @@ Supported languages
`po_slave_languages` is used to set the list of supported "slave"
languages, such as:
- po_slave_languages => { 'fr' => 'Français',
+ po_slave_languages => [ 'fr' => 'Français',
'es' => 'Español',
'de' => 'Deutsch',
- }
+ ]
Decide which pages are translatable
-----------------------------------
@@ -130,7 +130,7 @@ lighttpd
--------
Recent versions of lighttpd should be able to use
-`$HTTP["language"]` to configure the translatted pages to be served.
+`$HTTP["language"]` to configure the translated pages to be served.
See [Lighttpd Issue](http://redmine.lighttpd.net/issues/show/1119)
@@ -213,16 +213,16 @@ preferred `$EDITOR`, without needing to be online.
Markup languages support
------------------------
-[[Markdown|mdwn]] is well supported. Some other markup languages supported
-by ikiwiki mostly work, but some pieces of syntax are not rendered
-correctly on the slave pages:
+[[Markdown|mdwn]] and [[html]] are well supported. Some other markup
+languages supported by ikiwiki mostly work, but some pieces of syntax
+are not rendered correctly on the slave pages:
* [[reStructuredText|rst]]: anonymous hyperlinks and internal
cross-references
* [[wikitext]]: conversion of newlines to paragraphs
* [[creole]]: verbatim text is wrapped, tables are broken
-* [[html]] and LaTeX: not supported yet; the dedicated po4a modules
- could be used to support them, but they would need a security audit
+* LaTeX: not supported yet; the dedicated po4a module
+ could be used to support it, but it would need a security audit
* other markup languages have not been tested.
Security
@@ -254,18 +254,6 @@ once [[intrigeri]]'s `meta` branch is merged.
An integration branch, called `meta-po`, merges [[intrigeri]]'s `po`
and `meta` branches, and thus has this additional features.
-Language display order
-----------------------
-
-Jonas pointed out that one might want to control the order that links to
-other languages are listed, for various reasons. Currently, there is no
-order, as `po_slave_languages` is a hash. It would need to be converted
-to an array to support this. (If twere done, twere best done quickly.)
---[[Joey]]
-
-> Done in my po branch, preserving backward compatibility. Please
-> review :) --[[intrigeri]]
-
Pagespecs
---------
diff --git a/doc/plugins/po/discussion.mdwn b/doc/plugins/po/discussion.mdwn
index 27683f1ea..73858c818 100644
--- a/doc/plugins/po/discussion.mdwn
+++ b/doc/plugins/po/discussion.mdwn
@@ -150,6 +150,23 @@ The following analysis was done with his help.
variables; according to [[Joey]], this is "Freaky code, but seems ok
due to use of `quotementa`".
+##### Locale::Po4a::Xhtml
+
+* does not run any external program
+* does not build regexp's from untrusted variables
+
+=> Seems safe as far as the `includessi` option is disabled; the po
+plugin explicitly disables it.
+
+Relies on Locale::Po4a::Xml` to do most of the work.
+
+##### Locale::Po4a::Xml
+
+* does not run any external program
+* the `includeexternal` option makes it able to read external files;
+ the po plugin explicitly disables it
+* untrusted variables are escaped when used to build regexp's
+
##### Text::WrapI18N
`Text::WrapI18N` can cause DoS
diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn
index a921b9a02..15ed08d82 100644
--- a/doc/plugins/write.mdwn
+++ b/doc/plugins/write.mdwn
@@ -200,7 +200,9 @@ value is ignored.
Runs on the raw source of a page, before anything else touches it, and can
make arbitrary changes. The function is passed named parameters "page",
-"destpage", and "content". It should return the filtered content.
+"destpage", "content" and "fullpage". "fullpage" is a true value if,
+and only if, a full page's content is being filtered, e.g. as opposed
+to a directive parameter. It should return the filtered content.
### preprocess