1<?php
2/**
3 * i-net Download Plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     i-net software <tools@inetsoftware.de>
7 * @author     Gerry Weissbach <gweissbach@inetsoftware.de>
8 */
9
10/*
11 * delete from tblTranslation Where Value like '%\?\?\?%' and Lang not in ('en', 'de', 'es');
12 * DROP TABLE IF EXISTS tblTranslation_old;
13 * create table tblTranslation2 like tblTranslation;
14 * INSERT INTO tblTranslation2 (KeyID, Lang, Date, Value, User) SELECT KeyID, Lang, MAX(Date), Value, User FROM tblTranslation GROUP BY Value, Lang, KeyID, User;
15 * RENAME TABLE  tblTranslation TO  tblTranslation_old;
16 * RENAME TABLE  tblTranslation2 TO  tblTranslation;
17 */
18
19// must be run within Dokuwiki
20if (!defined('DOKU_INC')) die();
21if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC.'lib/plugins/');
22
23class helper_plugin_translator extends DokuWiki_Plugin { // DokuWiki_Helper_Plugin
24
25    var $database = null;
26    var $checkedOK = null;
27    var $pageWordLenIdx = null;
28    var $revertableUpload = array();
29
30    var $dataBaseStruct = array	(
31									"tblCategory" =>	array(	'statement' => 	"CREATE TABLE `tblCategory` (
32																				`CategoryID` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY,
33																				`Name` VARCHAR( 255 ) NOT NULL ,
34																				`FileName` VARCHAR( 255 ) NOT NULL
35																				) CHARACTER SET utf8 COLLATE utf8_unicode_ci;",
36																'fields' =>		array('CategoryID', 'Name', 'FileName')
37    ),
38									"tblMasterKey" => 	array(	'statement' =>	"CREATE TABLE `tblMasterKey` (
39																				`KeyID` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
40																				`ResourceKey` VARCHAR( 255 ) NOT NULL ,
41																				`Value` TEXT NOT NULL ,
42																				`MD5KeyVal` VARCHAR( 255 ) NOT NULL ,
43																				UNIQUE ( `Md5KeyVal` )
44																				) CHARACTER SET utf8 COLLATE utf8_unicode_ci;",
45																'fields' => 	array('KeyID', 'ResourceKey', 'Value', 'MD5KeyVal')
46    ),
47									"tblMaster" => 		array(	'statement' =>	"CREATE TABLE `tblMaster` (
48																				`KeyID` INT( 11 ) NOT NULL,
49																				`CategoryID` INT( 11 ) NOT NULL,
50																				`Version` VARCHAR( 255 ) NOT NULL ,
51																				PRIMARY KEY ( `KeyID`, `CategoryID`, `Version` )
52																				) CHARACTER SET utf8 COLLATE utf8_unicode_ci;",
53																'fields' => 	array('KeyID', 'CategoryID', 'Version')
54    ),
55									"tblTranslation" =>	array(	'statement' =>	"CREATE TABLE `tblTranslation` (
56																				`KeyID` VARCHAR( 255 ) NOT NULL ,
57																				`Lang` VARCHAR( 10 ) NOT NULL ,
58																				`Date` DATETIME NOT NULL ,
59																				`Value` TEXT NOT NULL ,
60																				`User` VARCHAR( 255 ) NOT NULL ,
61																				PRIMARY KEY ( `KeyID` , `Lang` , `Date` )
62																				) CHARACTER SET utf8 COLLATE utf8_unicode_ci;",
63																'fields' => 	array('KeyID', 'Lang', 'Value', 'User', 'Date')
64    ),
65									"tblUserRights" =>	array(	'statement' =>	"CREATE TABLE `tblUserRights` (
66																				`User` VARCHAR( 255 ) NOT NULL ,
67																				`Lang` VARCHAR( 255 ) NOT NULL ,
68																				PRIMARY KEY ( `User` )
69																				) CHARACTER SET utf8 COLLATE utf8_unicode_ci;",
70																'fields' => 	array('User', 'Lang')
71    ),
72    );
73
74    function getInfo(){
75        return array_merge(confToHash(dirname(__FILE__).'/info.txt'), array(
76				'name' => 'Translator - Helper',
77        ));
78    }
79
80    function getMethods() {
81        $result = array();
82        return $result;
83    }
84
85    function checkDatabase() {
86
87        if ( $this->init_database() === false ) {
88            print "Cannot init.";
89            return false;
90        }
91
92        if ( empty($this->database) ) {
93            print $this->lang['nodatabase'];
94            return false;
95        }
96
97        if ( !is_null($this->checkedOK) ) { return $this->checkedOK; }
98        $this->checkedOK = $this->currentVersionChecked();
99        if ( $this->checkedOK ) { return $this->checkedOK; }
100
101        foreach ($this->dataBaseStruct as $tableName => $sqlStatement ) {
102
103            $this->database->query("SHOW TABLES LIKE \"$tableName\";");
104            //$this->database->execute($tableName);
105            $allGood = false;
106
107            if ( $this->database->num_rows() != 1 ) {
108                msg("Creating table '$tableName'", 0);
109                $this->database->prepare($sqlStatement['statement']);
110                $this->database->execute();
111                $allGood = true;
112            } else {
113                // Check Log
114                $table = $this->database->databaseConnection->escape_string($tableName);
115                $this->database->prepare("SHOW COLUMNS FROM `$table`");
116                $this->database->execute();
117
118                if ( $this->database->num_rows() >= count($sqlStatement['fields']) ) {
119
120                    $allGood = true;
121                    $data = array(); $this->database->bind_assoc($data);
122                    while ( $this->database->fetch() ) {
123                        if ( !in_array($data['Field'], $sqlStatement['fields']) ) {
124                            msg("Field missing in '$tableName': '{$data['Field']}'", -1);
125                            $allGood = false;
126                            break;
127                        }
128                    }
129                }
130            }
131        }
132
133        $this->checkedOK = $allGood;
134        if ( $allGood ) {
135            $this->setCurrentVersionChecked();
136        }
137
138        return $allGood;
139    }
140
141
142    function init_database() {
143
144        if ( empty($this->database) ) {
145            if ( !$this->database =& plugin_load('helper', 'databaseconnector', true) ) { return false;}
146            $this->dbType = $dbType;
147            $this->database->setType($this->getConf('DBType'));
148            if ( $this->database->connect($this->getConf('DBName'), $this->getConf('DBUserName'), $this->getConf('DBUserPassword'), $this->getConf('DBHostName')) ) {
149                return true;
150            }
151            return false;
152        }
153    }
154
155    function close_database() {
156
157        if ( !empty($this->database) ) {
158            $this->database->close();
159            $this->database = null;
160        }
161    }
162
163    function _hashKey($key, $value) {
164        return md5($key . $value);
165    }
166
167    /*
168     * Create Master Key / Value Entries
169     */
170    function _createMasterTableEntry($translation, $categoryID, $version, &$finalStatus) {
171
172        foreach ( $translation as $key => $value) {
173
174            $KeyID = null;
175            $HASHKEY = $this->_hashKey($key, $value);
176
177            // Check if Key => Value is in tblMasterKeys
178            $this->database->prepare("SELECT KeyID FROM tblMasterKey WHERE MD5KeyVal=?;");
179            $this->database->execute($HASHKEY);
180
181            if ( $this->database->num_rows() == 0 ) {
182
183                // Key is not in DB ... is there a Key with another value for the current Category? Order DESC by Version
184                $this->database->prepare("SELECT tblMasterKey.KeyID FROM tblMaster LEFT JOIN tblMasterKey ON tblMaster.KeyID=tblMasterKey.KeyID WHERE ResourceKey=? AND CategoryID=? ORDER BY Version DESC;");
185                $this->database->execute($key, $categoryID);
186                if ( $this->database->num_rows() > 0 ) {
187                    $data = array(); $this->database->bind_assoc($data); $this->database->fetch();
188                    $KeyID = $data['KeyID'];
189
190                    // Update Database
191                    $this->database->prepare("UPDATE tblMasterKey SET Value=?, Md5KeyVal=? WHERE KeyID=?;");
192                    $this->database->execute($value, $HASHKEY, $KeyID);
193                } else {
194                    // The Key is not in the Database, so add it
195                    $this->database->prepare("INSERT INTO tblMasterKey (ResourceKey, Value, Md5KeyVal) VALUES(?, ?, ?);");
196                    $this->database->execute($key, $value, $HASHKEY);
197                    $KeyID = $this->database->insert_id();
198                }
199            } else {
200                // Fetch inserted Key ID
201                $data = array(); $this->database->bind_assoc($data); $this->database->fetch();
202                $KeyID = $data['KeyID'];
203
204                // If exists with same Version Return
205                $this->database->prepare("SELECT KeyID FROM tblMaster WHERE KeyID=? AND CategoryID=? AND Version=?;");
206                $this->database->execute($KeyID, $categoryID, $version);
207                if ( $this->database->num_rows() > 0 ) {
208                    $finalStatus['KeysMatchingExisting']++;
209                    continue;
210                }
211            }
212
213            // Add KeyID to tblMaster
214            $this->database->prepare("INSERT INTO tblMaster (KeyID, CategoryID, Version) VALUES(?, ?, ?);");
215            $this->database->execute($KeyID, $categoryID, $version);
216            continue;
217        }
218    }
219
220    /*
221     * get Category ID via Name
222     */
223    function _getCategoryFromName($categoryName) {
224
225        $CATEGORIES = $this->_getCategories($categoryName);
226        if ( empty($CATEGORIES[$categoryName]) ) {
227            msg($this->_messageReplacer('CategoryNotFound', $categoryName), -1);
228            return false;
229        }
230
231        return array( $CATEGORIES[$categoryName]['CategoryID'], str_replace('[LANG]', '(.*?)', $CATEGORIES[$categoryName]['FileName']));
232    }
233
234    /*
235     * get Categories
236     */
237    function _getCategories($categoryName=null, $isID=false) {
238
239        $additional = ''; $execute = array(); $return = array();
240        if ( !empty($categoryName) ) {
241            if ( $isID ) {
242                $additional .= "WHERE CategoryID=?";
243            } else {
244                $additional .= "WHERE Name=?";
245            }
246
247            $execute[] = $categoryName;
248        }
249
250        $this->database->prepare("SELECT Name, CategoryID, FileName FROM tblCategory $additional;");
251        $this->database->execute($execute);
252
253        if ( $this->database->num_rows() == 0 ) {
254            return $return;
255        }
256
257        $data = array(); $this->database->bind_assoc($data);
258        while ( $this->database->fetch() ) {
259            $return[$data['Name']] = array(	'CategoryID' => $data['CategoryID'],
260											'FileName' =>  $data['FileName'],
261            );
262        }
263
264        return $return;
265    }
266
267    /*
268     * Get Available Languages for a Category
269     */
270    function _getAvailableLanguagesVersions($categoryID) {
271
272        if ( !$categoryID ) {
273            return;
274        }
275
276        $SQL = "Select DISTINCT Version, Lang FROM (SELECT Version, keyID FROM tblMaster WHERE CategoryID=? GROUP BY Version) as t1 INNER JOIN tblTranslation ON t1.KeyID = tblTranslation.KeyID";
277        $SQL = "SELECT Version, Lang FROM tblTranslation INNER JOIN tblMaster ON tblMaster.KeyID=tblTranslation.KeyID WHERE CategoryID=? GROUP BY Version, Lang;";
278
279        // Approximativ - vermutlich zu viel, aber besser als gar nix!
280        $SQL = "SELECT Lang, Version FROM (SELECT DISTINCT Lang FROM tblTranslation) as t1 CROSS JOIN (SELECT DISTINCT Version FROM tblMaster WHERE CategoryID=?) as t2;";
281
282        $this->database->prepare($SQL);
283        $this->database->execute($categoryID);
284
285        $languages = array(); $data = array(); $this->database->bind_assoc($data);
286        while ( $this->database->fetch() ) {
287            $languages[$data['Version']][] = $data['Lang'];
288        }
289
290        foreach ( array_keys($languages) as $key ) {
291            array_unshift($languages[$key], $this->getConf('default_language'));
292        }
293
294        return $languages;
295    }
296
297
298    /*
299     * Get Available Languages for a Category
300     */
301    function _getAvailableLanguages($categoryID, $version=null) {
302
303        $EXECUTE = array($categoryID);
304        if ( !empty($version) ) {
305            $ADDITIONAL .= " AND Version=?";
306            $EXECUTE[] = $version;
307        }
308
309        $languages = array($this->getConf('default_language'));
310        $this->database->prepare("SELECT Lang FROM tblTranslation INNER JOIN tblMaster ON tblMaster.KeyID=tblTranslation.KeyID WHERE CategoryID=? $ADDITIONAL GROUP BY Lang;");
311        $this->database->execute($EXECUTE);
312
313        $data = array(); $this->database->bind_assoc($data);
314        while ( $this->database->fetch() ) {
315            $languages[] = $data['Lang'];
316        }
317
318        return $languages;
319    }
320
321    /*
322     * Get Available Versions for a Category
323     */
324    function _getAvailableVersions($categoryID=null) {
325
326        $EXECUTE = array();
327        $ADDITIONAL = "";
328        if ( !empty( $categoryID) ) {
329            $EXECUTE[] = $categoryID;
330            $ADDITIONAL .= " WHERE CategoryID=? ";
331        }
332
333        $versions = array();
334        $this->database->prepare("SELECT Version FROM tblMaster $ADDITIONAL GROUP BY Version;");
335        $this->database->execute($EXECUTE);
336
337        $data = array(); $this->database->bind_assoc($data);
338        while ( $this->database->fetch() ) {
339            $versions[] = trim($data['Version']);
340        }
341
342        $versions = array_unique($versions);
343        usort($versions, array($this, "_sortVersion"));
344
345        return $versions;
346    }
347
348    function _sortVersion($a, $b) {
349
350        if ($a === $b ) {
351            return 0;
352        } else if ( is_numeric($a) && is_numeric($b) ) {
353            return $a < $b ? -1 : 1;
354        } else if ( !is_numeric($a) && !is_numeric($b) ) {
355            return strcmp($a, $b);
356        } else if ( !is_numeric($a)) {
357            return 1;
358        } else {
359            return -1;
360        }
361    }
362
363    /*
364     * Get Key from Master via Name
365     */
366    function _getMasterKeyIDFromName($KeyName, $CategoryID, $isID=false, $getID=true) {
367
368        $this->setUTF8Collation();
369
370        $WHATTO = 'tblMasterKey.ResourceKey';
371        if ( $isID ) {
372            $WHATTO = 'tblMasterKey.KeyID';
373        }
374
375        // Get latest MasterKeyID from Category
376        $this->database->prepare("SELECT DISTINCT tblMasterKey.KeyID, Value FROM tblMasterKey INNER JOIN tblMaster ON tblMasterKey.KeyID=tblMaster.KeyID WHERE tblMaster.CategoryID=? AND $WHATTO=? ORDER BY Version DESC;");
377        $this->database->execute($CategoryID, $KeyName);
378
379        if ( $this->database->num_rows() > 0 ) {
380            $data = array(); $this->database->bind_assoc($data); $this->database->fetch();
381            return $getID ? $data['KeyID'] : $data['Value'];
382        } else {
383            return false;
384        }
385    }
386
387    /**
388     * Check for all Keys if they do have a master - otherwise, kick them
389     * @param $translation
390     * @param $finalStatus
391     * @param $CategoryID
392     */
393    function _checkForMasterKeyIDs(&$translation, &$finalStatus, $CategoryID) {
394
395        $this->setUTF8Collation();
396
397        $keysIN = implode("\",\"", array_keys($translation));
398        //        $keysIN = str_replace("(", "\(", $keysIN);
399        //        $keysIN = str_replace(")", "\)", $keysIN);
400
401        // Get latest MasterKeyID from Category
402        $SQL = "SELECT DISTINCT tblMasterKey.KeyID, tblMasterKey.ResourceKey FROM tblMasterKey INNER JOIN tblMaster ON tblMasterKey.KeyID=tblMaster.KeyID WHERE tblMaster.CategoryID=? AND tblMasterKey.ResourceKey in ( \"$keysIN\" ) ORDER BY Version DESC;";
403        $this->database->prepare($SQL);
404        $this->database->execute($CategoryID);
405
406        $data = array(); $this->database->bind_assoc($data);
407        while ( $this->database->fetch() ) {
408            $translation[$data['ResourceKey']] = array( 'ID' => $data['KeyID'], 'Value' => $translation[$data['ResourceKey']] );
409            $finalStatus['CountOfKeys']++;
410        }
411    }
412
413    /*
414     * Check if a key exists - additionally check for Lang and Value
415     */
416    function _keyExists($KeyID, $Lang=null, $Value=null, $Date=null) {
417
418        $additional = "";
419        $execute = array( $KeyID );
420
421        if ( !empty($Lang) ) {
422            $additional .= " AND Lang=?";
423            $execute[] = $Lang;
424        }
425
426        if ( !empty($Date) ) {
427            $additional .= " AND Date=?";
428            $execute[] = $Date;
429        }
430
431        $SQL = "SELECT KeyID, Value FROM tblTranslation WHERE KeyID=? $additional";
432
433        // Checks for the latest Entry
434        if ( !empty($Value) ) {
435            $SQL = "SELECT tblTrans.KeyID FROM ($SQL ORDER BY Date DESC LIMIT 1) as tblTrans WHERE BINARY tblTrans.Value=?";
436            $execute[] = $Value;
437        }
438
439        $this->database->prepare("$SQL;");
440        $this->database->execute($execute);
441
442        if ( $this->database->num_rows() == 0 ) {
443            return false;
444        }
445
446        return true;
447    }
448
449    /*
450     * Insert a new Translation Set of Translations
451     */
452    function _insertTranslation($KeyID, $Value, $Lang, $Date, $User=null) {
453        global $INFO;
454
455        $revertable = false;
456
457        if ( empty($Value) ) return $revertable;
458
459        // Bottleneck 2
460        if ( $this->_keyExists($KeyID, $Lang) ) {
461
462            if ( $this->_keyExists($KeyID, $Lang, $Value) || $this->_keyExists($KeyID, $Lang, null, $Date) ) {
463                return -1;
464            }
465
466            $revertable = true;
467        }
468
469        // Insert Translation
470        if ( empty($User) ) $User = $_SERVER['REMOTE_USER'];
471
472
473        $this->database->prepare("INSERT INTO tblTranslation (KeyID, Lang, Value, User, Date) VALUES(?, ?, ?, ?, ?);");
474        $this->database->execute($KeyID, $Lang, $Value, $User, $Date);
475
476        return $revertable;
477    }
478
479    function _insertTranslationArray($translation, &$finalStatus, $Lang, $Date) {
480
481        $CHECK = '';
482        $translationINV = array();
483        foreach( $translation as $key => $value ) {
484            if ( !is_array($value) ) {
485                $finalStatus['KeysNotInMaster'][] = $key;
486                unset($translation[$key]);
487                continue;
488            }
489
490            $CHECK .= $value['ID'] . ",";
491            $translationINV[$value['ID']] = array(
492                                                'key' => $key,
493                                                'value' => $value['Value']
494                                            );
495        }
496
497        $CHECK = substr($CHECK, 0, -1);
498        $SQL = "SELECT DISTINCT * FROM (SELECT KeyID, Value, Date FROM tblTranslation WHERE KeyID in ( $CHECK ) AND Lang=? ORDER BY Date) as t1 GROUP BY KeyID;";
499
500        $this->database->prepare($SQL);
501        $this->database->execute($Lang);
502
503        $data = array(); $this->database->bind_assoc($data);
504        while ( $this->database->fetch() ) {
505
506            if ( $translationINV[$data['KeyID']]['value'] == $data['Value'] || $data['Date'] == $Date ) {
507                 $finalStatus['KeysMatchingExisting'][] = $translationINV[$data['KeyID']]['key'];
508                 unset( $translation[$translationINV[$data['KeyID']]['key']] );
509                 unset( $translationINV[$data['KeyID']] );
510                 continue;
511            }
512
513            $finalStatus['CountOfToBeReverted']++;
514        }
515        unset($SQL);
516
517        if ( empty($translation) ) {
518            return;
519        }
520
521        $INSERT = '';
522        $INSERTDATA = array();
523        foreach( $translation as $key => $value ) {
524
525            $INSERTDATA[] = $value['ID'];
526            $INSERTDATA[] = $Lang;
527            $INSERTDATA[] = $value['value'];
528            $INSERTDATA[] = $_SERVER['REMOTE_USER'];
529            $INSERTDATA[] = $Date;
530
531            $INSERT .= '(?,?,?,?,?),';
532        }
533
534        $INSERT = substr($INSERT, 0, -1);
535        $this->database->prepare("INSERT INTO tblTranslation (KeyID, Lang, Value, User, Date) VALUES $INSERT;");
536        $this->database->execute($INSERTDATA);
537    }
538
539
540    function _getTranslation($CategoryID, $Version, $Language) {
541
542        $this->setUTF8Collation();
543
544        if ( $Language == $this->getConf('default_language') ) {
545            $this->database->prepare("SELECT ResourceKey, Value FROM tblMasterKey INNER JOIN tblMaster ON tblMasterKey.KeyID=tblMaster.KeyID WHERE tblMaster.Version=? AND tblMaster.CategoryID=? ORDER BY tblMasterKey.ResourceKey;");
546            $this->database->execute($Version, $CategoryID);
547        } else {
548            $this->database->prepare("SELECT tblMasterKey.ResourceKey, tblTrans.Value FROM (tblMasterKey INNER JOIN tblMaster ON tblMasterKey.KeyID=tblMaster.KeyID AND tblMaster.Version=? AND tblMaster.CategoryID=?) INNER JOIN (SELECT * FROM (SELECT * FROM tblTranslation WHERE tblTranslation.Lang=? ORDER BY tblTranslation.Date DESC) as tblTemp1 GROUP BY KeyID) as tblTrans ON tblMasterKey.KeyID = tblTrans.KeyID ORDER BY ResourceKey, Value;");
549            $this->database->execute($Version, $CategoryID, $Language);
550        }
551
552        $return = array();
553        $data = array(); $this->database->bind_assoc($data);
554        while ( $this->database->fetch() ) {
555            $return[$data['ResourceKey']] = $data['Value'];
556        }
557
558        return $return;
559    }
560
561    /*
562     * Revert Entries by dateTime, lang and user
563     */
564    function _revertEntries($dateTime, $lang, $user=null) {
565        global $INFO;
566
567        if ( empty($user) ) $user = $_SERVER['REMOTE_USER'];
568        $this->database->prepare("DELETE FROM tblTranslation WHERE Date=? AND Lang=? AND User=?;");
569        $this->database->execute($dateTime, $lang, $user);
570
571        return $this->database->num_rows();
572    }
573
574    /* ******************************************************************************************************************************
575     * Export Manager
576     ***************************************************************************************************************************** */
577    function _exportManager($caller) {
578
579        $form = $caller->_startFieldSet($this->getLang('ExportManager'), 'translator_export');
580
581        list($categories, $changeCategory, $changeVersion) = $this->_getChangerJS();
582
583        $versions = array();
584        $languages = array();
585
586        if ( is_array($categories[$_REQUEST['Category']]['Versions']) ) {
587            $versions = array_keys($categories[$_REQUEST['Category']]['Versions']);
588        }
589
590        if ( is_array($categories[$_REQUEST['Category']]['Versions'][$_REQUEST['Version']]) ) {
591            $languages = array_values($categories[$_REQUEST['Category']]['Versions'][$_REQUEST['Version']]);
592        }
593
594        $form->addElement(form_makeListboxField('Category', array_keys($categories), $_REQUEST['Category'], $this->getLang('Category') . ':', null, null, array('onchange' => $changeCategory)));
595        $form->addElement(form_makeTag('br'));
596        $form->addElement(form_makeListboxField('Version', $versions, $_REQUEST['Version'], $this->getLang('Version') . ':', null, null, array('onchange' => $changeVersion)));
597        $form->addElement(form_makeTag('br'));
598        $form->addElement(form_makeListboxField('Language', $languages, $_REQUEST['Language'], $this->getLang('Language') . ':'));
599        $form->addElement(form_makeTag('br'));
600        $form->addElement(form_makeField('submit', 'export_language', $this->getLang('Export'), ''));
601
602        $caller->_finishFieldset($form);
603    }
604
605    /**
606     * Set headers and send the file to the client
607     */
608    function _sendLanguageFile($data, $fileName){
609        global $conf;
610
611        // send headers
612        header("Content-Type: text");
613        // nocache
614        header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0');
615        header('Pragma: public');
616        header('Content-Disposition: attachment; filename="'.$fileName.'";');
617
618        // send file contents
619        if ( !empty($data) ) {
620            foreach( $data as $line ) {
621                print "$line\r\n"; flush();
622            }
623        }
624    }
625
626    function capture_form_output($form) {
627
628        if ( !$form ) { return ''; }
629        ob_start();
630        $form->printForm();
631        $output = ob_get_contents();
632        ob_end_clean();
633
634        return trim($output);
635    }
636
637    function _getTranslationMatrix($category, $Version, $Language, $additionalLanguage=null, $start="0", $amount="50", $display=null, $filter=null) {
638
639        $this->setUTF8Collation();
640
641        if ( empty($display) ) {
642            $display = $this->getLang('notTranslated');
643        }
644
645        $matrix = array();
646        list($categoryID) = $this->_getCategoryFromName($category);
647
648        if ( $additionalLanguage == $this->getConf('default_language') ) $additionalLanguage = null;
649
650        $ADDITIONAL = "";
651        $ADDITIONALKEYS = "";
652
653        $EXECUTE = array($categoryID, $Version, $Language, $Language);
654
655        // add SQL for Additional Language
656        if ( !empty($additionalLanguage) ) {
657            $ADDITIONAL .=	"LEFT JOIN ( tblTranslation as AdditionalTranslation INNER JOIN
658								(SELECT KeyID, MAX(Date) AS Date FROM tblTranslation WHERE Lang=? GROUP BY KeyID) as tblOldestAddTrans ON
659								tblOldestAddTrans.KeyID=AdditionalTranslation.KeyID AND tblOldestAddTrans.Date=AdditionalTranslation.Date AND AdditionalTranslation.Lang=?) ON
660							tblMaster.KeyID = AdditionalTranslation.KeyID ";
661
662            $ADDITIONALKEYS .= ", AdditionalTranslation.Value as AdditionalValue";
663            array_push($EXECUTE, $additionalLanguage);
664            array_push($EXECUTE, $additionalLanguage);
665        }
666
667        // Modify Display settings
668        switch($display) {
669            case $this->getLang('notTranslated')	: $ADDITIONAL .= "WHERE tblTranslation.Value IS NULL";
670            break;
671            case $this->getLang('translated')		: $ADDITIONAL .= "WHERE tblTranslation.Value IS NOT NULL";
672            break;
673        }
674
675        // Add Filter
676        if ( !empty($filter) ) {
677            if ( !strstr($ADDITIONAL, 'WHERE')) {
678                $ADDITIONAL .= "WHERE";
679            } else {
680                $ADDITIONAL .= " AND";
681            }
682
683            if( substr($filter, 0, 1) != "%" ) $filter = "%" . $filter;
684            if( substr($filter, -1) != "%" ) $filter .= "%";
685
686            $ADDITIONAL .= ' (ResourceKey LIKE ? OR tblMasterKey.Value LIKE ? OR tblTranslation.Value LIKE ?';
687            if ( !empty($additionalLanguage) ) {
688                $ADDITIONAL .= ' OR AdditionalTranslation.Value LIKE ? ';
689                array_push($EXECUTE, $filter);
690            }
691
692            $ADDITIONAL .= ')';
693
694            array_push($EXECUTE, $filter);
695            array_push($EXECUTE, $filter);
696            array_push($EXECUTE, $filter);
697        }
698
699        if ( empty($amount) ) $amount = 50;
700        // Limits
701
702        // Build SQL
703
704        $SQL =	"SELECT tblMasterKey.KeyID, ResourceKey, tblMasterKey.Value as MasterValue,
705						tblTranslation.Value as TranslationValue, tblTranslation.User $ADDITIONALKEYS
706						FROM (
707							( tblMasterKey INNER JOIN tblMaster ON
708							tblMaster.KeyID = tblMasterKey.KeyID AND CategoryID = ? AND Version = ? )
709
710							LEFT JOIN (
711								tblTranslation INNER JOIN
712								(SELECT KeyID, MAX(Date) AS Date FROM tblTranslation WHERE Lang=? GROUP BY KeyID) as tblOldestTrans ON
713								tblOldestTrans.KeyID=tblTranslation.KeyID AND tblOldestTrans.Date=tblTranslation.Date
714							) ON tblMaster.KeyID = tblTranslation.KeyID AND Lang=?
715						) $ADDITIONAL ORDER BY tblMaster.KeyID LIMIT ? OFFSET ?;";
716
717        $this->database->prepare("$SQL");
718        $this->database->execute(array_merge($EXECUTE, array('1000000000000', '0')));
719        $max = $this->database->num_rows();
720
721        array_push($EXECUTE, intval($amount));
722        array_push($EXECUTE, intval($start));
723
724        // Fetch Data
725        $this->database->execute($EXECUTE);
726
727        if ( $this->database->num_rows() == 0 ) {
728            return false;
729        }
730
731        $data = array(); $this->database->bind_assoc($data);
732        while ( $this->database->fetch() ) {
733
734            $matrix[$data['KeyID']] = array	(
735												'KeyID' => $data['KeyID'],
736												'ResourceKey' => $data['ResourceKey'],
737												'MasterValue' => str_replace('\n', "\r\n", $this->_stringDecode($data['MasterValue'])),
738												'TranslationValue' => str_replace('\n', "\r\n", $this->_stringDecode($data['TranslationValue'])),
739												'AdditionalValue' => str_replace('\n', "\r\n", $this->_stringDecode($data['AdditionalValue'])),
740												'User' => $data['User'],
741            );
742        }
743
744        return array($matrix, $max);
745    }
746
747
748    /*
749     * get the users languages from the database and return false if none are there
750     */
751    function _getLanguages() {
752        global $INFO;
753
754        //		print_r($INFO);
755        //		print $_SERVER['REMOTE_USER'];
756
757        if ( empty($INFO['userinfo']) ) {
758            return false;
759        }
760
761        $this->database->prepare("SELECT Lang FROM tblUserRights WHERE User=?");
762        $this->database->execute($_SERVER['REMOTE_USER']);
763
764        if ( $this->database->num_rows() == 0) {
765            return false;
766        }
767
768        $data = array(); $this->database->bind_assoc($data); $this->database->fetch();
769        return trim($data['Lang']);
770    }
771
772    function _handleRequest($fn) {
773        if (is_array($fn)) {
774            $cmd = key($fn);
775            $param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null;
776        } else {
777            $cmd = $fn;
778            $param = null;
779        }
780
781        switch($cmd){
782            case "revertuploaded"	:	$this->_revertUploadedEntries($_REQUEST['revert']); break;
783            case "translate"		:	$this->_updateTranslation($_REQUEST['Language'], $_REQUEST['translation']); break;
784            case "setpage"			:	$_REQUEST['start'] = $param; $_REQUEST['amount'] = $_REQUEST['newAmount']; $_REQUEST['AdditionalLanguage'] = $_REQUEST['newAdditionalLanguage']; break;
785            case "setup"			:	$_REQUEST['Language'] = $param; $_REQUEST['Display'] = $param ? key($fn[$cmd][$param]) : null; break;
786        }
787    }
788
789
790    function _stringEncode($var) {
791
792        // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
793        $ascii = '';
794        //$var = str_replace("\n", '\n', $var);
795        $strlen_var = strlen($var);
796
797        /*
798         * Iterate over every character in the string,
799         * escaping with a slash or encoding to UTF-8 where necessary
800         */
801        for ($c = 0; $c < $strlen_var; ++$c) {
802
803            $ord_var_c = ord($var{$c});
804
805            switch ($ord_var_c) {
806                case 0x08:  $ascii .= '\b';  break;
807                case 0x09:  $ascii .= '\t';  break;
808                case 0x0A:  $ascii .= '\n';  break;
809                case 0x0C:  $ascii .= '\f';  break;
810                case 0x0D:  $ascii .= '\r';  break;
811                case 0x3D:  $ascii .= '\=';  break;
812                case 0x3A:  $ascii .= '\:';  break;
813
814                case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
815                    // characters U-00000000 - U-0000007F (same as ASCII)
816                    $ascii .= $var{$c};
817                    break;
818
819                case (($ord_var_c & 0xE0) == 0xC0):
820                    // characters U-00000080 - U-000007FF, mask 110XXXXX
821                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
822                    $char = pack('C*', $ord_var_c, ord($var{$c+1}));
823                    $c+=1;
824                    //$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
825                    $utf16 = utf8_to_utf16be($char);
826                    $ascii .= sprintf('\u%04s', strtoupper(bin2hex($utf16)));
827                    break;
828
829                case (($ord_var_c & 0xF0) == 0xE0):
830                    // characters U-00000800 - U-0000FFFF, mask 1110XXXX
831                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
832                    $char = pack('C*', $ord_var_c,
833                    ord($var{$c+1}),
834                    ord($var{$c+2}));
835                    $c+=2;
836                    //$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
837                    $utf16 = utf8_to_utf16be($char);
838                    $ascii .= sprintf('\u%04s', strtoupper(bin2hex($utf16)));
839                    break;
840
841                case (($ord_var_c & 0xF8) == 0xF0):
842                    // characters U-00010000 - U-001FFFFF, mask 11110XXX
843                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
844                    $char = pack('C*', $ord_var_c,
845                    ord($var{$c+1}),
846                    ord($var{$c+2}),
847                    ord($var{$c+3}));
848                    $c+=3;
849                    //$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
850                    $utf16 = utf8_to_utf16be($char);
851                    $ascii .= sprintf('\u%04s', strtoupper(bin2hex($utf16)));
852                    break;
853
854                case (($ord_var_c & 0xFC) == 0xF8):
855                    // characters U-00200000 - U-03FFFFFF, mask 111110XX
856                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
857                    $char = pack('C*', $ord_var_c,
858                    ord($var{$c+1}),
859                    ord($var{$c+2}),
860                    ord($var{$c+3}),
861                    ord($var{$c+4}));
862                    $c+=4;
863                    //$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
864                    $utf16 = utf8_to_utf16be($char);
865                    $ascii .= sprintf('\u%04s', strtoupper(bin2hex($utf16)));
866                    break;
867
868                case (($ord_var_c & 0xFE) == 0xFC):
869                    // characters U-04000000 - U-7FFFFFFF, mask 1111110X
870                    // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
871                    $char = pack('C*', $ord_var_c,
872                    ord($var{$c+1}),
873                    ord($var{$c+2}),
874                    ord($var{$c+3}),
875                    ord($var{$c+4}),
876                    ord($var{$c+5}));
877                    $c+=5;
878                    //$utf16 = mb_convert_encoding($char, 'UTF-16', 'UTF-8');
879                    $utf16 = utf8_to_utf16be($char);
880                    $ascii .= sprintf('\u%04s', strtoupper(bin2hex($utf16)));
881                    break;
882            }
883        }
884
885        return $ascii;
886    }
887
888    function _stringDecode($chrs) {
889
890        // STRINGS RETURNED IN UTF-8 FORMAT
891
892        $utf8 = '';
893        $chrs = addcslashes(trim($chrs), "\n\t\r"); // Ensure to have the Line Breaks intact
894        $strlen_chrs = strlen($chrs);
895
896        for ($c = 0; $c < $strlen_chrs; ++$c) {
897
898            $substr_chrs_c_2 = substr($chrs, $c, 2);
899            $ord_chrs_c = ord($chrs{$c});
900
901            switch ($substr_chrs_c_2) {
902                case '\b':  $utf8 .= chr(0x08);  $c+=1;  break;
903                case '\t':  $utf8 .= chr(0x09);  $c+=1;  break;
904                case '\n':  $utf8 .= chr(0x0A);  $c+=1;  break;
905                case '\f':  $utf8 .= chr(0x0C);  $c+=1;  break;
906                case '\r':  $utf8 .= chr(0x0D);  $c+=1;  break;
907                case '\:':  $utf8 .= chr(0x3A);  $c+=1;  break;
908                case '\=':  $utf8 .= chr(0x3D);  $c+=1;  break;
909
910                default:
911                    if (preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6))) {
912                        // single, escaped unicode character
913                        $utf16 = chr(hexdec(substr($chrs, ($c+2), 2))) . chr(hexdec(substr($chrs, ($c+4), 2)));
914
915                        //$utf8 .= mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); // This is correct for rusians
916                        $utf8 .= utf16be_to_utf8($utf16); // this as Well;
917
918                        //$utf8 .= utf8_decode(utf16be_to_utf8($utf16));
919                        $c+=5;
920
921                    } elseif(($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F)) {
922                        $utf8 .= $chrs{$c};
923
924                    } elseif(($ord_chrs_c & 0xE0) == 0xC0) {
925                        // characters U-00000080 - U-000007FF, mask 110XXXXX
926                        //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
927                        $utf8 .= substr($chrs, $c, 2); $c += 1;
928
929                    } elseif(($ord_chrs_c & 0xF0) == 0xE0) {
930                        // characters U-00000800 - U-0000FFFF, mask 1110XXXX
931                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
932                        $utf8 .= substr($chrs, $c, 3); $c += 2;
933
934                    } elseif(($ord_chrs_c & 0xF8) == 0xF0) {
935                        // characters U-00010000 - U-001FFFFF, mask 11110XXX
936                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
937                        $utf8 .= substr($chrs, $c, 4); $c += 3;
938
939                    } elseif(($ord_chrs_c & 0xFC) == 0xF8) {
940                        // characters U-00200000 - U-03FFFFFF, mask 111110XX
941                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
942                        $utf8 .= substr($chrs, $c, 5); $c += 4;
943
944                    } elseif(($ord_chrs_c & 0xFE) == 0xFC) {
945                        // characters U-04000000 - U-7FFFFFFF, mask 1111110X
946                        // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
947                        $utf8 .= substr($chrs, $c, 6); $c += 5;
948                    } else {
949                        // Falls doch noch andere UTF8 Zeichen enthalten sind, m�ssen die extra behandelt werden.
950                        $utf8 .= chr($ord_chrs_c);
951                    }
952                    break;
953            }
954
955        }
956
957        // print " '$utf8' ";
958
959        return $utf8;
960    }
961
962    function _revertManager($parent, $revertableUpload) {
963
964        // If there is nothing revertable then end here;
965        if ( count($revertableUpload) == 0 ) {
966            return;
967        }
968
969        $form = $parent->_startFieldSet($this->getLang('RevertManager'), 'translator_revert');
970
971        if ( count($revertableUpload) > 1 ) {
972            foreach ( $revertableUpload as $revertable ) {
973                $form->addElement(form_makeCheckboxField("revert[{$revertable['current_date_time']}][{$revertable['lang']}]", 1, $revertable['name'] . " ({$revertable['lang']})", null));
974                $form->addElement(form_makeTag('br'));
975            }
976        } else {
977            $form->addElement($this->getLang('RevertManagerHowTo'));
978            $revertable = array_shift($revertableUpload);
979            $form->addHidden("revert[{$revertable['current_date_time']}][{$revertable['lang']}]", 1);
980        }
981
982        $form->addElement(form_makeField('submit', 'fn[revertuploaded]', $this->getLang('Revert'), ''));
983        return $parent->_finishFieldset($form);
984    }
985
986    function _updateTranslation($Language, $Translation) {
987        global $INFO;
988
989        $date = date('Y-m-d H:i:s');
990        $this->revertableUpload = array();
991        if ( !in_array($Language, explode('|', $this->_getLanguages()) ) ) return;
992
993        $finalStatus = array(
994											'KeysNotInMaster' => array(),
995											'KeysMatchingExisting' => array(),
996											'CountOfKeys' => 0,
997											'CountOfToBeReverted' => 0,
998        );
999
1000        foreach( $Translation as $key => $value ) {
1001
1002            $finalStatus['CountOfKeys']++;
1003
1004            if ( empty($value) ) {
1005                $finalStatus['RemovedUserKeys'] += $this->_tryRevertEntry($Language, $_SERVER['REMOTE_USER'], $key);
1006                continue;
1007            }
1008
1009            // 18.05.2010
1010            // Entfernt, damit Russische �bersetzungen wieder funktionieren
1011            // $value = utf8_decode($value);
1012
1013            // 20.05.2010
1014            // Russisch darf nicht ... aber Detusch z.B. muss ... welche Ausnahmen gibt es noch?
1015            //if ( !in_array( $Language, array("ru", "zh_CN", "zh_TW", "ja", "ko") ) ) {
1016            //    $value = utf8_decode($value);
1017            //}
1018
1019            // 06.12.2010 - �nderung der Datenbank. Es werden nur noch die codierten Werte gespeichert.
1020            $value = $this->_stringEncode($value);
1021
1022            $status = $this->_insertTranslation($key, $value, $Language, $date);
1023            if ( $status === -1 ) {
1024                $finalStatus['KeysMatchingExisting'][]=$key;
1025            } else if ( $status === true ) {
1026                $finalStatus['CountOfToBeReverted']++;
1027            }
1028        }
1029
1030        if ( $finalStatus['CountOfToBeReverted'] > 0 ) {
1031            $this->revertableUpload[$date] = 	array(
1032																'lang' => $Language,
1033																'name' => $_SERVER['REMOTE_USER'],
1034																'current_date_time' => $date,
1035            );
1036        }
1037
1038        $this->_statusResult($finalStatus, $Language);
1039        return;
1040
1041    }
1042
1043    /*
1044     * Revert Uploaded Entries
1045     */
1046    function _revertUploadedEntries($revertItems) {
1047
1048        if ( !is_array($revertItems) ) return;
1049
1050        foreach ( array_keys($revertItems) as $revertDateTime ) {
1051            foreach ( array_keys($revertItems[$revertDateTime]) as $lang ) {
1052                $items = $this->_revertEntries($revertDateTime, $lang);
1053                msg($this->_messageReplacer('RevertedItems', $items));
1054            }
1055        }
1056    }
1057
1058    function _tryRevertEntry($language, $user, $key=null) {
1059
1060        if ( $language == $this->getConf('defaultLanguage') ) return false;
1061
1062        $ADDITIONAL = "";
1063        $EXECUTE = array($user, $language);
1064
1065        if ( !empty( $key )) {
1066            $SQL = "SELECT tblTranslation.* FROM ((SELECT KeyID, MAX(Date) AS Date FROM tblTranslation WHERE Lang=? GROUP BY KeyID) as tblOldestAddTrans INNER JOIN tblTranslation ON tblOldestAddTrans.KeyID=tblTranslation.KeyID AND tblOldestAddTrans.Date=tblTranslation.Date) WHERE tblTranslation.KeyID=? AND tblTranslation.User=?;";
1067            $this->database->prepare($SQL);
1068            $this->database->execute($language, $key, $user);
1069            $data = array(); $this->database->bind_assoc($data); $this->database->fetch();
1070            $ADDITIONAL .= " AND KeyID=? AND Date=?";
1071            $EXECUTE[] = $data['KeyID'];
1072            $EXECUTE[] = $data['Date'];
1073        }
1074
1075        $this->database->prepare("DELETE FROM tblTranslation WHERE User=? AND Lang=? $ADDITIONAL");
1076        $this->database->execute($EXECUTE);
1077
1078        return $this->database->num_rows();
1079    }
1080
1081    function _statusResult($finalStatus, $Lang, $FileName="User created") {
1082
1083        if ( !is_array($finalStatus['KeysNotInMaster']) ) $finalStatus['KeysNotInMaster'] = array($finalStatus['KeysNotInMaster']);
1084        if ( !is_array($finalStatus['KeysMatchingExisting']) ) $finalStatus['KeysMatchingExisting'] = array($finalStatus['KeysMatchingExisting']);
1085
1086        if ( count($finalStatus['KeysNotInMaster']) > 0 ) {
1087            msg($this->_messageReplacer('KeysNotInMaster', array(count($finalStatus['KeysNotInMaster']), count($finalStatus['KeysNotInMaster'])+$finalStatus['CountOfKeys'], $Lang, $FileName, implode(', ', $finalStatus['KeysNotInMaster']))), -1);
1088        }
1089
1090        if ( count($finalStatus['KeysMatchingExisting']) > 0 ) {
1091            msg($this->_messageReplacer('KeysMatchingExisting', array(count($finalStatus['KeysMatchingExisting']), $finalStatus['CountOfKeys'], $Lang, $FileName, implode(', ', $finalStatus['KeysMatchingExisting']))), 1);
1092        }
1093
1094        if ( $finalStatus['RemovedUserKeys'] > 0 ) {
1095            msg($this->_messageReplacer('RemovedUserKeys', array($finalStatus['RemovedUserKeys'], $finalStatus['CountOfKeys'])));
1096        }
1097
1098        if ( $finalStatus['CountOfToBeReverted'] > 0 ) {
1099            msg($this->getLang('RevertValues'));
1100            return false;
1101        }
1102
1103        if ( $finalStatus['KeysMatchingExisting'] == $finalStatus['CountOfKeys']
1104        || ( $finalStatus['KeysMatchingExisting'] == 0 && $finalStatus['CountOfToBeReverted'] == 0 && $finalStatus['KeysNotInMaster'] == 0 ) ) {
1105            $_REQUEST['start'] += $_REQUEST['amount'];
1106        }
1107
1108        return true;
1109    }
1110
1111    function _getAmountOfMasterValues($categoryID=null, $version=null) {
1112
1113        $EXECUTE = array();
1114        $ADDITIONAL = '';
1115        if ( !empty($categoryID) ) {
1116            $ADDITIONAL .= "CategoryID=?";
1117            $EXECUTE[] = $categoryID;
1118        }
1119
1120        if ( !empty($categoryID) ) {
1121            if ( !empty($ADDITIONAL) ) {
1122                $ADDITIONAL .= " AND ";
1123            }
1124
1125            $ADDITIONAL .= "Version=?";
1126            $EXECUTE[] = $version;
1127        }
1128
1129        if ( !empty($ADDITIONAL) ) {
1130            $ADDITIONAL = " WHERE " . $ADDITIONAL;
1131        }
1132
1133
1134        $this->database->prepare("SELECT COUNT(tblMaster.KeyID) as amount FROM tblMasterKey INNER JOIN tblMaster ON tblMasterKey.KeyID=tblMaster.KeyID $ADDITIONAL;");
1135        $this->database->execute($EXECUTE);
1136
1137        $data=array(); $this->database->bind_assoc($data); $this->database->fetch();
1138
1139        return intval($data['amount']);
1140    }
1141
1142    function _getAmountOfLanguageValues($categoryID, $version, $lang) {
1143
1144        //$SQL = "SELECT COUNT(DISTINCT tblMaster.KeyID) as amount FROM tblMaster INNER JOIN tblTranslation ON tblMaster.KeyID=tblTranslation.KeyID WHERE Lang=? AND categoryID=? and Version=?;";
1145        $SQL = "SELECT COUNT(DISTINCT tblMaster.KeyID) as amount FROM tblMaster INNER JOIN tblTranslation ON tblMaster.KeyID=tblTranslation.KeyID AND Lang=? WHERE categoryID=? and Version=?;";
1146        //$SQL = "SELECT COUNT(tblMaster.KeyID) as amount FROM tblMaster INNER JOIN (SELECT KeyID FROM tblTranslation WHERE Lang=? GROUP BY KeyID) as tblTrans ON tblTrans.KeyID=tblMaster.KeyID WHERE categoryID=? and Version=?;";
1147
1148        $this->database->prepare($SQL);
1149        $this->database->execute($lang, $categoryID, $version);
1150
1151        $data=array(); $this->database->bind_assoc($data); $this->database->fetch();
1152
1153        return intval($data['amount']);
1154    }
1155
1156    function _downloadLink($category, $version, $language, $name, $NoEncoded=false) {
1157        global $ID;
1158        $options = array('export_language' => '1', 'Category' => $category, 'Version' => $version, 'Language' => $language);
1159        if ( $NoEncoded ) $options['NoEncode'] = 'true';
1160        return tpl_link(wl($ID, $options),$name,null,true);
1161    }
1162
1163    function _messageReplacer($LangKey, $replacements) {
1164        if ( !is_array($replacements))
1165        $replacements = array($replacements);
1166
1167        $language = $this->getLang($LangKey);
1168        for($i=0; $i<count($replacements); $i++) {
1169            $language = str_replace('{' . $i . '}', $replacements[$i], $language);
1170        }
1171
1172        return $language;
1173    }
1174
1175    function _getChangerJS($hasLanguageNode=true) {
1176
1177        $categories = $this->_getCategories();
1178        $JSCategories = "var categories = {";
1179        foreach ( $categories as $name => $category ) {
1180
1181            // Bottlenec 1
1182            $languages = $this->_getAvailableLanguagesVersions($category['CategoryID']);
1183            $versions = array_keys($languages);
1184            rsort($versions, SORT_NUMERIC);
1185
1186            if ( empty($versions) ) { continue; }
1187
1188            $JSCategories .= "'$name': {";
1189
1190            // Bottlenec 2
1191            foreach( $versions as $version ) {
1192                $categories[$name]['Versions'][$version] = $hasLanguageNode ? array_unique(array_merge(array('export all'), $languages[$version])) : array();
1193                $JSCategories .= "'$version':['" . implode("','", $categories[$name]['Versions'][$version]) . "']" . ( $version != end($versions) ? ',' : '' );
1194            }
1195
1196            $JSCategories .= "}" . ( $name != end(array_keys($categories)) ? ',' : '' );
1197        }
1198        $JSCategories .= "};";
1199
1200        if ( empty( $_REQUEST['Category']) ) $_REQUEST['Category'] = array_shift(array_keys($categories));
1201        if ( empty( $_REQUEST['Version']) && !empty($categories[$_REQUEST['Category']]['Versions']) ) $_REQUEST['Version'] = array_shift(array_keys($categories[$_REQUEST['Category']]['Versions']));
1202
1203        $nodes = "var node = this.parentNode.parentNode.getElementsByTagName('select');";
1204        $removeNodes = "while(node[i].hasChildNodes()) { node[i].removeChild(node[i].firstChild) }";
1205
1206        $createVersionNode = "for ( var vers in categories[cat] ) { var opt = document.createElement('option'); opt.appendChild(document.createTextNode(vers)); node[i].appendChild(opt) } ";
1207        $createLanguageNode = "for ( var lang in categories[cat][version] ) { var opt = document.createElement('option'); opt.appendChild(document.createTextNode(categories[cat][version][lang])); node[i].appendChild(opt) } ";
1208
1209        $nodeValues = "var cat = null; var version = null; for( var i=0; i<node.length; i++ ) { if (node[i].name == 'Category') { cat = node[i].value; } if (node[i].name == 'Version') { version = node[i].value; } }";
1210        $versionNode = "for( var i=0; i<node.length; i++ ) { if (node[i].name != 'Version') { continue; } $removeNodes $createVersionNode break; }";
1211        $languageNode = "for( var i=0; i<node.length; i++ ) { if (node[i].name != 'Language') { continue; } $removeNodes $createLanguageNode break; }";
1212
1213        $changeCategory = $JSCategories . " for ( var cat in categories) { if (this.value != cat ) { continue;} $nodes $versionNode" . ( $hasLanguageNode ? "var version = node[i].value; $languageNode " : '' ) . "break; } ";
1214        $changeVersion = $JSCategories . " $nodes $nodeValues $languageNode";
1215
1216        return array($categories, $changeCategory, $changeVersion);
1217    }
1218
1219    function setUTF8Collation() {
1220        $this->database->databaseConnection->query("SET NAMES 'utf8' COLLATE 'utf8_general_ci'");
1221        $this->database->databaseConnection->query("SET CHARACTER SET 'utf8'");
1222    }
1223
1224    /**
1225     * Allow the plugin to prevent DokuWiki creating a second instance of itself
1226     *
1227     * @return bool   true if the plugin can not be instantiated more than once
1228     */
1229    function isSingleton() {
1230        return true;
1231    }
1232
1233    /**
1234     * Pr�fen, ob die aktuelle Version schonmal hinsichtlich der Datenbankanbindung gepr�ft wurde
1235     */
1236    function currentVersionChecked() {
1237        if ( !file_exists( dirname(__FILE__).'/.translationcheck' ) ) {
1238            return false;
1239        }
1240
1241        $checkDate = implode('', file( dirname(__FILE__).'/.translationcheck' ) );
1242        $hash = confToHash(dirname(__FILE__).'/info.txt');
1243        return $hash['date'] == trim($checkDate);
1244    }
1245
1246    /**
1247     * Set the current Version to be checked
1248     */
1249    function setCurrentVersionChecked() {
1250
1251        $file = dirname(__FILE__).'/.translationcheck';
1252        $fh = fopen($file, 'w');
1253        if ( !$fh ) {
1254            msg('Could not write version check file.');
1255            return false;
1256        }
1257
1258        $hash = confToHash(dirname(__FILE__).'/info.txt');
1259        fwrite( $fh, $hash['date']);
1260        fclose($fh);
1261
1262        return true;
1263    }
1264}
1265
1266//Setup VIM: ex: et ts=4 enc=utf-8 :