po plugin: reworked available options
[ikiwiki.git] / IkiWiki / Plugin / po.pm
1 #!/usr/bin/perl
2 # .po as a wiki page type
3 # inspired by the GPL'd po4a-translate,
4 # which is Copyright 2002, 2003, 2004 by Martin Quinson (mquinson#debian.org)
5 package IkiWiki::Plugin::po;
6
7 use warnings;
8 use strict;
9 use IkiWiki 2.00;
10 use Encode;
11 use Locale::Po4a::Chooser;
12 use File::Temp;
13
14 sub import {
15         hook(type => "getsetup", id => "po", call => \&getsetup);
16         hook(type => "targetpage", id => "po", call => \&targetpage);
17         hook(type => "filter", id => "po", call => \&filter);
18         hook(type => "htmlize", id => "po", call => \&htmlize);
19 }
20
21 sub getsetup () { #{{{
22         return
23                 plugin => {
24                         safe => 0,
25                         rebuild => 1, # format plugin
26                 },
27                 po_master_language => {
28                         type => "string",
29                         example => {
30                                 'code' => 'en',
31                                 'name' => 'English'
32                         },
33                         description => "master language (non-PO files)",
34                         safe => 1,
35                         rebuild => 1,
36                 },
37                 po_slave_languages => {
38                         type => "string",
39                         example => {'fr' => { 'name' => 'Fran├žais' },
40                                     'es' => { 'name' => 'Castellano' },
41                                     'de' => { 'name' => 'Deutsch' },
42                         },
43                         description => "slave languages (PO files)",
44                         safe => 1,
45                         rebuild => 1,
46                 },
47 } #}}}
48
49 sub targetpage (@) { #{{{
50         my %params = @_;
51         my $page=$params{page};
52         my $ext=$params{ext};
53
54         if (! IkiWiki::PageSpec::match_istranslation($page, $page)) {
55                 return;
56         }
57
58         my ($masterpage, $lang) = ($page =~ /(.*)[.]([a-z]{2})$/);
59         if (! $config{usedirs} || $page eq 'index') {
60                 return $masterpage.".".$ext.".".$lang;
61         }
62         else {
63                 return $masterpage."/index.".$ext.".".$lang;
64         }
65 } #}}}
66
67 # We use filter to convert PO to the master page's type,
68 # since other plugins should not work on PO files
69 sub filter (@) { #{{{
70         my %params = @_;
71         my $page = $params{page};
72         my $content = decode_utf8(encode_utf8($params{content}));
73
74         # decide if this is a PO file that should be converted into a translated document,
75         # and perform various sanity checks
76         if (! IkiWiki::PageSpec::match_istranslation($page, $page)) {
77                 return $content;
78         }
79
80         my ($masterpage, $lang) = ($page =~ /(.*)[.]([a-z]{2})$/);
81         my $file=srcfile(exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page});
82         my $masterfile = srcfile($pagesources{$masterpage});
83         my (@pos,@masters);
84         push @pos,$file;
85         push @masters,$masterfile;
86         my %options = (
87                         "markdown" => (pagetype($masterfile) eq 'mdwn') ? 1 : 0,
88                         );
89         my $doc=Locale::Po4a::Chooser::new('text',%options);
90         $doc->process(
91                 'po_in_name'    => \@pos,
92                 'file_in_name'  => \@masters,
93                 'file_in_charset'  => 'utf-8',
94                 'file_out_charset' => 'utf-8',
95         ) or error("[po/filter:$file]: failed to translate");
96         my ($percent,$hit,$queries) = $doc->stats();
97         my $tmpfh = File::Temp->new(TEMPLATE => "/tmp/ikiwiki-po-filter-out.XXXXXXXXXX");
98         my $tmpout = $tmpfh->filename;
99         $doc->write($tmpout) or error("[po/filter:$file] could not write $tmpout");
100         $content = readfile($tmpout) or error("[po/filter:$file] could not read $tmpout");
101         return $content;
102 } #}}}
103
104 sub htmlize (@) { #{{{
105         my %params=@_;
106         my $page = $params{page};
107         my $content = $params{content};
108         my ($masterpage, $lang) = ($page =~ /(.*)[.]([a-z]{2})$/);
109         my $masterfile = srcfile($pagesources{$masterpage});
110
111         # force content to be htmlize'd as if it was the same type as the master page
112         return IkiWiki::htmlize($page, $page, pagetype($masterfile), $content);
113 } #}}}
114
115 package IkiWiki::PageSpec;
116
117 sub match_istranslation ($;@) { #{{{
118         my $page=shift;
119         my $wanted=shift;
120
121         my %params=@_;
122         my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
123         if (! defined $file) {
124                 return IkiWiki::FailReason->new("no file specified");
125         }
126
127         if (! IkiWiki::pagetype($page) eq 'po') {
128                 return IkiWiki::FailReason->new("is not a PO file");
129         }
130
131         my ($masterpage, $lang) = ($page =~ /(.*)[.]([a-z]{2})$/);
132         if (! defined $masterpage || ! defined $lang
133             || ! (length($masterpage) > 0) || ! (length($lang) > 0)) {
134                 return IkiWiki::FailReason->new("is not named like a translation file");
135         }
136
137         if (! defined $IkiWiki::pagesources{$masterpage}) {
138                 return IkiWiki::FailReason->new("the master page does not exist");
139         }
140
141         if (! defined $IkiWiki::config{po_slave_languages}{$lang}) {
142                 return IkiWiki::FailReason->new("language $lang is not supported");
143         }
144
145         return IkiWiki::SuccessReason->new("page $page is a translation");
146
147 } #}}}
148
149 1