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