xref: /plugin/autotranslation/helper.php (revision 3c97db4748ab90356a4ed9b622419ba3fc4b172e)
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
17    /**
18     * Initialize
19     */
20    function helper_plugin_translation(){
21        global $conf;
22        global $ID;
23        global $JSINFO;
24
25        require_once(DOKU_INC.'inc/pageutils.php');
26        require_once(DOKU_INC.'inc/utf8.php');
27
28        // load wanted translation into array
29        $this->trans = strtolower(str_replace(',',' ',$this->getConf('translations')));
30        $this->trans = array_unique(array_filter(explode(' ',$this->trans)));
31        sort($this->trans);
32
33        // get default translation
34        if(!$conf['lang_before_translation']){
35          $dfl = $conf['lang'];
36        } else {
37          $dfl = $conf['lang_before_translation'];
38        }
39        if(in_array($dfl,$this->trans)){
40            $this->defaultlang = $dfl;
41        }else{
42            $this->defaultlang = '';
43            array_unshift($this->trans,'');
44        }
45
46
47        $this->tns = $this->setupTNS($ID);
48        if ( $this->tns === false ) { return false; }
49        $JSINFO['conf']['lang'] = $dfl;
50    }
51
52
53	// Inner function for sorting
54	private function lensort($a,$b){
55    	return strlen($b)-strlen($a);
56	}
57
58	function setupTNS($ID) {
59
60		if ( !empty( $this->tns) ) { return $this->tns; }
61		if ( empty($ID) ) { $ID = getID(); }
62
63		$tnsA = explode(' ', $this->getConf('translationns'));
64		if ( empty($tnsA) ) return ''; // there is just this one - and translation is active.
65
66		usort($tnsA,array($this, 'lensort') );
67		foreach ( $tnsA as $tns ) {
68			$tns = cleanID(trim($tns));
69        	if(substr($tns, -1) != ':') { $tns .= ':'; }
70			if(strpos($ID,$tns) === false) continue;
71
72			return $tns;
73		}
74
75		return false;
76    }
77
78    /**
79     * Check if the given ID is a translation and return the language code.
80     */
81    function getLangPart($id){
82        $rx = '/^'.$this->tns.'('.join('|',$this->trans).'):/';
83        if(preg_match($rx,$id,$match)){
84            return $match[1];
85        }
86        return '';
87    }
88
89    /**
90     * Returns the browser language if it matches with one of the configured
91     * languages
92     */
93    function getBrowserLang(){
94        $rx = '/(^|,|:|;|-)('.join('|',$this->trans).')($|,|:|;|-)/i';
95        if(preg_match($rx,$_SERVER['HTTP_ACCEPT_LANGUAGE'],$match)){
96            return strtolower($match[2]);
97        }
98        return false;
99    }
100
101
102    /**
103     * Returns the ID and name to the wanted translation, empty
104     * $lng is default lang
105     */
106    function buildTransID($lng,$idpart){
107        global $conf;
108        global $saved_conf;
109        if($lng){
110            $link = ':'.$this->tns.$lng.':'.$idpart;
111            $name = $lng;
112        }else{
113            $link = ':'.$this->tns.$idpart;
114            if(!$conf['lang_before_translation']){
115              $name = $conf['lang'];
116            } else {
117              $name = $conf['lang_before_translation'];
118            }
119        }
120        return array($link,$name);
121    }
122
123    /**
124     * Check if current ID should be translated and any GUI
125     * should be shown
126     */
127    function istranslatable($id,$checkact=true){
128        global $ACT;
129
130        if($checkact && $ACT != 'show') return false;
131        if($this->tns && strpos($id,$this->tns) !== 0) return false;
132        $skiptrans = trim($this->getConf('skiptrans'));
133        if($skiptrans &&  preg_match('/'.$skiptrans.'/ui',':'.$id)) return false;
134        $meta = p_get_metadata($id);
135        if($meta['plugin']['translation']['notrans']) return false;
136
137        return true;
138    }
139
140    /**
141     * Displays the available and configured translations. Needs to be placed in the template.
142     */
143    function showTranslations(){
144        global $ID;
145        global $conf;
146        global $INFO;
147
148        $this->tns = $this->setupTNS($ID);
149        if(!$this->istranslatable($ID)) return;
150        $hasTranslation = false;
151
152        $this->checkage();
153
154        $LN = confToHash(dirname(__FILE__).'/lang/langnames.txt');
155
156        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
157        $idpart = preg_replace($rx,'',$ID);
158
159        $out  = '<div class="plugin_translation">';
160        $out .= '<span>'.$this->getLang('translations');
161        if($this->getConf('about')){
162            $out .= '<sup>'.html_wikilink($this->getConf('about'),'?').'</sup>';
163        }
164        $out .= ':</span> ';
165
166        if($this->getConf('dropdown')){ // use dropdown
167            if($INFO['exists']){
168                $class = 'wikilink1';
169            }else{
170                $class = 'wikilink2';
171            }
172            $out .= '<form action="'.wl().'" id="translation__dropdown">';
173            $out .= '<select name="id" class="'.$class.'">';
174            foreach($this->trans as $t){
175                list($link,$name) = $this->buildTransID($t,$idpart);
176                $link = cleanID($link);
177
178                if ( auth_quickaclcheck($link) < AUTH_READ ) { continue; }
179            	if ( !$hasTranslation && $t != $conf['lang'] && $t != $conf['lang_before_translation'] ) { $hasTranslation = true; }
180
181            	if($ID == $link){
182                    $sel = ' selected="selected"';
183                }else{
184                    $sel = '';
185                }
186                if(page_exists($link,'',false)){
187                    $class = 'wikilink1';
188                }else{
189                    $class = 'wikilink2';
190                }
191                $out .= '<option value="'.$link.'"'.$sel.' class="'.$class.'" title="'.$LN[$name].'">'.hsc($name).'</option>';
192            }
193            $out .= '</select>';
194            $out .= '<input name="go" type="submit" value="&rarr;" />';
195            $out .= '</form>';
196        }else{ // use list
197            $out .= '<ul>';
198            foreach($this->trans as $t){
199                list($link,$name) = $this->buildTransID($t,$idpart);
200
201                $link = cleanID($link);
202
203                if ( auth_quickaclcheck($link) < AUTH_READ ) { continue; }
204            	if ( !$hasTranslation && !empty($t) ) { $hasTranslation = true; }
205
206                if(page_exists($link,'',false)){
207                    $class = 'wikilink1';
208                }else{
209                    $class = 'wikilink2';
210                }
211
212                $out .= '  <li><div class="li"><a href="'.wl($link, 's=translation_true').'" class="'.$class.'" title="'.$LN[$name].'">'.hsc($name).'</a></div></li>';
213            }
214            $out .= '</ul>';
215        }
216
217        $out .= '</div>';
218
219        return $hasTranslation ? $out : '';
220    }
221
222    /**
223     * Checks if the current page is a translation of a page
224     * in the default language. Displays a notice when it is
225     * older than the original page. Tries to lin to a diff
226     * with changes on the original since the translation
227     */
228    function checkage(){
229        global $ID;
230        global $INFO;
231        if(!$this->getConf('checkage')) return;
232        if(!$INFO['exists']) return;
233        $lng = $this->getLangPart($ID);
234        if($lng == $this->defaultlang) return;
235
236        $rx = '/^'.$this->tns.'(('.join('|',$this->trans).'):)?/';
237        $idpart = preg_replace($rx,'',$ID);
238
239        // compare modification times
240        list($orig,$name) = $this->buildTransID($this->defaultlang,$idpart);
241        $origfn = wikiFN($orig);
242        if($INFO['lastmod'] >= @filemtime($origfn) ) return;
243
244        // get revision from before translation
245        $orev = 0;
246        $revs = getRevisions($orig,0,100);
247        foreach($revs as $rev){
248            if($rev < $INFO['lastmod']){
249                $orev = $rev;
250                break;
251            }
252        }
253
254        // see if the found revision still exists
255        if($orev && !page_exists($orig,$orev)) $orev=0;
256
257        // build the message and display it
258        $msg = sprintf($this->getLang('outdated'),wl($orig));
259        if($orev){
260            $msg .= sprintf(' '.$this->getLang('diff'),
261                    wl($orig,array('do'=>'diff','rev'=>$orev)));
262        }
263
264        echo '<div class="notify">'.$msg.'</div>';
265    }
266}
267