xref: /plugin/autotranslation/helper.php (revision 8bd452a32c9625f62ce513b081a1c2d9f5601982)
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
159        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
160        $idpart = preg_replace($rx,'',$ID);
161
162        $out  = '<div class="plugin_translation">';
163
164        //show text
165        if ($this->getConf('description')){
166            $out .= '<span>'.$this->getLang('translations');
167            if ($this->getConf('about')) $out .= $this->showAbout();
168            $out .= ':</span> ';
169        }
170
171        if($this->getConf('dropdown')){ // use dropdown fixme move to own functions
172            if($INFO['exists']){
173                $class = 'wikilink1';
174            }else{
175                $class = 'wikilink2';
176            }
177
178            $out2 = ""; //FIXME ugly name
179            foreach($this->trans as $t){
180                list($link,$name) = $this->buildTransID($t,$idpart);
181                $link = cleanID($link);
182                if($ID == $link){
183                    $sel = ' selected="selected"';
184                    if($this->getConf('dropdown2')) { //FIXME ugly name
185                        $out .= $this->makecountrylink($LN, $idpart, $t, false);
186                        $out .= "&nbsp;";
187                    }
188                }else{
189                    $sel = '';
190                }
191                if(page_exists($link,'',false)){
192                    $class = 'wikilink1';
193                }else{
194                    $class = 'wikilink2';
195                }
196
197                //linktitle
198                $linktitle = '';
199                if (strlen($LN[$name]) > 0){
200                    $linktitle = $LN[$name];
201                } else{
202                    $linktitle = hsc($name);
203                }
204
205                $out2 .= '<option value="'.$link.'"'.$sel.' class="'.$class.'" title="'.$linktitle.'">'.hsc($name).'</option>';
206            }
207            $out .= '<form action="'.wl().'" id="translation__dropdown">';
208            $out .= '<select name="id" class="'.$class.'">';
209            $out .= $out2;
210            $out .= '</select>';
211            $out .= '<input name="go" type="submit" value="&rarr;" />';
212            $out .= '</form>';
213
214            //link to about (right)
215            if (!$this->getConf('description') && $this->getConf('about')) {
216                $out .= '&nbsp';
217                $out .= $this->showAbout();
218            }
219        }else{ // use list
220            $out .= '<ul>';
221
222            // FIXME what's this?
223            if (!$this->getConf('description') && $this->getConf('about')) {
224                $out .= '&nbsp';
225                $out .= $this->showAbout();
226            }
227
228            foreach($this->trans as $t){
229                $out .= $this->makecountrylink($LN, $idpart, $t, true);
230            }
231            $out .= '</ul>';
232        }
233
234        $out .= '</div>';
235
236        return $out;
237    }
238
239    /**
240     * Create the link or option for a single translation
241     *
242     * @fixme bad name - translations are not about countries
243     * @param $LN string      The language
244     * @param $idpart string  The ID of the translated page
245     * @param $t  FIXME
246     * @param $div bool  true for lists, false for dropdown FIXME
247     * @returns FIXME
248     */
249    function makecountrylink($LN, $idpart, $t, $div) {
250        global $ID;
251        global $conf;
252        global $INFO;
253
254        require(DOKU_PLUGIN.'translation/flags/langnames.php');
255
256        list($link,$name) = $this->buildTransID($t,$idpart);
257        $link = cleanID($link);
258        if(page_exists($link,'',false)){
259            $class = 'wikilink1';
260        }else{
261            $class = 'wikilink2';
262        }
263
264        //linktitle
265        $linktitle = '';
266        if (strlen($LN[$name]) > 0){
267            $linktitle = $LN[$name];
268        } else{
269            $linktitle = hsc($name);
270        }
271
272        //if (show flag AND ((flag exist) OR (flag not exist AND show blank flag))
273        if (($langflag[hsc($name)] != NULL && strlen($langflag[hsc($name)]) > 0 && $this->getConf('flags')) || $this->getConf('flags') && $this->getConf('blankflag')) {
274
275            resolve_pageid(getNS($ID),$link,$exists);
276            if ($div) {
277                if ($exists){ //solid box
278                    $out .= '  <li><div class="li">';
279                } else{ //50% transparent box (50% transparent flag)
280                    $out .= '  <li><div class="flag_not_exists">';
281                }
282            }
283
284            //html_wikilink works very slow for images
285            //$flag['title'] = $langname[$name];
286            //$flag['src'] = DOKU_URL.'lib/plugins/translation/flags/'.$langflag[$name];
287            //$out .= html_wikilink($link,$flag);
288
289            $out .= '<a href="'.wl($link).'"';
290            $out .= 'title="'.$linktitle.'"';
291            //class for image
292            $out .= 'class="wikilink3"'; //FIXME WTF?
293            $out .= '>';
294
295            //show flag
296            if ($langflag[hsc($name)] != NULL && strlen($langflag[hsc($name)]) > 0){
297                $out .= '<img src="'.DOKU_URL.'lib/plugins/translation/flags/'.$langflag[hsc($name)].'" alt='.$linktitle.'" border="0">';
298            } else{ //show blank flag
299                //$out .= '<img src="'.DOKU_BASE.'lib/images/blank.gif'.'" width=15 height=11 alt="'.$linktitle.'" border="0">';
300                $out .= '<img src="'.DOKU_BASE.'lib/plugins/translation/flags/blankflag.gif'.'" width=15 height=11 alt="'.$linktitle.'" border="0">';
301            }
302            $out .= '</a>';
303
304        } else{ //show text (also if flag not exist and blankflag=false)
305            if ($div) {
306                $out .= '  <li><div class="li">';
307            }
308            $out .= html_wikilink($link,hsc($name));
309        }
310        if ($div) {
311            $out .= '</div></li>';
312        }
313
314        return $out;
315    }
316
317    /**
318     * Checks if the current page is a translation of a page
319     * in the default language. Displays a notice when it is
320     * older than the original page. Tries to lin to a diff
321     * with changes on the original since the translation
322     */
323    function checkage(){
324        global $ID;
325        global $INFO;
326        if(!$this->getConf('checkage')) return;
327        if(!$INFO['exists']) return;
328        $lng = $this->getLangPart($ID);
329        if($lng == $this->defaultlang) return;
330
331        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
332        $idpart = preg_replace($rx,'',$ID);
333
334        // compare modification times
335        list($orig,$name) = $this->buildTransID($this->defaultlang,$idpart);
336        $origfn = wikiFN($orig);
337        if($INFO['lastmod'] >= @filemtime($origfn) ) return;
338
339        // get revision from before translation
340        $orev = 0;
341        $revs = getRevisions($orig,0,100);
342        foreach($revs as $rev){
343            if($rev < $INFO['lastmod']){
344                $orev = $rev;
345                break;
346            }
347        }
348
349        // see if the found revision still exists
350        if($orev && !page_exists($orig,$orev)) $orev=0;
351
352        // build the message and display it
353        $orig = cleanID($orig);
354        $msg = sprintf($this->getLang('outdated'),wl($orig));
355        if($orev){
356            $msg .= sprintf(' '.$this->getLang('diff'),
357                    wl($orig,array('do'=>'diff','rev'=>$orev)));
358        }
359
360        echo '<div class="notify">'.$msg.'</div>';
361    }
362}
363