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