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