X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/d4136aea8aa8968d2cd87b40e8d85301a3549323..68770930a72adc39f535210bceff171efcf205ac:/IkiWiki/Plugin/po.pm diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm index 6bf09b6d6..6395ebdc2 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; # language codes ordered as in config po_slave_languages memoize("istranslatable"); memoize("_istranslation"); @@ -104,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, @@ -137,12 +138,33 @@ sub checkconfig () { $field, 'po')); } } + + 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}) { @@ -171,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"; } @@ -197,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)}; } } @@ -229,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)}; } } } @@ -243,13 +265,6 @@ sub filter (@) { my $page = $params{page}; my $destpage = $params{destpage}; my $content = $params{content}; - - my @caller = caller(4); - unless ($caller[3] eq "IkiWiki::render" || - $caller[3] eq 'IkiWiki::Plugin::sidebar::sidebar_content') { - return $content; - } - if (istranslation($page) && ! alreadyfiltered($page, $destpage)) { $content = po_to_markup($page, $content); setalreadyfiltered($page, $destpage); @@ -294,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 && @@ -347,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, }; @@ -543,7 +558,7 @@ sub formbuilder (@) { # This cannot be done in the formbuilder_setup hook as the list of types is # computed later. if ($form->field("do") eq "create") { - foreach my $field ($form->field) { + foreach my $field ($form->field) { next unless "$field" eq "type"; next unless $field->type eq 'select'; my $orig_value = $field->value; @@ -600,7 +615,7 @@ sub mybeautify_urlpath ($) { $res =~ s!/\Qindex.$config{htmlext}\E$!/!; map { $res =~ s!/\Qindex.$_.$config{htmlext}\E$!/!; - } (keys %{$config{po_slave_languages}}); + } @slavelanguages; } return $res; } @@ -691,7 +706,7 @@ sub myisselflink ($$) { return 1 if $origsubs{'isselflink'}->($page, $link); if (istranslation($page)) { return $origsubs{'isselflink'}->(masterpage($page), $link); - } + } return; } @@ -819,7 +834,7 @@ sub islanguagecode ($) { return $code =~ /^[a-z]{2}$/; } -sub otherlanguage ($$) { +sub otherlanguage_page ($$) { my $page=shift; my $code=shift; @@ -827,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; } @@ -861,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)); @@ -960,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(); @@ -990,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 (;$) { @@ -1026,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; } @@ -1041,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}) { @@ -1114,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)); @@ -1174,12 +1194,43 @@ sub isvalidpo ($) { unlink $infile; if ($res) { - return IkiWiki::SuccessReason->new("valid gettext data"); + return IkiWiki::SuccessReason->new("valid gettext data"); } return IkiWiki::FailReason->new(gettext("invalid gettext data, go back ". "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 # `---- @@ -1240,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