xref: /plugin/autotranslation/helper.php (revision 49a71a894777f09fa70b9a8f4647f9077f8a6798)
1af1904f9SAndreas Gohr<?php
2af1904f9SAndreas Gohr/**
3af1904f9SAndreas Gohr * Translation Plugin: Simple multilanguage plugin
4af1904f9SAndreas Gohr *
5af1904f9SAndreas Gohr * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6af1904f9SAndreas Gohr * @author     Andreas Gohr <andi@splitbrain.org>
7af1904f9SAndreas Gohr */
8af1904f9SAndreas Gohr
9af1904f9SAndreas Gohr// must be run within Dokuwiki
10af1904f9SAndreas Gohrif(!defined('DOKU_INC')) die();
11af1904f9SAndreas Gohr
12af1904f9SAndreas Gohrclass helper_plugin_translation extends DokuWiki_Plugin {
13af1904f9SAndreas Gohr    var $trans       = array();
14af1904f9SAndreas Gohr    var $tns         = '';
157c54a0a6SAndreas Gohr    var $defaultlang = '';
16*49a71a89SAndreas Gohr    var $LN          = array(); // hold native names
17af1904f9SAndreas Gohr
18af1904f9SAndreas Gohr    /**
19af1904f9SAndreas Gohr     * Initialize
20af1904f9SAndreas Gohr     */
21af1904f9SAndreas Gohr    function helper_plugin_translation(){
227c54a0a6SAndreas Gohr        global $conf;
23af1904f9SAndreas Gohr        require_once(DOKU_INC.'inc/pageutils.php');
24af1904f9SAndreas Gohr        require_once(DOKU_INC.'inc/utf8.php');
25af1904f9SAndreas Gohr
26af1904f9SAndreas Gohr        // load wanted translation into array
27af1904f9SAndreas Gohr        $this->trans = strtolower(str_replace(',',' ',$this->getConf('translations')));
28af1904f9SAndreas Gohr        $this->trans = array_unique(array_filter(explode(' ',$this->trans)));
29af1904f9SAndreas Gohr        sort($this->trans);
307c54a0a6SAndreas Gohr
31*49a71a89SAndreas Gohr        // load language names
32*49a71a89SAndreas Gohr        $this->LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
33*49a71a89SAndreas Gohr
347c54a0a6SAndreas Gohr        // get default translation
357c54a0a6SAndreas Gohr        if(!$conf['lang_before_translation']){
367c54a0a6SAndreas Gohr            $dfl = $conf['lang'];
377c54a0a6SAndreas Gohr        } else {
387c54a0a6SAndreas Gohr            $dfl = $conf['lang_before_translation'];
397c54a0a6SAndreas Gohr        }
407c54a0a6SAndreas Gohr        if(in_array($dfl,$this->trans)){
417c54a0a6SAndreas Gohr            $this->defaultlang = $dfl;
427c54a0a6SAndreas Gohr        }else{
437c54a0a6SAndreas Gohr            $this->defaultlang = '';
44af1904f9SAndreas Gohr            array_unshift($this->trans,'');
457c54a0a6SAndreas Gohr        }
467c54a0a6SAndreas Gohr
47af1904f9SAndreas Gohr
48af1904f9SAndreas Gohr        $this->tns = cleanID($this->getConf('translationns'));
49af1904f9SAndreas Gohr        if($this->tns) $this->tns .= ':';
50af1904f9SAndreas Gohr    }
51af1904f9SAndreas Gohr
52af1904f9SAndreas Gohr    /**
53af1904f9SAndreas Gohr     * Check if the given ID is a translation and return the language code.
54af1904f9SAndreas Gohr     */
55af1904f9SAndreas Gohr    function getLangPart($id){
56af1904f9SAndreas Gohr        $rx = '/^'.$this->tns.'('.join('|',$this->trans).'):/';
57af1904f9SAndreas Gohr        if(preg_match($rx,$id,$match)){
58af1904f9SAndreas Gohr            return $match[1];
59af1904f9SAndreas Gohr        }
60af1904f9SAndreas Gohr        return '';
61af1904f9SAndreas Gohr    }
62af1904f9SAndreas Gohr
63af1904f9SAndreas Gohr    /**
647053cd66SAndreas Gohr     * Returns the browser language if it matches with one of the configured
657053cd66SAndreas Gohr     * languages
667053cd66SAndreas Gohr     */
677053cd66SAndreas Gohr    function getBrowserLang(){
687053cd66SAndreas Gohr        $rx = '/(^|,|:|;|-)('.join('|',$this->trans).')($|,|:|;|-)/i';
697053cd66SAndreas Gohr        if(preg_match($rx,$_SERVER['HTTP_ACCEPT_LANGUAGE'],$match)){
707053cd66SAndreas Gohr            return strtolower($match[2]);
717053cd66SAndreas Gohr        }
727053cd66SAndreas Gohr        return false;
737053cd66SAndreas Gohr    }
747053cd66SAndreas Gohr
757053cd66SAndreas Gohr
767053cd66SAndreas Gohr    /**
777c54a0a6SAndreas Gohr     * Returns the ID and name to the wanted translation, empty
787c54a0a6SAndreas Gohr     * $lng is default lang
79af1904f9SAndreas Gohr     */
80af1904f9SAndreas Gohr    function buildTransID($lng,$idpart){
81af1904f9SAndreas Gohr        global $conf;
82af1904f9SAndreas Gohr        global $saved_conf;
83af1904f9SAndreas Gohr        if($lng){
84af1904f9SAndreas Gohr            $link = ':'.$this->tns.$lng.':'.$idpart;
85af1904f9SAndreas Gohr            $name = $lng;
86af1904f9SAndreas Gohr        }else{
87af1904f9SAndreas Gohr            $link = ':'.$this->tns.$idpart;
88af1904f9SAndreas Gohr            if(!$conf['lang_before_translation']){
89af1904f9SAndreas Gohr              $name = $conf['lang'];
90af1904f9SAndreas Gohr            } else {
91af1904f9SAndreas Gohr              $name = $conf['lang_before_translation'];
92af1904f9SAndreas Gohr            }
93af1904f9SAndreas Gohr        }
94af1904f9SAndreas Gohr        return array($link,$name);
95af1904f9SAndreas Gohr    }
96af1904f9SAndreas Gohr
971469199dSAndreas Gohr    /**
9884877e9bSAndreas Gohr     * Check if current ID should be translated and any GUI
9984877e9bSAndreas Gohr     * should be shown
10084877e9bSAndreas Gohr     */
10184877e9bSAndreas Gohr    function istranslatable($id,$checkact=true){
10284877e9bSAndreas Gohr        global $ACT;
10384877e9bSAndreas Gohr
10484877e9bSAndreas Gohr        if($checkact && $ACT != 'show') return false;
10584877e9bSAndreas Gohr        if($this->tns && strpos($id,$this->tns) !== 0) return false;
10684877e9bSAndreas Gohr        $skiptrans = trim($this->getConf('skiptrans'));
10784877e9bSAndreas Gohr        if($skiptrans &&  preg_match('/'.$skiptrans.'/ui',':'.$id)) return false;
10884877e9bSAndreas Gohr        $meta = p_get_metadata($id);
10984877e9bSAndreas Gohr        if($meta['plugin']['translation']['notrans']) return false;
11084877e9bSAndreas Gohr
11184877e9bSAndreas Gohr        return true;
11284877e9bSAndreas Gohr    }
11384877e9bSAndreas Gohr
11401dd7da9SAndreas Gohr    /**
11501dd7da9SAndreas Gohr     * Return the (localized) about link
11601dd7da9SAndreas Gohr     *
11701dd7da9SAndreas Gohr     * @fixme why is this doing the detection stuff again?
11801dd7da9SAndreas Gohr     */
11901dd7da9SAndreas Gohr    function showAbout() {
120c9640767STomasz Tomasik        global $ID;
121c9640767STomasz Tomasik        global $conf;
122c9640767STomasz Tomasik        global $INFO;
123c9640767STomasz Tomasik
124c9640767STomasz Tomasik        $this->checkage();
125c9640767STomasz Tomasik
126c9640767STomasz Tomasik        $LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
127c9640767STomasz Tomasik
128c9640767STomasz Tomasik        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
129c9640767STomasz Tomasik        $idpart = preg_replace($rx,'',$ID);
130c9640767STomasz Tomasik
131c9640767STomasz Tomasik        $out = '';
132c9640767STomasz Tomasik        $out .= '<sup>';
133c9640767STomasz Tomasik        if($this->getConf('localabout')){
134c9640767STomasz Tomasik            $lc = '';
135c9640767STomasz Tomasik
136c9640767STomasz Tomasik            //try main lang namespace
137c9640767STomasz Tomasik            foreach($this->trans as $t){
138c9640767STomasz Tomasik                list($link,$name) = $this->buildTransID($t,$idpart);
139c9640767STomasz Tomasik                $link = cleanID($link);
140c9640767STomasz Tomasik                if($ID == $link){
141c9640767STomasz Tomasik                    $lc = hsc($name);
142c9640767STomasz Tomasik                }
143c9640767STomasz Tomasik                if ($lc) break;
144c9640767STomasz Tomasik            }
145c9640767STomasz Tomasik
146c9640767STomasz Tomasik            //try browser language
147c9640767STomasz Tomasik            if(!$lc) $lc = $this->getBrowserLang();
148c9640767STomasz Tomasik
149c9640767STomasz Tomasik            //try wiki language
150c9640767STomasz Tomasik            if(!$lc) $lc = $conf['lang'];
151c9640767STomasz Tomasik
152c9640767STomasz Tomasik            if(!$lc) { //can't find language
153c9640767STomasz Tomasik                $localabout = $this->getConf('about'); //http://localhost/dokuwiki/doku.php?id=translation:about
154c9640767STomasz Tomasik            } else { //i found language!
155c9640767STomasz Tomasik                        $localabout = $lc.':'.$this->getConf('about'); //http://localhost/dokuwiki/doku.php?id=en:translation:about
156c9640767STomasz Tomasik            }
157c9640767STomasz Tomasik
158c9640767STomasz Tomasik            //make link
159c9640767STomasz Tomasik            $out .= html_wikilink($localabout,'?');
16001dd7da9SAndreas Gohr            } else {
161c9640767STomasz Tomasik            $out .= html_wikilink($this->getConf('about'),'?');
162c9640767STomasz Tomasik        }
163c9640767STomasz Tomasik        $out .= '</sup>';
164c9640767STomasz Tomasik
165c9640767STomasz Tomasik        return $out;
166c9640767STomasz Tomasik    }
167c9640767STomasz Tomasik
16884877e9bSAndreas Gohr    /**
1691469199dSAndreas Gohr     * Displays the available and configured translations. Needs to be placed in the template.
1701469199dSAndreas Gohr     */
1711469199dSAndreas Gohr    function showTranslations(){
1721469199dSAndreas Gohr        global $ID;
1731469199dSAndreas Gohr        global $conf;
1741469199dSAndreas Gohr        global $INFO;
1751469199dSAndreas Gohr
17684877e9bSAndreas Gohr        if(!$this->istranslatable($ID)) return;
17784877e9bSAndreas Gohr
17884877e9bSAndreas Gohr        $this->checkage();
1791469199dSAndreas Gohr
18039ecab8bSAndreas Gohr        $LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
18139ecab8bSAndreas Gohr
1821469199dSAndreas Gohr        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
1831469199dSAndreas Gohr        $idpart = preg_replace($rx,'',$ID);
1841469199dSAndreas Gohr
1851469199dSAndreas Gohr        $out  = '<div class="plugin_translation">';
186c9640767STomasz Tomasik
187c9640767STomasz Tomasik        //show text
188c9640767STomasz Tomasik        if ($this->getConf('description')){
1891469199dSAndreas Gohr            $out .= '<span>'.$this->getLang('translations');
190c9640767STomasz Tomasik            if ($this->getConf('showabout')) $out .= $this->showAbout();
1911469199dSAndreas Gohr            $out .= ':</span> ';
192c9640767STomasz Tomasik        }
1931469199dSAndreas Gohr
19401dd7da9SAndreas Gohr        if($this->getConf('dropdown')){ // use dropdown fixme move to own functions
1951469199dSAndreas Gohr            if($INFO['exists']){
1961469199dSAndreas Gohr                $class = 'wikilink1';
1971469199dSAndreas Gohr            }else{
1981469199dSAndreas Gohr                $class = 'wikilink2';
1991469199dSAndreas Gohr            }
200c9640767STomasz Tomasik
20101dd7da9SAndreas Gohr            $out2 = ""; //FIXME ugly name
2021469199dSAndreas Gohr            foreach($this->trans as $t){
2031469199dSAndreas Gohr                list($link,$name) = $this->buildTransID($t,$idpart);
2041469199dSAndreas Gohr                $link = cleanID($link);
2051469199dSAndreas Gohr                if($ID == $link){
2061469199dSAndreas Gohr                    $sel = ' selected="selected"';
20701dd7da9SAndreas Gohr                    if($this->getConf('dropdown2')) { //FIXME ugly name
208c9640767STomasz Tomasik                        $out .= $this->makecountrylink($LN, $idpart, $t, false);
209c9640767STomasz Tomasik                        $out .= "&nbsp;";
210c9640767STomasz Tomasik                    }
2111469199dSAndreas Gohr                }else{
2121469199dSAndreas Gohr                    $sel = '';
2131469199dSAndreas Gohr                }
2141469199dSAndreas Gohr                if(page_exists($link,'',false)){
2151469199dSAndreas Gohr                    $class = 'wikilink1';
2161469199dSAndreas Gohr                }else{
2171469199dSAndreas Gohr                    $class = 'wikilink2';
2181469199dSAndreas Gohr                }
219c9640767STomasz Tomasik
220c9640767STomasz Tomasik                //linktitle
221c9640767STomasz Tomasik                $linktitle = '';
222c9640767STomasz Tomasik                if (strlen($LN[$name]) > 0){
223c9640767STomasz Tomasik                    $linktitle = $LN[$name];
224c9640767STomasz Tomasik                } else{
225c9640767STomasz Tomasik                    $linktitle = hsc($name);
2261469199dSAndreas Gohr                }
227c9640767STomasz Tomasik
228c9640767STomasz Tomasik                $out2 .= '<option value="'.$link.'"'.$sel.' class="'.$class.'" title="'.$linktitle.'">'.hsc($name).'</option>';
229c9640767STomasz Tomasik            }
230c9640767STomasz Tomasik            $out .= '<form action="'.wl().'" id="translation__dropdown">';
231c9640767STomasz Tomasik            $out .= '<select name="id" class="'.$class.'">';
232c9640767STomasz Tomasik            $out .= $out2;
2331469199dSAndreas Gohr            $out .= '</select>';
2341469199dSAndreas Gohr            $out .= '<input name="go" type="submit" value="&rarr;" />';
2351469199dSAndreas Gohr            $out .= '</form>';
236c9640767STomasz Tomasik
237c9640767STomasz Tomasik            //link to about (right)
238c9640767STomasz Tomasik            if (!$this->getConf('description') && $this->getConf('showabout')) {
239c9640767STomasz Tomasik                $out .= '&nbsp';
240c9640767STomasz Tomasik                $out .= $this->showAbout();
24139ecab8bSAndreas Gohr            }
242c9640767STomasz Tomasik        }else{ // use list
243c9640767STomasz Tomasik            $out .= '<ul>';
244c9640767STomasz Tomasik
24501dd7da9SAndreas Gohr            // FIXME what's this?
246c9640767STomasz Tomasik            if (!$this->getConf('description') && $this->getConf('showabout')) {
247c9640767STomasz Tomasik                $out .= '&nbsp';
248c9640767STomasz Tomasik                $out .= $this->showAbout();
249c9640767STomasz Tomasik            }
250c9640767STomasz Tomasik
251c9640767STomasz Tomasik            foreach($this->trans as $t){
252c9640767STomasz Tomasik                $out .= $this->makecountrylink($LN, $idpart, $t, true);
2531469199dSAndreas Gohr            }
2541469199dSAndreas Gohr            $out .= '</ul>';
2551469199dSAndreas Gohr        }
2561469199dSAndreas Gohr
2571469199dSAndreas Gohr        $out .= '</div>';
2581469199dSAndreas Gohr
2591469199dSAndreas Gohr        return $out;
2601469199dSAndreas Gohr    }
261af1904f9SAndreas Gohr
26201dd7da9SAndreas Gohr    /**
26301dd7da9SAndreas Gohr     * Create the link or option for a single translation
26401dd7da9SAndreas Gohr     *
26501dd7da9SAndreas Gohr     * @fixme bad name - translations are not about countries
26601dd7da9SAndreas Gohr     * @param $LN string      The language
26701dd7da9SAndreas Gohr     * @param $idpart string  The ID of the translated page
26801dd7da9SAndreas Gohr     * @param $t  FIXME
26901dd7da9SAndreas Gohr     * @param $div bool  true for lists, false for dropdown FIXME
27001dd7da9SAndreas Gohr     * @returns FIXME
27101dd7da9SAndreas Gohr     */
27201dd7da9SAndreas Gohr    function makecountrylink($LN, $idpart, $t, $div) {
273c9640767STomasz Tomasik        global $ID;
274c9640767STomasz Tomasik        global $conf;
275c9640767STomasz Tomasik        global $INFO;
276c9640767STomasz Tomasik
277c9640767STomasz Tomasik        require(DOKU_PLUGIN.'translation/flags/langnames.php');
278c9640767STomasz Tomasik
279c9640767STomasz Tomasik        list($link,$name) = $this->buildTransID($t,$idpart);
280c9640767STomasz Tomasik        $link = cleanID($link);
281c9640767STomasz Tomasik        if(page_exists($link,'',false)){
282c9640767STomasz Tomasik            $class = 'wikilink1';
283c9640767STomasz Tomasik        }else{
284c9640767STomasz Tomasik            $class = 'wikilink2';
285c9640767STomasz Tomasik        }
286c9640767STomasz Tomasik
287c9640767STomasz Tomasik        //linktitle
288c9640767STomasz Tomasik        $linktitle = '';
289c9640767STomasz Tomasik        if (strlen($LN[$name]) > 0){
290c9640767STomasz Tomasik            $linktitle = $LN[$name];
291c9640767STomasz Tomasik        } else{
292c9640767STomasz Tomasik            $linktitle = hsc($name);
293c9640767STomasz Tomasik        }
294c9640767STomasz Tomasik
295c9640767STomasz Tomasik        //if (show flag AND ((flag exist) OR (flag not exist AND show blank flag))
296c9640767STomasz Tomasik        if (($langflag[hsc($name)] != NULL && strlen($langflag[hsc($name)]) > 0 && $this->getConf('flags')) || $this->getConf('flags') && $this->getConf('blankflag')) {
297c9640767STomasz Tomasik
298c9640767STomasz Tomasik            resolve_pageid(getNS($ID),$link,$exists);
29901dd7da9SAndreas Gohr            if ($div) {
300c9640767STomasz Tomasik                if ($exists){ //solid box
301c9640767STomasz Tomasik                    $out .= '  <li><div class="li">';
302c9640767STomasz Tomasik                } else{ //50% transparent box (50% transparent flag)
303c9640767STomasz Tomasik                    $out .= '  <li><div class="flag_not_exists">';
304c9640767STomasz Tomasik                }
305c9640767STomasz Tomasik            }
306c9640767STomasz Tomasik
307c9640767STomasz Tomasik            //html_wikilink works very slow for images
308c9640767STomasz Tomasik            //$flag['title'] = $langname[$name];
309c9640767STomasz Tomasik            //$flag['src'] = DOKU_URL.'lib/plugins/translation/flags/'.$langflag[$name];
310c9640767STomasz Tomasik            //$out .= html_wikilink($link,$flag);
311c9640767STomasz Tomasik
312c9640767STomasz Tomasik            $out .= '<a href="'.wl($link).'"';
313c9640767STomasz Tomasik            $out .= 'title="'.$linktitle.'"';
314c9640767STomasz Tomasik            //class for image
31501dd7da9SAndreas Gohr            $out .= 'class="wikilink3"'; //FIXME WTF?
316c9640767STomasz Tomasik            $out .= '>';
317c9640767STomasz Tomasik
318c9640767STomasz Tomasik            //show flag
319c9640767STomasz Tomasik            if ($langflag[hsc($name)] != NULL && strlen($langflag[hsc($name)]) > 0){
320c9640767STomasz Tomasik                $out .= '<img src="'.DOKU_URL.'lib/plugins/translation/flags/'.$langflag[hsc($name)].'" alt='.$linktitle.'" border="0">';
321c9640767STomasz Tomasik            } else{ //show blank flag
322c9640767STomasz Tomasik                //$out .= '<img src="'.DOKU_BASE.'lib/images/blank.gif'.'" width=15 height=11 alt="'.$linktitle.'" border="0">';
323c9640767STomasz Tomasik                $out .= '<img src="'.DOKU_BASE.'lib/plugins/translation/flags/blankflag.gif'.'" width=15 height=11 alt="'.$linktitle.'" border="0">';
324c9640767STomasz Tomasik            }
325c9640767STomasz Tomasik            $out .= '</a>';
326c9640767STomasz Tomasik
32701dd7da9SAndreas Gohr        } else{ //show text (also if flag not exist and blankflag=false)
32801dd7da9SAndreas Gohr            if ($div) {
329c9640767STomasz Tomasik                $out .= '  <li><div class="li">';
330c9640767STomasz Tomasik            }
331c9640767STomasz Tomasik            $out .= html_wikilink($link,hsc($name));
332c9640767STomasz Tomasik        }
33301dd7da9SAndreas Gohr        if ($div) {
334c9640767STomasz Tomasik            $out .= '</div></li>';
335c9640767STomasz Tomasik        }
336c9640767STomasz Tomasik
337c9640767STomasz Tomasik        return $out;
338c9640767STomasz Tomasik    }
339c9640767STomasz Tomasik
34084877e9bSAndreas Gohr    /**
34184877e9bSAndreas Gohr     * Checks if the current page is a translation of a page
34284877e9bSAndreas Gohr     * in the default language. Displays a notice when it is
34384877e9bSAndreas Gohr     * older than the original page. Tries to lin to a diff
34484877e9bSAndreas Gohr     * with changes on the original since the translation
34584877e9bSAndreas Gohr     */
34684877e9bSAndreas Gohr    function checkage(){
34784877e9bSAndreas Gohr        global $ID;
34884877e9bSAndreas Gohr        global $INFO;
34984877e9bSAndreas Gohr        if(!$this->getConf('checkage')) return;
35084877e9bSAndreas Gohr        if(!$INFO['exists']) return;
35184877e9bSAndreas Gohr        $lng = $this->getLangPart($ID);
35284877e9bSAndreas Gohr        if($lng == $this->defaultlang) return;
353af1904f9SAndreas Gohr
35484877e9bSAndreas Gohr        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
35584877e9bSAndreas Gohr        $idpart = preg_replace($rx,'',$ID);
35684877e9bSAndreas Gohr
35784877e9bSAndreas Gohr        // compare modification times
35884877e9bSAndreas Gohr        list($orig,$name) = $this->buildTransID($this->defaultlang,$idpart);
35984877e9bSAndreas Gohr        $origfn = wikiFN($orig);
36084877e9bSAndreas Gohr        if($INFO['lastmod'] >= @filemtime($origfn) ) return;
36184877e9bSAndreas Gohr
36284877e9bSAndreas Gohr        // get revision from before translation
36384877e9bSAndreas Gohr        $orev = 0;
36484877e9bSAndreas Gohr        $revs = getRevisions($orig,0,100);
36584877e9bSAndreas Gohr        foreach($revs as $rev){
36684877e9bSAndreas Gohr            if($rev < $INFO['lastmod']){
36784877e9bSAndreas Gohr                $orev = $rev;
36884877e9bSAndreas Gohr                break;
36984877e9bSAndreas Gohr            }
37084877e9bSAndreas Gohr        }
37184877e9bSAndreas Gohr
37244552920SAndreas Gohr        // see if the found revision still exists
37344552920SAndreas Gohr        if($orev && !page_exists($orig,$orev)) $orev=0;
37444552920SAndreas Gohr
37584877e9bSAndreas Gohr        // build the message and display it
376dc3fbdb9SOleksiy Zagorskyi        $orig = cleanID($orig);
37784877e9bSAndreas Gohr        $msg = sprintf($this->getLang('outdated'),wl($orig));
37884877e9bSAndreas Gohr        if($orev){
37984877e9bSAndreas Gohr            $msg .= sprintf(' '.$this->getLang('diff'),
38084877e9bSAndreas Gohr                    wl($orig,array('do'=>'diff','rev'=>$orev)));
38184877e9bSAndreas Gohr        }
38200431e1eSAndreas Gohr
38300431e1eSAndreas Gohr        echo '<div class="notify">'.$msg.'</div>';
38484877e9bSAndreas Gohr    }
385af1904f9SAndreas Gohr}
386