X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/1914ae2fd24e1e8021404eae847d70c710f8542d..d98296d1db02febfa7cc4fbe7f304ca2a9858fef:/IkiWiki/Plugin/po.pm

diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm
index b9f59f3e8..0af47aad5 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; # languages codes ordered as in config po_slave_languages
 
 memoize("istranslatable");
 memoize("_istranslation");
@@ -51,14 +52,22 @@ sub import {
 	hook(type => "formbuilder_setup", id => "po", call => \&formbuilder_setup, last => 1);
 	hook(type => "formbuilder", id => "po", call => \&formbuilder);
 
-	$origsubs{'beautify_urlpath'}=\&IkiWiki::beautify_urlpath;
-	inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath);
-	$origsubs{'targetpage'}=\&IkiWiki::targetpage;
-	inject(name => "IkiWiki::targetpage", call => \&mytargetpage);
-	$origsubs{'urlto'}=\&IkiWiki::urlto;
-	inject(name => "IkiWiki::urlto", call => \&myurlto);
-	$origsubs{'cgiurl'}=\&IkiWiki::cgiurl;
-	inject(name => "IkiWiki::cgiurl", call => \&mycgiurl);
+	if (! %origsubs) {
+		$origsubs{'bestlink'}=\&IkiWiki::bestlink;
+		inject(name => "IkiWiki::bestlink", call => \&mybestlink);
+		$origsubs{'beautify_urlpath'}=\&IkiWiki::beautify_urlpath;
+		inject(name => "IkiWiki::beautify_urlpath", call => \&mybeautify_urlpath);
+		$origsubs{'targetpage'}=\&IkiWiki::targetpage;
+		inject(name => "IkiWiki::targetpage", call => \&mytargetpage);
+		$origsubs{'urlto'}=\&IkiWiki::urlto;
+		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);
+		$origsubs{'isselflink'}=\&IkiWiki::isselflink;
+		inject(name => "IkiWiki::isselflink", call => \&myisselflink);
+	}
 }
 
 
@@ -81,7 +90,8 @@ sub getsetup () {
 	return
 		plugin => {
 			safe => 0,
-			rebuild => 1,
+			rebuild => 1, # format plugin
+			section => "format",
 		},
 		po_master_language => {
 			type => "string",
@@ -95,11 +105,11 @@ sub getsetup () {
 		},
 		po_slave_languages => {
 			type => "string",
-			example => {
-				'fr' => 'Français',
-				'es' => 'Español',
-				'de' => 'Deutsch'
-			},
+			example => [
+				'fr|Français',
+				'es|Español',
+				'de|Deutsch'
+                            ],
 			description => "slave languages (PO files)",
 			safe => 1,
 			rebuild => 1,
@@ -129,10 +139,32 @@ sub checkconfig () {
 		}
 	}
 
+	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));
+                        }
+			$slaves{$code} = $name;
+			push @slavelanguages, $code;
+
+                }
+		$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 {
 		islanguagecode($_)
 			or error(sprintf(gettext("%s is not a valid language code"), $_));
-	} ($config{po_master_language}{code}, keys %{$config{po_slave_languages}});
+	} ($config{po_master_language}{code}, @slavelanguages);
 
 	if (! exists $config{po_translatable_pages} ||
 	    ! defined $config{po_translatable_pages}) {
@@ -151,10 +183,6 @@ 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';
 	}
-	unless ($config{po_link_to} eq 'default') {
-		$origsubs{'bestlink'}=\&IkiWiki::bestlink;
-		inject(name => "IkiWiki::bestlink", call => \&mybestlink);
-	}
 
 	push @{$config{wiki_file_prune_regexps}}, qr/\.pot$/;
 
@@ -165,7 +193,7 @@ sub checkconfig () {
 		next if $underlay=~/^locale\//;
 
 		# Underlays containing the po files for slave languages.
-		foreach my $ll (keys %{$config{po_slave_languages}}) {
+		foreach my $ll (@slavelanguages) {
 			add_underlay("po/$ll/$underlay")
 				if -d "$config{underlaydirbase}/po/$ll/$underlay";
 		}
@@ -173,7 +201,8 @@ sub checkconfig () {
 		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";
 		}
 	}
 }
@@ -190,7 +219,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)};
 	}
 }
 
@@ -222,7 +251,7 @@ sub scan (@) {
 				# make sure any destpage's translations has
 				# $page in its backlinks
 				push @{$links{$page}},
-					values %{otherlanguages($destpage)};
+					values %{otherlanguages_pages($destpage)};
 			}
 		}
 	}
