X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/6c0f9c691c3df3a2ec30dec626c997623568a400..eda2357c3e1990df049264735e8751af8962ded5:/IkiWiki/Plugin/po.pm?ds=inline

diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm
index 2b2839f24..903a9500f 100644
--- a/IkiWiki/Plugin/po.pm
+++ b/IkiWiki/Plugin/po.pm
@@ -51,16 +51,20 @@ sub import {
 	hook(type => "formbuilder_setup", id => "po", call => \&formbuilder_setup, last => 1);
 	hook(type => "formbuilder", id => "po", call => \&formbuilder);
 
-	$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);
+	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);
+	}
 }
 
 
@@ -83,7 +87,8 @@ sub getsetup () {
 	return
 		plugin => {
 			safe => 0,
-			rebuild => 1,
+			rebuild => 1, # format plugin
+			section => "format",
 		},
 		po_master_language => {
 			type => "string",
@@ -130,6 +135,7 @@ sub checkconfig () {
 				      $field, 'po'));
 		}
 	}
+	delete $config{po_slave_languages}{$config{po_master_language}{code}};;
 
 	map {
 		islanguagecode($_)
@@ -171,7 +177,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";
 		}
 	}
 }
@@ -305,7 +312,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 (@) {
@@ -384,31 +391,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;
 		}
@@ -421,8 +429,7 @@ sub change (@) {
 
 	if ($updated_po_files) {
 		commit_and_refresh(
-			gettext("updated PO files"),
-			"IkiWiki::Plugin::po::change");
+			gettext("updated PO files"));
 	}
 }
 
@@ -529,10 +536,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 { $_ 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) ;
 			}
 		}
 	}
@@ -548,13 +568,15 @@ sub mybestlink ($$) {
 	my $link=shift;
 
 	return $origsubs{'bestlink'}->($page, $link)
-		if $config{po_link_to} eq "default";
+		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
-	    && ($config{po_link_to} eq "current" || $config{po_link_to} eq "negotiated")
 	    && 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;
@@ -564,7 +586,7 @@ 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 {
@@ -637,6 +659,22 @@ 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;
+}
+
 # ,----
 # | Blackboxes for private data
 # `----
@@ -692,6 +730,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;
 }
@@ -809,18 +848,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));
@@ -901,15 +940,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();
@@ -995,17 +1032,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();
 	}
@@ -1023,11 +1061,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));
@@ -1050,10 +1085,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});
 	};
 
@@ -1061,21 +1092,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()
@@ -1128,6 +1156,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
 # `----
@@ -1188,4 +1247,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