xref: /plugin/autotranslation/helper.php (revision 04971eea45156aeb084c3a7f8bb24951c8c3f07d)
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 = '';
1649a71a89SAndreas Gohr    var $LN          = array(); // hold native names
17*04971eeaSAndreas Gohr    var $opts        = array(); // display options
18af1904f9SAndreas Gohr
19af1904f9SAndreas Gohr    /**
20af1904f9SAndreas Gohr     * Initialize
21af1904f9SAndreas Gohr     */
22af1904f9SAndreas Gohr    function helper_plugin_translation(){
237c54a0a6SAndreas Gohr        global $conf;
24af1904f9SAndreas Gohr        require_once(DOKU_INC.'inc/pageutils.php');
25af1904f9SAndreas Gohr        require_once(DOKU_INC.'inc/utf8.php');
26af1904f9SAndreas Gohr
27af1904f9SAndreas Gohr        // load wanted translation into array
28af1904f9SAndreas Gohr        $this->trans = strtolower(str_replace(',',' ',$this->getConf('translations')));
29af1904f9SAndreas Gohr        $this->trans = array_unique(array_filter(explode(' ',$this->trans)));
30af1904f9SAndreas Gohr        sort($this->trans);
317c54a0a6SAndreas Gohr
3249a71a89SAndreas Gohr        // load language names
3349a71a89SAndreas Gohr        $this->LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
3449a71a89SAndreas Gohr
35*04971eeaSAndreas Gohr        // display options
36*04971eeaSAndreas Gohr        $this->opts = $this->getConf('display');
37*04971eeaSAndreas Gohr        $this->opts = explode(',',$this->opts);
38*04971eeaSAndreas Gohr        $this->opts = array_map('trim',$this->opts);
39*04971eeaSAndreas Gohr        $this->opts = array_fill_keys($this->opts, true);
40*04971eeaSAndreas Gohr
417c54a0a6SAndreas Gohr        // get default translation
427c54a0a6SAndreas Gohr        if(!$conf['lang_before_translation']){
437c54a0a6SAndreas Gohr            $dfl = $conf['lang'];
447c54a0a6SAndreas Gohr        } else {
457c54a0a6SAndreas Gohr            $dfl = $conf['lang_before_translation'];
467c54a0a6SAndreas Gohr        }
477c54a0a6SAndreas Gohr        if(in_array($dfl,$this->trans)){
487c54a0a6SAndreas Gohr            $this->defaultlang = $dfl;
497c54a0a6SAndreas Gohr        }else{
507c54a0a6SAndreas Gohr            $this->defaultlang = '';
51af1904f9SAndreas Gohr            array_unshift($this->trans,'');
527c54a0a6SAndreas Gohr        }
537c54a0a6SAndreas Gohr
54af1904f9SAndreas Gohr        $this->tns = cleanID($this->getConf('translationns'));
55af1904f9SAndreas Gohr        if($this->tns) $this->tns .= ':';
56af1904f9SAndreas Gohr    }
57af1904f9SAndreas Gohr
58af1904f9SAndreas Gohr    /**
59af1904f9SAndreas Gohr     * Check if the given ID is a translation and return the language code.
60af1904f9SAndreas Gohr     */
61af1904f9SAndreas Gohr    function getLangPart($id){
6226522e09SAndreas Gohr        list($lng) = $this->getTransParts($id);
6326522e09SAndreas Gohr        return $lng;
64af1904f9SAndreas Gohr    }
6526522e09SAndreas Gohr
6626522e09SAndreas Gohr    /**
6726522e09SAndreas Gohr     * Check if the given ID is a translation and return the language code and
6826522e09SAndreas Gohr     * the id part.
6926522e09SAndreas Gohr     */
7026522e09SAndreas Gohr    function getTransParts($id){
7126522e09SAndreas Gohr        $rx = '/^'.$this->tns.'('.join('|',$this->trans).'):(.*)/';
7226522e09SAndreas Gohr        if(preg_match($rx,$id,$match)){
7326522e09SAndreas Gohr            return array($match[1],$match[2]);
7426522e09SAndreas Gohr        }
7526522e09SAndreas Gohr        return array('',$id);
76af1904f9SAndreas Gohr    }
77af1904f9SAndreas Gohr
78af1904f9SAndreas Gohr    /**
797053cd66SAndreas Gohr     * Returns the browser language if it matches with one of the configured
807053cd66SAndreas Gohr     * languages
817053cd66SAndreas Gohr     */
827053cd66SAndreas Gohr    function getBrowserLang(){
837053cd66SAndreas Gohr        $rx = '/(^|,|:|;|-)('.join('|',$this->trans).')($|,|:|;|-)/i';
847053cd66SAndreas Gohr        if(preg_match($rx,$_SERVER['HTTP_ACCEPT_LANGUAGE'],$match)){
857053cd66SAndreas Gohr            return strtolower($match[2]);
867053cd66SAndreas Gohr        }
877053cd66SAndreas Gohr        return false;
887053cd66SAndreas Gohr    }
897053cd66SAndreas Gohr
907053cd66SAndreas Gohr    /**
917c54a0a6SAndreas Gohr     * Returns the ID and name to the wanted translation, empty
927c54a0a6SAndreas Gohr     * $lng is default lang
93af1904f9SAndreas Gohr     */
94af1904f9SAndreas Gohr    function buildTransID($lng,$idpart){
95af1904f9SAndreas Gohr        global $conf;
96af1904f9SAndreas Gohr        if($lng){
97af1904f9SAndreas Gohr            $link = ':'.$this->tns.$lng.':'.$idpart;
98af1904f9SAndreas Gohr            $name = $lng;
99af1904f9SAndreas Gohr        }else{
100af1904f9SAndreas Gohr            $link = ':'.$this->tns.$idpart;
101*04971eeaSAndreas Gohr            $name = $this->realLC('');
102af1904f9SAndreas Gohr        }
103af1904f9SAndreas Gohr        return array($link,$name);
104af1904f9SAndreas Gohr    }
105af1904f9SAndreas Gohr
1061469199dSAndreas Gohr    /**
107*04971eeaSAndreas Gohr     * Returns the real language code, even when an empty one is given
108*04971eeaSAndreas Gohr     * (eg. resolves th default language)
109*04971eeaSAndreas Gohr     */
110*04971eeaSAndreas Gohr    function realLC($lc){
111*04971eeaSAndreas Gohr        global $conf;
112*04971eeaSAndreas Gohr        if($lc){
113*04971eeaSAndreas Gohr            return $lc;
114*04971eeaSAndreas Gohr        }elseif(!$conf['lang_before_translation']){
115*04971eeaSAndreas Gohr            return $conf['lang'];
116*04971eeaSAndreas Gohr        } else {
117*04971eeaSAndreas Gohr            return $conf['lang_before_translation'];
118*04971eeaSAndreas Gohr        }
119*04971eeaSAndreas Gohr    }
120*04971eeaSAndreas Gohr
121*04971eeaSAndreas Gohr    /**
12284877e9bSAndreas Gohr     * Check if current ID should be translated and any GUI
12384877e9bSAndreas Gohr     * should be shown
12484877e9bSAndreas Gohr     */
12584877e9bSAndreas Gohr    function istranslatable($id,$checkact=true){
12684877e9bSAndreas Gohr        global $ACT;
12784877e9bSAndreas Gohr
12884877e9bSAndreas Gohr        if($checkact && $ACT != 'show') return false;
12984877e9bSAndreas Gohr        if($this->tns && strpos($id,$this->tns) !== 0) return false;
13084877e9bSAndreas Gohr        $skiptrans = trim($this->getConf('skiptrans'));
13184877e9bSAndreas Gohr        if($skiptrans &&  preg_match('/'.$skiptrans.'/ui',':'.$id)) return false;
13284877e9bSAndreas Gohr        $meta = p_get_metadata($id);
13384877e9bSAndreas Gohr        if($meta['plugin']['translation']['notrans']) return false;
13484877e9bSAndreas Gohr
13584877e9bSAndreas Gohr        return true;
13684877e9bSAndreas Gohr    }
13784877e9bSAndreas Gohr
13801dd7da9SAndreas Gohr    /**
13901dd7da9SAndreas Gohr     * Return the (localized) about link
14001dd7da9SAndreas Gohr     */
14101dd7da9SAndreas Gohr    function showAbout() {
142c9640767STomasz Tomasik        global $ID;
143c9640767STomasz Tomasik        global $conf;
144c9640767STomasz Tomasik        global $INFO;
145c9640767STomasz Tomasik
146d0bdb959SAndreas Gohr        $about = $this->getConf('about');
147d0bdb959SAndreas Gohr        if($this->getConf('localabout')){
148d0bdb959SAndreas Gohr            list($lc,$idpart) = $this->getTransParts($about);
149*04971eeaSAndreas Gohr            list($about,$name) = $this->buildTransID($conf['lang'],$idpart); #FIXME conf[lang] is wrong
150d0bdb959SAndreas Gohr            $about = cleanID($about);
151d0bdb959SAndreas Gohr        }
152c9640767STomasz Tomasik
153c9640767STomasz Tomasik        $out = '';
154c9640767STomasz Tomasik        $out .= '<sup>';
155d0bdb959SAndreas Gohr        $out .= html_wikilink($about,'?');
156c9640767STomasz Tomasik        $out .= '</sup>';
157c9640767STomasz Tomasik
158c9640767STomasz Tomasik        return $out;
159c9640767STomasz Tomasik    }
160c9640767STomasz Tomasik
16184877e9bSAndreas Gohr    /**
1621469199dSAndreas Gohr     * Displays the available and configured translations. Needs to be placed in the template.
1631469199dSAndreas Gohr     */
1641469199dSAndreas Gohr    function showTranslations(){
1651469199dSAndreas Gohr        global $ID;
1661469199dSAndreas Gohr        global $conf;
1671469199dSAndreas Gohr        global $INFO;
1681469199dSAndreas Gohr
16984877e9bSAndreas Gohr        if(!$this->istranslatable($ID)) return;
17084877e9bSAndreas Gohr        $this->checkage();
1711469199dSAndreas Gohr
172*04971eeaSAndreas Gohr        list($lc,$idpart) = $this->getTransParts($ID);
173*04971eeaSAndreas Gohr        $lang = $this->realLC($lc);
17439ecab8bSAndreas Gohr
1751469199dSAndreas Gohr
1761469199dSAndreas Gohr        $out  = '<div class="plugin_translation">';
177c9640767STomasz Tomasik
178*04971eeaSAndreas Gohr        //show title and about
179c9640767STomasz Tomasik        if ($this->getConf('description')){
1801469199dSAndreas Gohr            $out .= '<span>'.$this->getLang('translations');
1818bd452a3SAndreas Gohr            if ($this->getConf('about')) $out .= $this->showAbout();
1821469199dSAndreas Gohr            $out .= ':</span> ';
183c9640767STomasz Tomasik        }
1841469199dSAndreas Gohr
185*04971eeaSAndreas Gohr        // open wrapper
186*04971eeaSAndreas Gohr        if($this->getConf('dropdown')){
187*04971eeaSAndreas Gohr            // select needs its own styling
1881469199dSAndreas Gohr            if($INFO['exists']){
1891469199dSAndreas Gohr                $class = 'wikilink1';
1901469199dSAndreas Gohr            }else{
1911469199dSAndreas Gohr                $class = 'wikilink2';
1921469199dSAndreas Gohr            }
193*04971eeaSAndreas Gohr            if(isset($this->opts['flag'])){
194*04971eeaSAndreas Gohr                $flag   = DOKU_BASE.'lib/plugins/translation/flags/'.hsc($lang).'.gif';
195c9640767STomasz Tomasik            }
196c9640767STomasz Tomasik            $out .= '<form action="'.wl().'" id="translation__dropdown">';
197*04971eeaSAndreas Gohr            if($flag) $out .= '<img src="'.$flag.'" alt="'.hsc($lang).'" height="11" class="'.$class.'" /> ';
198c9640767STomasz Tomasik            $out .= '<select name="id" class="'.$class.'">';
199*04971eeaSAndreas Gohr        }else{
200*04971eeaSAndreas Gohr            $out .= '<ul>';
201*04971eeaSAndreas Gohr        }
202*04971eeaSAndreas Gohr
203*04971eeaSAndreas Gohr        // insert items
204*04971eeaSAndreas Gohr        foreach($this->trans as $t){
205*04971eeaSAndreas Gohr            $out .= $this->getTransItem($t, $idpart);
206*04971eeaSAndreas Gohr        }
207*04971eeaSAndreas Gohr
208*04971eeaSAndreas Gohr        // close wrapper
209*04971eeaSAndreas Gohr        if($this->getConf('dropdown')){
2101469199dSAndreas Gohr            $out .= '</select>';
2111469199dSAndreas Gohr            $out .= '<input name="go" type="submit" value="&rarr;" />';
2121469199dSAndreas Gohr            $out .= '</form>';
213*04971eeaSAndreas Gohr        }else{
2141469199dSAndreas Gohr            $out .= '</ul>';
2151469199dSAndreas Gohr        }
2161469199dSAndreas Gohr
217*04971eeaSAndreas Gohr        // show about if not already shown
218*04971eeaSAndreas Gohr        if (!$this->getConf('description') && $this->getConf('about')) {
219*04971eeaSAndreas Gohr            $out .= '&nbsp';
220*04971eeaSAndreas Gohr            $out .= $this->showAbout();
221*04971eeaSAndreas Gohr        }
222*04971eeaSAndreas Gohr
2231469199dSAndreas Gohr        $out .= '</div>';
2241469199dSAndreas Gohr
2251469199dSAndreas Gohr        return $out;
2261469199dSAndreas Gohr    }
227af1904f9SAndreas Gohr
22801dd7da9SAndreas Gohr    /**
22901dd7da9SAndreas Gohr     * Create the link or option for a single translation
23001dd7da9SAndreas Gohr     *
231*04971eeaSAndreas Gohr     * @param $lc string      The language code
23201dd7da9SAndreas Gohr     * @param $idpart string  The ID of the translated page
233*04971eeaSAndreas Gohr     * @returns string        The item
23401dd7da9SAndreas Gohr     */
235*04971eeaSAndreas Gohr    function getTransItem($lc, $idpart) {
236c9640767STomasz Tomasik        global $ID;
237c9640767STomasz Tomasik        global $conf;
238c9640767STomasz Tomasik
239*04971eeaSAndreas Gohr        list($link,$lang) = $this->buildTransID($lc,$idpart);
240c9640767STomasz Tomasik        $link = cleanID($link);
241*04971eeaSAndreas Gohr
242*04971eeaSAndreas Gohr
243*04971eeaSAndreas Gohr        // class
244c9640767STomasz Tomasik        if(page_exists($link,'',false)){
245c9640767STomasz Tomasik            $class = 'wikilink1';
246c9640767STomasz Tomasik        }else{
247c9640767STomasz Tomasik            $class = 'wikilink2';
248c9640767STomasz Tomasik        }
249c9640767STomasz Tomasik
250*04971eeaSAndreas Gohr        // local language name
251*04971eeaSAndreas Gohr        if ($this->LN[$lang]){
252*04971eeaSAndreas Gohr            $localname = $this->LN[$lang];
253c9640767STomasz Tomasik        } else{
254*04971eeaSAndreas Gohr            $localname = $lang;
255c9640767STomasz Tomasik        }
256c9640767STomasz Tomasik
257*04971eeaSAndreas Gohr        // current?
258*04971eeaSAndreas Gohr        if($ID == $link){
259*04971eeaSAndreas Gohr            $sel    = ' selected="selected"';
260*04971eeaSAndreas Gohr            $class .= ' cur';
261*04971eeaSAndreas Gohr        }else{
262*04971eeaSAndreas Gohr            $sel    = '';
263*04971eeaSAndreas Gohr        }
264c9640767STomasz Tomasik
265*04971eeaSAndreas Gohr        // flag
266*04971eeaSAndreas Gohr        if(isset($this->opts['flag'])){
267*04971eeaSAndreas Gohr            $flag   = DOKU_BASE.'lib/plugins/translation/flags/'.hsc($lang).'.gif';
268*04971eeaSAndreas Gohr            $style  = ' style="background-image: url(\''.$flag.'\')"';
269*04971eeaSAndreas Gohr            $class .= ' flag';
270*04971eeaSAndreas Gohr        }
271*04971eeaSAndreas Gohr
272*04971eeaSAndreas Gohr        // what to display as name
273*04971eeaSAndreas Gohr        if(isset($this->opts['name'])){
274*04971eeaSAndreas Gohr            $display = hsc($localname);
275*04971eeaSAndreas Gohr            if(isset($this->opts['lc'])) $display .= ' ('.hsc($lang).')';
276*04971eeaSAndreas Gohr        }elseif(isset($this->opts['lc'])){
277*04971eeaSAndreas Gohr            $display = hsc($lang);
278*04971eeaSAndreas Gohr        }else{
279*04971eeaSAndreas Gohr            $display = '&nbsp;';
280*04971eeaSAndreas Gohr        }
281*04971eeaSAndreas Gohr
282*04971eeaSAndreas Gohr        // prepare output
283*04971eeaSAndreas Gohr        $out = '';
284*04971eeaSAndreas Gohr        if($this->getConf('dropdown')){
285*04971eeaSAndreas Gohr            $out .= '<option class="'.$class.'" title="'.hsc($localname).'" value="'.$link.'"'.$sel.$style.'>';
286*04971eeaSAndreas Gohr            $out .= $display;
287*04971eeaSAndreas Gohr            $out .= '</option>';
288*04971eeaSAndreas Gohr        }else{
289c9640767STomasz Tomasik            $out .= '<li><div class="li">';
290*04971eeaSAndreas Gohr            $out .= '<a href='.wl($link).' class="'.$class.'" title="'.hsc($localname).'">';
291*04971eeaSAndreas Gohr            if($flag) $out .= '<img src="'.$flag.'" alt="'.hsc($lang).'" height="11" />';
292*04971eeaSAndreas Gohr            $out .= $display;
293c9640767STomasz Tomasik            $out .= '</a>';
294c9640767STomasz Tomasik            $out .= '</div></li>';
295c9640767STomasz Tomasik        }
296c9640767STomasz Tomasik
297c9640767STomasz Tomasik        return $out;
298c9640767STomasz Tomasik    }
299c9640767STomasz Tomasik
30084877e9bSAndreas Gohr    /**
30184877e9bSAndreas Gohr     * Checks if the current page is a translation of a page
30284877e9bSAndreas Gohr     * in the default language. Displays a notice when it is
30384877e9bSAndreas Gohr     * older than the original page. Tries to lin to a diff
30484877e9bSAndreas Gohr     * with changes on the original since the translation
30584877e9bSAndreas Gohr     */
30684877e9bSAndreas Gohr    function checkage(){
30784877e9bSAndreas Gohr        global $ID;
30884877e9bSAndreas Gohr        global $INFO;
30984877e9bSAndreas Gohr        if(!$this->getConf('checkage')) return;
31084877e9bSAndreas Gohr        if(!$INFO['exists']) return;
31184877e9bSAndreas Gohr        $lng = $this->getLangPart($ID);
31284877e9bSAndreas Gohr        if($lng == $this->defaultlang) return;
313af1904f9SAndreas Gohr
31484877e9bSAndreas Gohr        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
31584877e9bSAndreas Gohr        $idpart = preg_replace($rx,'',$ID);
31684877e9bSAndreas Gohr
31784877e9bSAndreas Gohr        // compare modification times
31884877e9bSAndreas Gohr        list($orig,$name) = $this->buildTransID($this->defaultlang,$idpart);
31984877e9bSAndreas Gohr        $origfn = wikiFN($orig);
32084877e9bSAndreas Gohr        if($INFO['lastmod'] >= @filemtime($origfn) ) return;
32184877e9bSAndreas Gohr
32284877e9bSAndreas Gohr        // get revision from before translation
32384877e9bSAndreas Gohr        $orev = 0;
32484877e9bSAndreas Gohr        $revs = getRevisions($orig,0,100);
32584877e9bSAndreas Gohr        foreach($revs as $rev){
32684877e9bSAndreas Gohr            if($rev < $INFO['lastmod']){
32784877e9bSAndreas Gohr                $orev = $rev;
32884877e9bSAndreas Gohr                break;
32984877e9bSAndreas Gohr            }
33084877e9bSAndreas Gohr        }
33184877e9bSAndreas Gohr
33244552920SAndreas Gohr        // see if the found revision still exists
33344552920SAndreas Gohr        if($orev && !page_exists($orig,$orev)) $orev=0;
33444552920SAndreas Gohr
33584877e9bSAndreas Gohr        // build the message and display it
336dc3fbdb9SOleksiy Zagorskyi        $orig = cleanID($orig);
33784877e9bSAndreas Gohr        $msg = sprintf($this->getLang('outdated'),wl($orig));
33884877e9bSAndreas Gohr        if($orev){
33984877e9bSAndreas Gohr            $msg .= sprintf(' '.$this->getLang('diff'),
34084877e9bSAndreas Gohr                    wl($orig,array('do'=>'diff','rev'=>$orev)));
34184877e9bSAndreas Gohr        }
34200431e1eSAndreas Gohr
34300431e1eSAndreas Gohr        echo '<div class="notify">'.$msg.'</div>';
34484877e9bSAndreas Gohr    }
345af1904f9SAndreas Gohr}
346