@@ -280,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 &&
@@ -307,7 +336,7 @@ sub pagetemplate (@) {
 	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 (@) {
@@ -333,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,
 		};
@@ -386,31 +415,32 @@ sub change (@) {
 		resetalreadyfiltered();
 		require IkiWiki::Render;
 		foreach my $file (@rendered) {
-			debug(sprintf(gettext("building %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.
-	# (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;
+
+		# Avoid touching underlay files.
+		next if $masterfile ne "$config{srcdir}/$file";
+
 		# 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.
-		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)) {
-			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;
 		}
@@ -423,8 +453,7 @@ sub change (@) {
 
 	if ($updated_po_files) {
 		commit_and_refresh(
-			gettext("updated PO files"),
-			"IkiWiki::Plugin::po::change");
+			gettext("updated PO files"));
 	}
 }
 
@@ -531,10 +560,23 @@ sub formbuilder (@) {
 	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 { $_->[0] 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) ;
 			}
 		}
 	}
@@ -545,15 +587,20 @@ sub formbuilder (@) {
 # `----
 
 # Implement po_link_to 'current' and 'negotiated' settings.
-# Not injected otherwise.
 sub mybestlink ($$) {
 	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 @caller = caller(1);
 	if (length $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;
@@ -563,12 +610,12 @@ sub mybeautify_urlpath ($) {
 	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{htmlext}\E$!/!;
-		} (keys %{$config{po_slave_languages}});
+		} @slavelanguages;
 	}
 	return $res;
 }
@@ -636,6 +683,33 @@ sub mycgiurl (@) {
 	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;
+}
+
+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
 # `----
@@ -691,6 +765,7 @@ sub istranslatablefile ($) {
 	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;
 }
@@ -759,7 +834,7 @@ sub islanguagecode ($) {
 	return $code =~ /^[a-z]{2}$/;
 }
 
-sub otherlanguage ($$) {
+sub otherlanguage_page ($$) {
 	my $page=shift;
 	my $code=shift;
 
@@ -767,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;
 }
 
@@ -801,25 +890,25 @@ sub pofile ($$) {
 sub pofiles ($) {
 	my $masterfile=shift;
 
-	return map pofile($masterfile, $_), (keys %{$config{po_slave_languages}});
+	return map pofile($masterfile, $_), @slavelanguages;
 }
 
 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));
@@ -900,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();
@@ -930,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 (;$) {
@@ -966,7 +1048,7 @@ sub ishomepage ($) {
 	my $page = shift;
 
 	return 1 if $page eq 'index';
-	map { return 1 if $page eq 'index.'.$_ } keys %{$config{po_slave_languages}};
+	map { return 1 if $page eq 'index.'.$_ } @slavelanguages;
 	return undef;
 }
 
@@ -981,7 +1063,7 @@ sub deletetranslations ($) {
 		if (-e $absfile && ! -l $absfile && ! -d $absfile) {
 			push @todelete, $file;
 		}
-	} keys %{$config{po_slave_languages}};
+	} @slavelanguages;
 
 	map {
 		if ($config{rcs}) {
@@ -994,17 +1076,18 @@ sub deletetranslations ($) {
 
 	if (@todelete) {
 		commit_and_refresh(
-			gettext("removed obsolete PO files"),
-			"IkiWiki::Plugin::po::deletetranslations");
+			gettext("removed obsolete PO files"));
 	}
 }
 
-sub commit_and_refresh ($$) {
-	my ($msg, $author) = (shift, shift);
+sub commit_and_refresh ($) {
+	my $msg = shift;
 
 	if ($config{rcs}) {
 		IkiWiki::disable_commit_hook();
-		IkiWiki::rcs_commit_staged($msg, $author, "127.0.0.1");
+		IkiWiki::rcs_commit_staged(
+			message => $msg,
+		);
 		IkiWiki::enable_commit_hook();
 		IkiWiki::rcs_update();
 	}
@@ -1022,11 +1105,8 @@ sub commit_and_refresh ($$) {
 	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 $nonfatal = shift;
 
 	$content = '' unless defined $content;
 	$content = decode_utf8(encode_utf8($content));
@@ -1049,10 +1129,6 @@ sub po_to_markup ($$;$) {
 
 	my $fail = sub ($) {
 		my $msg = "po(po_to_markup) - $page : " . shift;
-		if ($nonfatal) {
-			warn $msg;
-			return undef;
-		}
 		error($msg, sub { unlink $infile, $outfile});
 	};
 
@@ -1060,21 +1136,18 @@ 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));
 
-	$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()
@@ -1127,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
 # `----
@@ -1187,4 +1291,32 @@ sub match_currentlang ($$;@) {
 	}
 }
 
+sub match_needstranslation ($$;@) {
+	my $page=shift;
+	my $wanted=shift;
+
+	if (defined $wanted && $wanted ne "") {
+		if ($wanted !~ /^\d+$/) {
+			return IkiWiki::FailReason->new("parameter is not an integer");
+		}
+		elsif ($wanted > 100) {
+			return IkiWiki::FailReason->new("parameter is greater than 100");
+                }
+        }
+        else {
+		$wanted=100;
+        }
+
+	my $percenttranslated=IkiWiki::Plugin::po::percenttranslated($page);
+	if ($percenttranslated eq 'N/A') {
+		return IkiWiki::FailReason->new("file is not a translatable page");
+	}
+	elsif ($percenttranslated < $wanted) {
+		return IkiWiki::SuccessReason->new("file has $percenttranslated translated");
+        }
+	else {
+		return IkiWiki::FailReason->new("file is translated enough");
+	}
+}
+
 1