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 * @author Guy Brand <gb@isis.u-strasbg.fr> 8 */ 9 10// must be run within Dokuwiki 11if(!defined('DOKU_INC')) die(); 12 13if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 14require_once(DOKU_PLUGIN . 'action.php'); 15 16class action_plugin_translation extends DokuWiki_Action_Plugin { 17 18 /** 19 * for th helper plugin 20 * @var helper_plugin_translation 21 */ 22 var $hlp = null; 23 24 var $locale; 25 26 /** 27 * Constructor. Load helper plugin 28 */ 29 function action_plugin_translation() { 30 $this->hlp =& plugin_load('helper', 'translation'); 31 } 32 33 /** 34 * Registe the events 35 */ 36 function register(&$controller) { 37 // should the lang be applied to UI? 38 $scriptName = basename($_SERVER['PHP_SELF']); 39 if($this->getConf('translateui')) { 40 switch($scriptName) { 41 case 'js.php': 42 $controller->register_hook('INIT_LANG_LOAD', 'BEFORE', $this, 'translation_js'); 43 $controller->register_hook('JS_CACHE_USE', 'BEFORE', $this, 'translation_jscache'); 44 break; 45 46 case 'ajax.php': 47 $controller->register_hook('INIT_LANG_LOAD', 'BEFORE', $this, 'translate_media_manager'); 48 break; 49 50 case 'mediamanager.php': 51 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'setJsCacheKey'); 52 break; 53 54 default: 55 $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'setJsCacheKey'); 56 } 57 } 58 59 if($scriptName !== 'js.php' && $scriptName !== 'ajax.php') { 60 $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'translation_hook'); 61 $controller->register_hook('MEDIAMANAGER_STARTED', 'BEFORE', $this, 'translation_hook'); 62 } 63 64 $controller->register_hook('SEARCH_QUERY_PAGELOOKUP', 'AFTER', $this, 'translation_search'); 65 $controller->register_hook('COMMON_PAGETPL_LOAD', 'AFTER', $this, 'page_template_replacement'); 66 } 67 68 /** 69 * Hook Callback. Make current language available as page template placeholder and handle 70 * original language copying 71 * 72 * @param $event 73 * @param $args 74 */ 75 function page_template_replacement(&$event, $args) { 76 global $ID; 77 78 // load orginal content as template? 79 if($this->getConf('copytrans') && $this->hlp->istranslatable($ID, false)) { 80 // look for existing translations 81 $translations = $this->hlp->getAvailableTranslations($ID); 82 if($translations) { 83 // find original language (might've been provided via parameter or use first translation) 84 $orig = (string) $_REQUEST['fromlang']; 85 if(!$orig) $orig = array_shift(array_keys($translations)); 86 87 // load file 88 $origfile = $translations[$orig]; 89 $event->data['tpl'] = io_readFile(wikiFN($origfile)); 90 91 // prefix with warning 92 $warn = io_readFile($this->localFN('totranslate')); 93 if($warn) $warn .= "\n\n"; 94 $event->data['tpl'] = $warn . $event->data['tpl']; 95 96 // show user a choice of translations if any 97 if(count($translations) > 1) { 98 $links = array(); 99 foreach($translations as $t => $l) { 100 $links[] = '<a href="' . wl($ID, array('do' => 'edit', 'fromlang' => $t)) . '">' . $this->hlp->getLocalName($t) . '</a>'; 101 } 102 103 msg( 104 sprintf( 105 $this->getLang('transloaded'), 106 $this->hlp->getLocalName($orig), 107 join(', ', $links) 108 ) 109 ); 110 } 111 112 } 113 } 114 115 // apply placeholders 116 $event->data['tpl'] = str_replace('@LANG@', $this->hlp->realLC(''), $event->data['tpl']); 117 $event->data['tpl'] = str_replace('@TRANS@', $this->hlp->getLangPart($ID), $event->data['tpl']); 118 } 119 120 /** 121 * Hook Callback. Load correct translation when loading JavaScript 122 * 123 * @param $event 124 * @param $args 125 */ 126 function translation_js(&$event, $args) { 127 global $conf; 128 if(!isset($_GET['lang'])) return; 129 if(!in_array($_GET['lang'], $this->hlp->trans)) return; 130 $lang = $_GET['lang']; 131 $event->data = $lang; 132 $conf['lang'] = $lang; 133 } 134 135 /** 136 * Hook Callback. Pass language code to JavaScript dispatcher 137 * 138 * @param $event 139 * @param $args 140 * @return bool 141 */ 142 function setJsCacheKey(&$event, $args) { 143 if(!isset($this->locale)) return false; 144 $count = count($event->data['script']); 145 for($i = 0; $i < $count; $i++) { 146 if(strpos($event->data['script'][$i]['src'], '/lib/exe/js.php') !== false) { 147 $event->data['script'][$i]['src'] .= '&lang=' . hsc($this->locale); 148 } 149 } 150 151 return false; 152 } 153 154 /** 155 * Hook Callback. Make sure the JavaScript is translation dependent 156 * 157 * @param $event 158 * @param $args 159 */ 160 function translation_jscache(&$event, $args) { 161 if(!isset($_GET['lang'])) return; 162 if(!in_array($_GET['lang'], $this->hlp->trans)) return; 163 164 $lang = $_GET['lang']; 165 // reuse the constructor to reinitialize the cache key 166 $event->data->cache( 167 $event->data->key . $lang, 168 $event->data->ext 169 ); 170 } 171 172 /** 173 * Hook Callback. Translate the AJAX loaded media manager 174 * 175 * @param $event 176 * @param $args 177 */ 178 function translate_media_manager(&$event, $args) { 179 global $conf; 180 if(isset($_REQUEST['ID'])) { 181 $id = getID(); 182 $lc = $this->hlp->getLangPart($id); 183 } elseif(isset($_SESSION[DOKU_COOKIE]['translationlc'])) { 184 $lc = $_SESSION[DOKU_COOKIE]['translationlc']; 185 } else { 186 return; 187 } 188 $conf['lang'] = $lc; 189 $event->data = $lc; 190 } 191 192 /** 193 * Hook Callback. Change the UI language in foreign language namespaces 194 */ 195 function translation_hook(&$event, $args) { 196 global $ID; 197 global $lang; 198 global $conf; 199 global $ACT; 200 // redirect away from start page? 201 if($this->conf['redirectstart'] && $ID == $conf['start'] && $ACT == 'show') { 202 $lc = $this->hlp->getBrowserLang(); 203 if(!$lc) $lc = $conf['lang']; 204 header('Location: ' . wl($lc . ':' . $conf['start'], '', true, '&')); 205 exit; 206 } 207 208 // check if we are in a foreign language namespace 209 $lc = $this->hlp->getLangPart($ID); 210 211 // store language in session (for page related views only) 212 if(in_array($ACT, array('show', 'recent', 'diff', 'edit', 'preview', 'source', 'subscribe'))) { 213 $_SESSION[DOKU_COOKIE]['translationlc'] = $lc; 214 } 215 if(!$lc) $lc = $_SESSION[DOKU_COOKIE]['translationlc']; 216 if(!$lc) return; 217 $this->locale = $lc; 218 219 if(!$this->getConf('translateui')) { 220 return true; 221 } 222 223 if(file_exists(DOKU_INC . 'inc/lang/' . $lc . '/lang.php')) { 224 require(DOKU_INC . 'inc/lang/' . $lc . '/lang.php'); 225 } 226 $conf['lang_before_translation'] = $conf['lang']; //store for later access in syntax plugin 227 $conf['lang'] = $lc; 228 229 return true; 230 } 231 232 /** 233 * Hook Callback. Resort page match results so that results are ordered by translation, having the 234 * default language first 235 */ 236 function translation_search(&$event, $args) { 237 238 if($event->data['has_titles']) { 239 // sort into translation slots 240 $res = array(); 241 foreach($event->result as $r => $t) { 242 $tr = $this->hlp->getLangPart($r); 243 if(!is_array($res["x$tr"])) $res["x$tr"] = array(); 244 $res["x$tr"][] = array($r, $t); 245 } 246 // sort by translations 247 ksort($res); 248 // combine 249 $event->result = array(); 250 foreach($res as $r) { 251 foreach($r as $l) { 252 $event->result[$l[0]] = $l[1]; 253 } 254 } 255 } else { 256 # legacy support for old DokuWiki hooks 257 258 // sort into translation slots 259 $res = array(); 260 foreach($event->result as $r) { 261 $tr = $this->hlp->getLangPart($r); 262 if(!is_array($res["x$tr"])) $res["x$tr"] = array(); 263 $res["x$tr"][] = $r; 264 } 265 // sort by translations 266 ksort($res); 267 // combine 268 $event->result = array(); 269 foreach($res as $r) { 270 $event->result = array_merge($event->result, $r); 271 } 272 } 273 } 274 275} 276 277//Setup VIM: ex: et ts=4 : 278