X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/d9f0b56a412799feafe041b088db327a4d373c6e..0cc2a36f593fd14b6345ad2c0b446edb2bafbe2e:/IkiWiki/Plugin/po.pm

diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm
index 6b708e850..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") {
@@ -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$!/!;
@@ -788,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);
@@ -820,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 ($) {
@@ -833,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;
 }
 
@@ -847,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;
 }
@@ -1001,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;
 }
 
@@ -1015,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),
@@ -1226,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
 # `----