xref: /plugin/autotranslation/helper.php (revision 49a71a894777f09fa70b9a8f4647f9077f8a6798)
1<?php
2/**
3 * Translation Plugin: Simple multilanguage plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <andi@splitbrain.org>
7 */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12class helper_plugin_translation extends DokuWiki_Plugin {
13    var $trans       = array();
14    var $tns         = '';
15    var $defaultlang = '';
16    var $LN          = array(); // hold native names
17
18    /**
19     * Initialize
20     */
21    function helper_plugin_translation(){
22        global $conf;
23        require_once(DOKU_INC.'inc/pageutils.php');
24        require_once(DOKU_INC.'inc/utf8.php');
25
26        // load wanted translation into array
27        $this->trans = strtolower(str_replace(',',' ',$this->getConf('translations')));
28        $this->trans = array_unique(array_filter(explode(' ',$this->trans)));
29        sort($this->trans);
30
31        // load language names
32        $this->LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
33
34        // get default translation
35        if(!$conf['lang_before_translation']){
36            $dfl = $conf['lang'];
37        } else {
38            $dfl = $conf['lang_before_translation'];
39        }
40        if(in_array($dfl,$this->trans)){
41            $this->defaultlang = $dfl;
42        }else{
43            $this->defaultlang = '';
44            array_unshift($this->trans,'');
45        }
46
47
48        $this->tns = cleanID($this->getConf('translationns'));
49        if($this->tns) $this->tns .= ':';
50    }
51
52    /**
53     * Check if the given ID is a translation and return the language code.
54     */
55    function getLangPart($id){
56        $rx = '/^'.$this->tns.'('.join('|',$this->trans).'):/';
57        if(preg_match($rx,$id,$match)){
58            return $match[1];
59        }
60        return '';
61    }
62
63    /**
64     * Returns the browser language if it matches with one of the configured
65     * languages
66     */
67    function getBrowserLang(){
68        $rx = '/(^|,|:|;|-)('.join('|',$this->trans).')($|,|:|;|-)/i';
69        if(preg_match($rx,$_SERVER['HTTP_ACCEPT_LANGUAGE'],$match)){
70            return strtolower($match[2]);
71        }
72        return false;
73    }
74
75
76    /**
77     * Returns the ID and name to the wanted translation, empty
78     * $lng is default lang
79     */
80    function buildTransID($lng,$idpart){
81        global $conf;
82        global $saved_conf;
83        if($lng){
84            $link = ':'.$this->tns.$lng.':'.$idpart;
85            $name = $lng;
86        }else{
87            $link = ':'.$this->tns.$idpart;
88            if(!$conf['lang_before_translation']){
89              $name = $conf['lang'];
90            } else {
91              $name = $conf['lang_before_translation'];
92            }
93        }
94        return array($link,$name);
95    }
96
97    /**
98     * Check if current ID should be translated and any GUI
99     * should be shown
100     */
101    function istranslatable($id,$checkact=true){
102        global $ACT;
103
104        if($checkact && $ACT != 'show') return false;
105        if($this->tns && strpos($id,$this->tns) !== 0) return false;
106        $skiptrans = trim($this->getConf('skiptrans'));
107        if($skiptrans &&  preg_match('/'.$skiptrans.'/ui',':'.$id)) return false;
108        $meta = p_get_metadata($id);
109        if($meta['plugin']['translation']['notrans']) return false;
110
111        return true;
112    }
113
114    /**
115     * Return the (localized) about link
116     *
117     * @fixme why is this doing the detection stuff again?
118     */
119    function showAbout() {
120        global $ID;
121        global $conf;
122        global $INFO;
123
124        $this->checkage();
125
126        $LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
127
128        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
129        $idpart = preg_replace($rx,'',$ID);
130
131        $out = '';
132        $out .= '<sup>';
133        if($this->getConf('localabout')){
134            $lc = '';
135
136            //try main lang namespace
137            foreach($this->trans as $t){
138                list($link,$name) = $this->buildTransID($t,$idpart);
139                $link = cleanID($link);
140                if($ID == $link){
141                    $lc = hsc($name);
142                }
143                if ($lc) break;
144            }
145
146            //try browser language
147            if(!$lc) $lc = $this->getBrowserLang();
148
149            //try wiki language
150            if(!$lc) $lc = $conf['lang'];
151
152            if(!$lc) { //can't find language
153                $localabout = $this->getConf('about'); //http://localhost/dokuwiki/doku.php?id=translation:about
154            } else { //i found language!
155                        $localabout = $lc.':'.$this->getConf('about'); //http://localhost/dokuwiki/doku.php?id=en:translation:about
156            }
157
158            //make link
159            $out .= html_wikilink($localabout,'?');
160            } else {
161            $out .= html_wikilink($this->getConf('about'),'?');
162        }
163        $out .= '</sup>';
164
165        return $out;
166    }
167
168    /**
169     * Displays the available and configured translations. Needs to be placed in the template.
170     */
171    function showTranslations(){
172        global $ID;
173        global $conf;
174        global $INFO;
175
176        if(!$this->istranslatable($ID)) return;
177
178        $this->checkage();
179
180        $LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
181
182        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
183        $idpart = preg_replace($rx,'',$ID);
184
185        $out  = '<div class="plugin_translation">';
186
187        //show text
188        if ($this->getConf('description')){
189            $out .= '<span>'.$this->getLang('translations');
190            if ($this->getConf('showabout')) $out .= $this->showAbout();
191            $out .= ':</span> ';
192        }
193
194        if($this->getConf('dropdown')){ // use dropdown fixme move to own functions
195            if($INFO['exists']){
196                $class = 'wikilink1';
197            }else{
198                $class = 'wikilink2';
199            }
200
201            $out2 = ""; //FIXME ugly name
202            foreach($this->trans as $t){
203                list($link,$name) = $this->buildTransID($t,$idpart);
204                $link = cleanID($link);
205                if($ID == $link){
206                    $sel = ' selected="selected"';
207                    if($this->getConf('dropdown2')) { //FIXME ugly name
208                        $out .= $this->makecountrylink($LN, $idpart, $t, false);
209                        $out .= "&nbsp;";
210                    }
211                }else{
212                    $sel = '';
213                }
214                if(page_exists($link,'',false)){
215                    $class = 'wikilink1';
216                }else{
217                    $class = 'wikilink2';
218                }
219
220                //linktitle
221                $linktitle = '';
222                if (strlen($LN[$name]) > 0){
223                    $linktitle = $LN[$name];
224                } else{
225                    $linktitle = hsc($name);
226                }
227
228                $out2 .= '<option value="'.$link.'"'.$sel.' class="'.$class.'" title="'.$linktitle.'">'.hsc($name).'</option>';
229            }
230            $out .= '<form action="'.wl().'" id="translation__dropdown">';
231            $out .= '<select name="id" class="'.$class.'">';
232            $out .= $out2;
233            $out .= '</select>';
234            $out .= '<input name="go" type="submit" value="&rarr;" />';
235            $out .= '</form>';
236
237            //link to about (right)
238            if (!$this->getConf('description') && $this->getConf('showabout')) {
239                $out .= '&nbsp';
240                $out .= $this->showAbout();
241            }
242        }else{ // use list
243            $out .= '<ul>';
244
245            // FIXME what's this?
246            if (!$this->getConf('description') && $this->getConf('showabout')) {
247                $out .= '&nbsp';
248                $out .= $this->showAbout();
249            }
250
251            foreach($this->trans as $t){
252                $out .= $this->makecountrylink($LN, $idpart, $t, true);
253            }
254            $out .= '</ul>';
255        }
256
257        $out .= '</div>';
258
259        return $out;
260    }
261
262    /**
263     * Create the link or option for a single translation
264     *
265     * @fixme bad name - translations are not about countries
266     * @param $LN string      The language
267     * @param $idpart string  The ID of the translated page
268     * @param $t  FIXME
269     * @param $div bool  true for lists, false for dropdown FIXME
270     * @returns FIXME
271     */
272    function makecountrylink($LN, $idpart, $t, $div) {
273        global $ID;
274        global $conf;
275        global $INFO;
276
277        require(DOKU_PLUGIN.'translation/flags/langnames.php');
278
279        list($link,$name) = $this->buildTransID($t,$idpart);
280        $link = cleanID($link);
281        if(page_exists($link,'',false)){
282            $class = 'wikilink1';
283        }else{
284            $class = 'wikilink2';
285        }
286
287        //linktitle
288        $linktitle = '';
289        if (strlen($LN[$name]) > 0){
290            $linktitle = $LN[$name];
291        } else{
292            $linktitle = hsc($name);
293        }
294
295        //if (show flag AND ((flag exist) OR (flag not exist AND show blank flag))
296        if (($langflag[hsc($name)] != NULL && strlen($langflag[hsc($name)]) > 0 && $this->getConf('flags')) || $this->getConf('flags') && $this->getConf('blankflag')) {
297
298            resolve_pageid(getNS($ID),$link,$exists);
299            if ($div) {
300                if ($exists){ //solid box
301                    $out .= '  <li><div class="li">';
302                } else{ //50% transparent box (50% transparent flag)
303                    $out .= '  <li><div class="flag_not_exists">';
304                }
305            }
306
307            //html_wikilink works very slow for images
308            //$flag['title'] = $langname[$name];
309            //$flag['src'] = DOKU_URL.'lib/plugins/translation/flags/'.$langflag[$name];
310            //$out .= html_wikilink($link,$flag);
311
312            $out .= '<a href="'.wl($link).'"';
313            $out .= 'title="'.$linktitle.'"';
314            //class for image
315            $out .= 'class="wikilink3"'; //FIXME WTF?
316            $out .= '>';
317
318            //show flag
319            if ($langflag[hsc($name)] != NULL && strlen($langflag[hsc($name)]) > 0){
320                $out .= '<img src="'.DOKU_URL.'lib/plugins/translation/flags/'.$langflag[hsc($name)].'" alt='.$linktitle.'" border="0">';
321            } else{ //show blank flag
322                //$out .= '<img src="'.DOKU_BASE.'lib/images/blank.gif'.'" width=15 height=11 alt="'.$linktitle.'" border="0">';
323                $out .= '<img src="'.DOKU_BASE.'lib/plugins/translation/flags/blankflag.gif'.'" width=15 height=11 alt="'.$linktitle.'" border="0">';
324            }
325            $out .= '</a>';
326
327        } else{ //show text (also if flag not exist and blankflag=false)
328            if ($div) {
329                $out .= '  <li><div class="li">';
330            }
331            $out .= html_wikilink($link,hsc($name));
332        }
333        if ($div) {
334            $out .= '</div></li>';
335        }
336
337        return $out;
338    }
339
340    /**
341     * Checks if the current page is a translation of a page
342     * in the default language. Displays a notice when it is
343     * older than the original page. Tries to lin to a diff
344     * with changes on the original since the translation
345     */
346    function checkage(){
347        global $ID;
348        global $INFO;
349        if(!$this->getConf('checkage')) return;
350        if(!$INFO['exists']) return;
351        $lng = $this->getLangPart($ID);
352        if($lng == $this->defaultlang) return;
353
354        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
355        $idpart = preg_replace($rx,'',$ID);
356
357        // compare modification times
358        list($orig,$name) = $this->buildTransID($this->defaultlang,$idpart);
359        $origfn = wikiFN($orig);
360        if($INFO['lastmod'] >= @filemtime($origfn) ) return;
361
362        // get revision from before translation
363        $orev = 0;
364        $revs = getRevisions($orig,0,100);
365        foreach($revs as $rev){
366            if($rev < $INFO['lastmod']){
367                $orev = $rev;
368                break;
369            }
370        }
371
372        // see if the found revision still exists
373        if($orev && !page_exists($orig,$orev)) $orev=0;
374
375        // build the message and display it
376        $orig = cleanID($orig);
377        $msg = sprintf($this->getLang('outdated'),wl($orig));
378        if($orev){
379            $msg .= sprintf(' '.$this->getLang('diff'),
380                    wl($orig,array('do'=>'diff','rev'=>$orev)));
381        }
382
383        echo '<div class="notify">'.$msg.'</div>';
384    }
385}
386