X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/fbfda5ccfce40d3f0b5a6076ef02f07e9e5b8fd6..68ddcc0b9a8e4629bcdd6dba81225085afbdf9fe:/IkiWiki/Plugin/po.pm diff --git a/IkiWiki/Plugin/po.pm b/IkiWiki/Plugin/po.pm index a233fb5af..13b98b739 100644 --- a/IkiWiki/Plugin/po.pm +++ b/IkiWiki/Plugin/po.pm @@ -23,13 +23,14 @@ use File::Copy; use File::Spec; 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 +my $language_code_pattern = '[a-zA-Z]+(?:_[a-zA-Z]+)?'; memoize("istranslatable"); memoize("_istranslation"); @@ -37,7 +38,8 @@ memoize("percenttranslated"); sub import { hook(type => "getsetup", id => "po", call => \&getsetup); - hook(type => "checkconfig", id => "po", call => \&checkconfig); + hook(type => "checkconfig", id => "po", call => \&checkconfig, + last => 1); hook(type => "needsbuild", id => "po", call => \&needsbuild); hook(type => "scan", id => "po", call => \&scan, last => 1); hook(type => "filter", id => "po", call => \&filter); @@ -45,11 +47,10 @@ sub import { hook(type => "pagetemplate", id => "po", call => \&pagetemplate, last => 1); hook(type => "rename", id => "po", call => \&renamepages, first => 1); hook(type => "delete", id => "po", call => \&mydelete); - hook(type => "change", id => "po", call => \&change); + hook(type => "rendered", id => "po", call => \&rendered); hook(type => "checkcontent", id => "po", call => \&checkcontent); hook(type => "canremove", id => "po", call => \&canremove); hook(type => "canrename", id => "po", call => \&canrename); - hook(type => "editcontent", id => "po", call => \&editcontent); hook(type => "formbuilder_setup", id => "po", call => \&formbuilder_setup, last => 1); hook(type => "formbuilder", id => "po", call => \&formbuilder); @@ -64,8 +65,11 @@ sub import { 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); + if (IkiWiki->can('rootpage')) { + $origsubs{'rootpage'}=\&IkiWiki::rootpage; + inject(name => "IkiWiki::rootpage", call => \&myrootpage) + if defined $origsubs{'rootpage'}; + } $origsubs{'isselflink'}=\&IkiWiki::isselflink; inject(name => "IkiWiki::isselflink", call => \&myisselflink); } @@ -138,6 +142,7 @@ sub checkconfig () { 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) { @@ -148,23 +153,25 @@ sub checkconfig () { } if (ref $config{po_slave_languages} eq 'ARRAY') { - my %slaves; foreach my $pair (@{$config{po_slave_languages}}) { my ($code, $name)=splitlangpair($pair); - if (defined $code) { + if (defined $code && ! exists $slavelanguages{$code}) { push @slavelanguages, $code; - $slaves{$code} = $name; + $slavelanguages{$code} = $name; } } - $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}{$master_language_code}; + delete $slavelanguages{$master_language_code}; map { islanguagecode($_) @@ -295,9 +302,8 @@ sub filter (@) { my $page = $params{page}; my $destpage = $params{destpage}; my $content = $params{content}; - if (istranslation($page) && ! alreadyfiltered($page, $destpage)) { + if (istranslation($page)) { $content = po_to_markup($page, $content); - setalreadyfiltered($page, $destpage); } return $content; } @@ -334,6 +340,19 @@ sub pagetemplate (@) { if ($template->query(name => "istranslatable")) { $template->param(istranslatable => istranslatable($page)); } + my $lang_code = istranslation($page) ? lang($page) : $master_language_code; + if ($template->query(name => "lang_code")) { + $template->param(lang_code => $lang_code); + } + if ($template->query(name => "html_lang_code")) { + $template->param(html_lang_code => htmllangcode($lang_code)); + } + if ($template->query(name => "html_lang_dir")) { + $template->param(html_lang_dir => htmllangdir($lang_code)); + } + if ($template->query(name => "lang_name")) { + $template->param(lang_name => languagename($lang_code)); + } if ($template->query(name => "HOMEPAGEURL")) { $template->param(homepageurl => homepageurl($page)); } @@ -363,7 +382,8 @@ sub pagetemplate (@) { && $masterpage eq "index") { $template->param('parentlinks' => []); } - if (ishomepage($page) && $template->query(name => "title")) { + if (ishomepage($page) && $template->query(name => "title") + && !$template->param("title_overridden")) { $template->param(title => $config{wikiname}); } } @@ -411,7 +431,7 @@ sub mydelete (@) { map { deletetranslations($_) } grep istranslatablefile($_), @deleted; } -sub change (@) { +sub rendered (@) { my @rendered=@_; my $updated_po_files=0; @@ -498,15 +518,6 @@ sub canrename (@) { return undef; } -# As we're previewing or saving a page, the content may have -# changed, so tell the next filter() invocation it must not be lazy. -sub editcontent () { - my %params=@_; - - unsetalreadyfiltered($params{page}, $params{page}); - return $params{content}; -} - sub formbuilder_setup (@) { my %params=@_; my $form=$params{form}; @@ -526,7 +537,7 @@ sub formbuilder_setup (@) { # their buttons, which is why this hook must be run last. # The canrename/canremove hooks already ensure this is forbidden # at the backend level, so this is only UI sugar. - if (istranslation($form->field("page"))) { + if (istranslation(scalar $form->field("page"))) { map { for (my $i = 0; $i < @{$params{buttons}}; $i++) { if (@{$params{buttons}}[$i] eq $_) { @@ -615,23 +626,27 @@ sub mybeautify_urlpath ($) { return $res; } -sub mytargetpage ($$) { +sub mytargetpage ($$;$) { my $page=shift; my $ext=shift; + my $filename=shift; if (istranslation($page) || istranslatable($page)) { my ($masterpage, $lang) = (masterpage($page), lang($page)); - if (! $config{usedirs} || $masterpage eq 'index') { + if (defined $filename) { + return $masterpage . "/" . $filename . "." . $lang . "." . $ext; + } + elsif (! $config{usedirs} || $masterpage eq 'index') { return $masterpage . "." . $lang . "." . $ext; } else { return $masterpage . "/index." . $lang . "." . $ext; } } - return $origsubs{'targetpage'}->($page, $ext); + return $origsubs{'targetpage'}->($page, $ext, $filename); } -sub myurlto ($$;$) { +sub myurlto ($;$$) { my $to=shift; my $from=shift; my $absolute=shift; @@ -640,7 +655,12 @@ sub myurlto ($$;$) { if (! length $to && $config{po_link_to} eq "current" && istranslatable('index')) { - return IkiWiki::beautify_urlpath(IkiWiki::baseurl($from) . "index." . lang($from) . ".$config{htmlext}"); + if (defined $from) { + return IkiWiki::beautify_urlpath(IkiWiki::baseurl($from) . "index." . lang($from) . ".$config{htmlext}"); + } + else { + return $origsubs{'urlto'}->($to,$from,$absolute); + } } # avoid using our injected beautify_urlpath if run by cgi_editpage, # so that one is redirected to the just-edited page rather than to the @@ -705,42 +725,6 @@ sub myisselflink ($$) { return; } -# ,---- -# | Blackboxes for private data -# `---- - -{ - my %filtered; - - sub alreadyfiltered($$) { - my $page=shift; - my $destpage=shift; - - return exists $filtered{$page}{$destpage} - && $filtered{$page}{$destpage} eq 1; - } - - sub setalreadyfiltered($$) { - my $page=shift; - my $destpage=shift; - - $filtered{$page}{$destpage}=1; - } - - sub unsetalreadyfiltered($$) { - my $page=shift; - my $destpage=shift; - - if (exists $filtered{$page}{$destpage}) { - delete $filtered{$page}{$destpage}; - } - } - - sub resetalreadyfiltered() { - undef %filtered; - } -} - # ,---- # | Helper functions # `---- @@ -793,11 +777,11 @@ sub _istranslation ($) { && pagetype($file) eq 'po'; return 0 if $file =~ /\.pot$/; - my ($masterpage, $lang) = ($page =~ /(.*)[.]([a-z]{2})$/); + my ($masterpage, $lang) = ($page =~ /(.*)[.]($language_code_pattern)$/); 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); @@ -832,10 +816,23 @@ sub lang ($) { return $master_language_code; } +sub htmllangcode ($) { + (my $lang = shift) =~ tr/_/-/; + return $lang; +} + +sub htmllangdir ($) { + my $lang = shift; + if ($lang =~ /^(ar|fa|he)/) { + return 'rtl'; + } + return 'ltr'; +} + sub islanguagecode ($) { my $code=shift; - return $code =~ /^[a-z]{2}$/; + return $code =~ /^$language_code_pattern$/; } sub otherlanguage_page ($$) { @@ -949,10 +946,9 @@ sub refreshpofiles ($@) { } if (-e $pofile) { - system("msgmerge", "--previous", "-q", "-U", "--backup=none", $pofile, $potfile) == 0 - or error("po(refreshpofiles) ". - sprintf(gettext("failed to update %s"), - $pofile)); + if (! (system("msgmerge", "--previous", "-q", "-U", "--backup=none", $pofile, $potfile) == 0)) { + print STDERR ("po(refreshpofiles) ". sprintf(gettext("failed to update %s"), $pofile)); + } } else { File::Copy::syscopy($potfile,$pofile) @@ -1015,8 +1011,8 @@ sub languagename ($) { return $master_language_name if $code eq $master_language_code; - return $config{po_slave_languages}{$code} - if defined $config{po_slave_languages}{$code}; + return $slavelanguages{$code} + if defined $slavelanguages{$code}; return; } @@ -1028,6 +1024,8 @@ sub otherlanguagesloop ($) { push @ret, { url => urlto_with_orig_beautiful_urlpath(masterpage($page), $page), code => $master_language_code, + html_code => htmllangcode($master_language_code), + html_dir => htmllangdir($master_language_code), language => $master_language_name, master => 1, }; @@ -1038,6 +1036,8 @@ sub otherlanguagesloop ($) { push @ret, { url => urlto_with_orig_beautiful_urlpath($otherpage, $page), code => $lang, + html_code => htmllangcode($lang), + html_dir => htmllangdir($lang), language => languagename($lang), percent => percenttranslated($otherpage), } @@ -1077,7 +1077,7 @@ sub deletetranslations ($) { IkiWiki::rcs_remove($_); } else { - IkiWiki::prune("$config{srcdir}/$_"); + IkiWiki::prune("$config{srcdir}/$_", $config{srcdir}); } } @todelete; @@ -1099,7 +1099,6 @@ sub commit_and_refresh ($) { IkiWiki::rcs_update(); } # Reinitialize module's private variables. - resetalreadyfiltered(); resettranslationscache(); flushmemoizecache(); # Trigger a wiki refresh. @@ -1227,6 +1226,7 @@ sub po4a_options($) { # how to disable options is not consistent across po4a modules $options{includessi} = ''; $options{includeexternal} = 0; + $options{ontagerror} = 'warn'; } elsif ($pagetype eq 'mdwn') { $options{markdown} = 1; @@ -1241,17 +1241,24 @@ sub po4a_options($) { sub splitlangpair ($) { my $pair=shift; - my ($code, $name) = ( $pair =~ /^([a-z]{2})\|(.+)$/ ); + my ($code, $name) = ( $pair =~ /^($language_code_pattern)\|(.+)$/ ); if (! defined $code || ! defined $name || ! length $code || ! length $name) { # not a fatal error to avoid breaking if used with web setup - print STDERR sprintf(gettext("%s has invalid syntax: must use CODE|NAME"), - $pair)."\n"; + 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 # `---- @@ -1286,7 +1293,7 @@ sub match_lang ($$;@) { my $regexp=IkiWiki::glob2re($wanted); my $lang=IkiWiki::Plugin::po::lang($page); - if ($lang !~ /^$regexp$/i) { + if ($lang !~ $regexp) { return IkiWiki::FailReason->new("file language is $lang, not $wanted"); } else {