10a7415d3SAndreas Gohr<?php 20a7415d3SAndreas Gohr/** 3af1904f9SAndreas Gohr * Translation Plugin: Simple multilanguage plugin 40a7415d3SAndreas Gohr * 50a7415d3SAndreas Gohr * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 60a7415d3SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 70a7415d3SAndreas Gohr * @author Guy Brand <gb@isis.u-strasbg.fr> 80a7415d3SAndreas Gohr */ 90a7415d3SAndreas Gohr 100a7415d3SAndreas Gohr// must be run within Dokuwiki 110a7415d3SAndreas Gohrif(!defined('DOKU_INC')) die(); 120a7415d3SAndreas Gohr 130a7415d3SAndreas Gohrif(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 140a7415d3SAndreas Gohrrequire_once(DOKU_PLUGIN . 'action.php'); 150a7415d3SAndreas Gohr 160a7415d3SAndreas Gohrclass action_plugin_translation extends DokuWiki_Action_Plugin { 170a7415d3SAndreas Gohr 180a7415d3SAndreas Gohr /** 19af1904f9SAndreas Gohr * for th helper plugin 20cabcc95dSDominik Eckelmann * @var helper_plugin_translation 21af1904f9SAndreas Gohr */ 22af1904f9SAndreas Gohr var $hlp = null; 23af1904f9SAndreas Gohr 24ec6cbde6SDominik Eckelmann var $locale; 25ec6cbde6SDominik Eckelmann 26af1904f9SAndreas Gohr /** 27af1904f9SAndreas Gohr * Constructor. Load helper plugin 28af1904f9SAndreas Gohr */ 29af1904f9SAndreas Gohr function action_plugin_translation() { 30af1904f9SAndreas Gohr $this->hlp =& plugin_load('helper', 'translation'); 31af1904f9SAndreas Gohr } 32af1904f9SAndreas Gohr 33af1904f9SAndreas Gohr /** 340a7415d3SAndreas Gohr * Registe the events 350a7415d3SAndreas Gohr */ 360a7415d3SAndreas Gohr function register(&$controller) { 370a7415d3SAndreas Gohr // should the lang be applied to UI? 38ec6cbde6SDominik Eckelmann $scriptName = basename($_SERVER['PHP_SELF']); 3934591120SDominik Eckelmann if($this->getConf('translateui')) { 40ec6cbde6SDominik Eckelmann switch($scriptName) { 41ec6cbde6SDominik Eckelmann case 'js.php': 42ec6cbde6SDominik Eckelmann $controller->register_hook('INIT_LANG_LOAD', 'BEFORE', $this, 'translation_js'); 43db7c51b4SAndreas Gohr $controller->register_hook('JS_CACHE_USE', 'BEFORE', $this, 'translation_jscache'); 44ec6cbde6SDominik Eckelmann break; 45ec6cbde6SDominik Eckelmann 46ec6cbde6SDominik Eckelmann case 'ajax.php': 47ec6cbde6SDominik Eckelmann $controller->register_hook('INIT_LANG_LOAD', 'BEFORE', $this, 'translate_media_manager'); 48ec6cbde6SDominik Eckelmann break; 49ec6cbde6SDominik Eckelmann 50ec6cbde6SDominik Eckelmann case 'mediamanager.php': 51ec6cbde6SDominik Eckelmann $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'setJsCacheKey'); 52ec6cbde6SDominik Eckelmann break; 53ec6cbde6SDominik Eckelmann 54ec6cbde6SDominik Eckelmann default: 55ec6cbde6SDominik Eckelmann $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'setJsCacheKey'); 56ec6cbde6SDominik Eckelmann } 570a7415d3SAndreas Gohr } 5834591120SDominik Eckelmann 5934591120SDominik Eckelmann if($scriptName !== 'js.php' && $scriptName !== 'ajax.php') { 6034591120SDominik Eckelmann $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'translation_hook'); 6134591120SDominik Eckelmann $controller->register_hook('MEDIAMANAGER_STARTED', 'BEFORE', $this, 'translation_hook'); 6234591120SDominik Eckelmann } 6334591120SDominik Eckelmann 64af1904f9SAndreas Gohr $controller->register_hook('SEARCH_QUERY_PAGELOOKUP', 'AFTER', $this, 'translation_search'); 65cabcc95dSDominik Eckelmann $controller->register_hook('COMMON_PAGETPL_LOAD', 'AFTER', $this, 'page_template_replacement'); 66cabcc95dSDominik Eckelmann } 67cabcc95dSDominik Eckelmann 68bbe70520SAndreas Gohr /** 69bbe70520SAndreas Gohr * Hook Callback. Make current language available as page template placeholder and handle 70bbe70520SAndreas Gohr * original language copying 71bbe70520SAndreas Gohr * 72bbe70520SAndreas Gohr * @param $event 73bbe70520SAndreas Gohr * @param $args 74bbe70520SAndreas Gohr */ 75cabcc95dSDominik Eckelmann function page_template_replacement(&$event, $args) { 76cabcc95dSDominik Eckelmann global $ID; 77bbe70520SAndreas Gohr 78bbe70520SAndreas Gohr // load orginal content as template? 79bbe70520SAndreas Gohr if($this->getConf('copytrans') && $this->hlp->istranslatable($ID, false)) { 80bbe70520SAndreas Gohr // look for existing translations 81bbe70520SAndreas Gohr $translations = $this->hlp->getAvailableTranslations($ID); 82bbe70520SAndreas Gohr if($translations) { 83bbe70520SAndreas Gohr // find original language (might've been provided via parameter or use first translation) 84bbe70520SAndreas Gohr $orig = (string) $_REQUEST['fromlang']; 85bbe70520SAndreas Gohr if(!$orig) $orig = array_shift(array_keys($translations)); 86bbe70520SAndreas Gohr 87bbe70520SAndreas Gohr // load file 88bbe70520SAndreas Gohr $origfile = $translations[$orig]; 89bbe70520SAndreas Gohr $event->data['tpl'] = io_readFile(wikiFN($origfile)); 90bbe70520SAndreas Gohr 91bbe70520SAndreas Gohr // prefix with warning 92bbe70520SAndreas Gohr $warn = io_readFile($this->localFN('totranslate')); 93bbe70520SAndreas Gohr if($warn) $warn .= "\n\n"; 94bbe70520SAndreas Gohr $event->data['tpl'] = $warn . $event->data['tpl']; 95bbe70520SAndreas Gohr 96bbe70520SAndreas Gohr // show user a choice of translations if any 97bbe70520SAndreas Gohr if(count($translations) > 1) { 98bbe70520SAndreas Gohr $links = array(); 99bbe70520SAndreas Gohr foreach($translations as $t => $l) { 100a198a703SAndreas Gohr $links[] = '<a href="' . wl($ID, array('do' => 'edit', 'fromlang' => $t)) . '">' . $this->hlp->getLocalName($t) . '</a>'; 101bbe70520SAndreas Gohr } 102bbe70520SAndreas Gohr 103*5fd0d0d1SAndreas Gohr msg( 104*5fd0d0d1SAndreas Gohr sprintf( 105bbe70520SAndreas Gohr $this->getLang('transloaded'), 106bbe70520SAndreas Gohr $this->hlp->getLocalName($orig), 107bbe70520SAndreas Gohr join(', ', $links) 108bbe70520SAndreas Gohr ) 109bbe70520SAndreas Gohr ); 110bbe70520SAndreas Gohr } 111bbe70520SAndreas Gohr 112bbe70520SAndreas Gohr } 113bbe70520SAndreas Gohr } 114bbe70520SAndreas Gohr 115bbe70520SAndreas Gohr // apply placeholders 116cabcc95dSDominik Eckelmann $event->data['tpl'] = str_replace('@LANG@', $this->hlp->realLC(''), $event->data['tpl']); 117cabcc95dSDominik Eckelmann $event->data['tpl'] = str_replace('@TRANS@', $this->hlp->getLangPart($ID), $event->data['tpl']); 1180a7415d3SAndreas Gohr } 1190a7415d3SAndreas Gohr 120bbe70520SAndreas Gohr /** 121bbe70520SAndreas Gohr * Hook Callback. Load correct translation when loading JavaScript 122bbe70520SAndreas Gohr * 123bbe70520SAndreas Gohr * @param $event 124bbe70520SAndreas Gohr * @param $args 125bbe70520SAndreas Gohr */ 126bbe70520SAndreas Gohr function translation_js(&$event, $args) { 127bbe70520SAndreas Gohr global $conf; 128bbe70520SAndreas Gohr if(!isset($_GET['lang'])) return; 129bbe70520SAndreas Gohr if(!in_array($_GET['lang'], $this->hlp->trans)) return; 130bbe70520SAndreas Gohr $lang = $_GET['lang']; 131bbe70520SAndreas Gohr $event->data = $lang; 132bbe70520SAndreas Gohr $conf['lang'] = $lang; 133bbe70520SAndreas Gohr } 134bbe70520SAndreas Gohr 135bbe70520SAndreas Gohr /** 136bbe70520SAndreas Gohr * Hook Callback. Pass language code to JavaScript dispatcher 137bbe70520SAndreas Gohr * 138bbe70520SAndreas Gohr * @param $event 139bbe70520SAndreas Gohr * @param $args 140bbe70520SAndreas Gohr * @return bool 141bbe70520SAndreas Gohr */ 142ec6cbde6SDominik Eckelmann function setJsCacheKey(&$event, $args) { 143ec6cbde6SDominik Eckelmann if(!isset($this->locale)) return false; 144ec6cbde6SDominik Eckelmann $count = count($event->data['script']); 145ec6cbde6SDominik Eckelmann for($i = 0; $i < $count; $i++) { 146ec6cbde6SDominik Eckelmann if(strpos($event->data['script'][$i]['src'], '/lib/exe/js.php') !== false) { 147db7c51b4SAndreas Gohr $event->data['script'][$i]['src'] .= '&lang=' . hsc($this->locale); 148ec6cbde6SDominik Eckelmann } 149ec6cbde6SDominik Eckelmann } 150ec6cbde6SDominik Eckelmann 151ec6cbde6SDominik Eckelmann return false; 152ec6cbde6SDominik Eckelmann } 153ec6cbde6SDominik Eckelmann 154bbe70520SAndreas Gohr /** 155bbe70520SAndreas Gohr * Hook Callback. Make sure the JavaScript is translation dependent 156bbe70520SAndreas Gohr * 157bbe70520SAndreas Gohr * @param $event 158bbe70520SAndreas Gohr * @param $args 159bbe70520SAndreas Gohr */ 160db7c51b4SAndreas Gohr function translation_jscache(&$event, $args) { 161db7c51b4SAndreas Gohr if(!isset($_GET['lang'])) return; 162db7c51b4SAndreas Gohr if(!in_array($_GET['lang'], $this->hlp->trans)) return; 163db7c51b4SAndreas Gohr 164db7c51b4SAndreas Gohr $lang = $_GET['lang']; 165db7c51b4SAndreas Gohr // reuse the constructor to reinitialize the cache key 166db7c51b4SAndreas Gohr $event->data->cache( 167db7c51b4SAndreas Gohr $event->data->key . $lang, 168db7c51b4SAndreas Gohr $event->data->ext 169db7c51b4SAndreas Gohr ); 170ec6cbde6SDominik Eckelmann } 171ec6cbde6SDominik Eckelmann 172bbe70520SAndreas Gohr /** 173bbe70520SAndreas Gohr * Hook Callback. Translate the AJAX loaded media manager 174bbe70520SAndreas Gohr * 175bbe70520SAndreas Gohr * @param $event 176bbe70520SAndreas Gohr * @param $args 177bbe70520SAndreas Gohr */ 178ec6cbde6SDominik Eckelmann function translate_media_manager(&$event, $args) { 179ec6cbde6SDominik Eckelmann global $conf; 180ec6cbde6SDominik Eckelmann if(isset($_REQUEST['ID'])) { 181ec6cbde6SDominik Eckelmann $id = getID(); 182ec6cbde6SDominik Eckelmann $lc = $this->hlp->getLangPart($id); 183ec6cbde6SDominik Eckelmann } elseif(isset($_SESSION[DOKU_COOKIE]['translationlc'])) { 184ec6cbde6SDominik Eckelmann $lc = $_SESSION[DOKU_COOKIE]['translationlc']; 185ec6cbde6SDominik Eckelmann } else { 186db7c51b4SAndreas Gohr return; 187ec6cbde6SDominik Eckelmann } 188ec6cbde6SDominik Eckelmann $conf['lang'] = $lc; 189ec6cbde6SDominik Eckelmann $event->data = $lc; 190ec6cbde6SDominik Eckelmann } 191ec6cbde6SDominik Eckelmann 1920a7415d3SAndreas Gohr /** 193bbe70520SAndreas Gohr * Hook Callback. Change the UI language in foreign language namespaces 1940a7415d3SAndreas Gohr */ 1950a7415d3SAndreas Gohr function translation_hook(&$event, $args) { 1960a7415d3SAndreas Gohr global $ID; 1970a7415d3SAndreas Gohr global $lang; 1980a7415d3SAndreas Gohr global $conf; 1997053cd66SAndreas Gohr global $ACT; 2007053cd66SAndreas Gohr // redirect away from start page? 2017053cd66SAndreas Gohr if($this->conf['redirectstart'] && $ID == $conf['start'] && $ACT == 'show') { 2027053cd66SAndreas Gohr $lc = $this->hlp->getBrowserLang(); 2037053cd66SAndreas Gohr if(!$lc) $lc = $conf['lang']; 2047053cd66SAndreas Gohr header('Location: ' . wl($lc . ':' . $conf['start'], '', true, '&')); 2057053cd66SAndreas Gohr exit; 2067053cd66SAndreas Gohr } 2070a7415d3SAndreas Gohr 2080a7415d3SAndreas Gohr // check if we are in a foreign language namespace 209af1904f9SAndreas Gohr $lc = $this->hlp->getLangPart($ID); 210a526927fSAndreas Gohr 211f2279247SAndreas Gohr // store language in session (for page related views only) 212f2279247SAndreas Gohr if(in_array($ACT, array('show', 'recent', 'diff', 'edit', 'preview', 'source', 'subscribe'))) { 213f2279247SAndreas Gohr $_SESSION[DOKU_COOKIE]['translationlc'] = $lc; 214f2279247SAndreas Gohr } 215a526927fSAndreas Gohr if(!$lc) $lc = $_SESSION[DOKU_COOKIE]['translationlc']; 216a526927fSAndreas Gohr if(!$lc) return; 21734591120SDominik Eckelmann $this->locale = $lc; 21834591120SDominik Eckelmann 21934591120SDominik Eckelmann if(!$this->getConf('translateui')) { 22034591120SDominik Eckelmann return true; 22134591120SDominik Eckelmann } 2220a7415d3SAndreas Gohr 2230a7415d3SAndreas Gohr if(file_exists(DOKU_INC . 'inc/lang/' . $lc . '/lang.php')) { 2240a7415d3SAndreas Gohr require(DOKU_INC . 'inc/lang/' . $lc . '/lang.php'); 2250a7415d3SAndreas Gohr } 2260a7415d3SAndreas Gohr $conf['lang_before_translation'] = $conf['lang']; //store for later access in syntax plugin 2270a7415d3SAndreas Gohr $conf['lang'] = $lc; 2280a7415d3SAndreas Gohr 2290a7415d3SAndreas Gohr return true; 2300a7415d3SAndreas Gohr } 231af1904f9SAndreas Gohr 232af1904f9SAndreas Gohr /** 233bbe70520SAndreas Gohr * Hook Callback. Resort page match results so that results are ordered by translation, having the 234af1904f9SAndreas Gohr * default language first 235af1904f9SAndreas Gohr */ 236af1904f9SAndreas Gohr function translation_search(&$event, $args) { 237d75e50bcSAndreas Gohr 238d75e50bcSAndreas Gohr if($event->data['has_titles']) { 239d75e50bcSAndreas Gohr // sort into translation slots 240d75e50bcSAndreas Gohr $res = array(); 241d75e50bcSAndreas Gohr foreach($event->result as $r => $t) { 242d75e50bcSAndreas Gohr $tr = $this->hlp->getLangPart($r); 243d75e50bcSAndreas Gohr if(!is_array($res["x$tr"])) $res["x$tr"] = array(); 244d75e50bcSAndreas Gohr $res["x$tr"][] = array($r, $t); 245d75e50bcSAndreas Gohr } 246d75e50bcSAndreas Gohr // sort by translations 247d75e50bcSAndreas Gohr ksort($res); 248d75e50bcSAndreas Gohr // combine 249d75e50bcSAndreas Gohr $event->result = array(); 250d75e50bcSAndreas Gohr foreach($res as $r) { 251d75e50bcSAndreas Gohr foreach($r as $l) { 252d75e50bcSAndreas Gohr $event->result[$l[0]] = $l[1]; 253d75e50bcSAndreas Gohr } 254d75e50bcSAndreas Gohr } 255d75e50bcSAndreas Gohr } else { 256d75e50bcSAndreas Gohr # legacy support for old DokuWiki hooks 257d75e50bcSAndreas Gohr 258af1904f9SAndreas Gohr // sort into translation slots 259af1904f9SAndreas Gohr $res = array(); 260af1904f9SAndreas Gohr foreach($event->result as $r) { 261af1904f9SAndreas Gohr $tr = $this->hlp->getLangPart($r); 262af1904f9SAndreas Gohr if(!is_array($res["x$tr"])) $res["x$tr"] = array(); 263af1904f9SAndreas Gohr $res["x$tr"][] = $r; 264af1904f9SAndreas Gohr } 265af1904f9SAndreas Gohr // sort by translations 266af1904f9SAndreas Gohr ksort($res); 267af1904f9SAndreas Gohr // combine 268af1904f9SAndreas Gohr $event->result = array(); 269af1904f9SAndreas Gohr foreach($res as $r) { 270af1904f9SAndreas Gohr $event->result = array_merge($event->result, $r); 271af1904f9SAndreas Gohr } 272af1904f9SAndreas Gohr } 273d75e50bcSAndreas Gohr } 274af1904f9SAndreas Gohr 2750a7415d3SAndreas Gohr} 2760a7415d3SAndreas Gohr 277ec6cbde6SDominik Eckelmann//Setup VIM: ex: et ts=4 : 278