ATutor 2.0
[atutor.git] / mods / _core / languages / classes / LanguageManager.class.php
1 <?php
2 /************************************************************************/
3 /* ATutor                                                                                                                               */
4 /************************************************************************/
5 /* Copyright (c) 2002-2010                                              */
6 /* Inclusive Design Institute                                           */
7 /* http://atutor.ca                                                     */
8 /* This program is free software. You can redistribute it and/or        */
9 /* modify it under the terms of the GNU General Public License          */
10 /* as published by the Free Software Foundation.                        */
11 /************************************************************************/
12 // $Id: LanguageManager.class.php 8919 2009-11-16 18:07:32Z cindy $
13
14 require_once(dirname(__FILE__) . '/Language.class.php');
15
16 define('AT_LANG_STATUS_EMPTY',       0);
17 define('AT_LANG_STATUS_INCOMPLETE',  1);
18 define('AT_LANG_STATUS_COMPLETE',    2);
19 define('AT_LANG_STATUS_PUBLISHED',   3);
20
21 /**
22 * LanguageManager
23 * Class for managing available languages as Language Objects.
24 * @access       public
25 * @author       Joel Kronenberg
26 * @see          Language.class.php
27 * @package      Language
28 */
29 class LanguageManager {
30
31         /**
32         * This array stores references to all the Language Objects
33         * that are available in this installation.
34         * @access private
35         * @var array
36         */
37         var $availableLanguages;
38
39         /**
40         * The fallback language if the DEFAULT_LANGUAGE isn't defined.
41         * @access private
42         * @var string
43         */
44         var $default_lang = 'en';
45
46         /**
47         * The fallback charachter set if the DEFAULT_CHARSET isn't defined.
48         * @access private
49         * @var string
50         */
51 //      var $default_charset = 'iso-8859-1';
52         var $default_charset = 'utf-8';
53
54         /**
55         * The number of languages that are available. Does not include
56         * character set variations.
57         * @access private
58         * @var integer
59         */
60         var $numLanguages;
61
62         /**
63         * Constructor.
64         * 
65         * Initializes availableLanguages and numLanguages.
66         */
67         function LanguageManager() {
68                 global $db;
69
70                 $sql    = 'SELECT * FROM '.TABLE_PREFIX.'languages ORDER BY native_name';
71                 $result = mysql_query($sql, $db);
72                 while($row = mysql_fetch_assoc($result)) {
73                         if (defined('AT_DEVEL_TRANSLATE') && AT_DEVEL_TRANSLATE) {
74                                 $row['status'] = AT_LANG_STATUS_PUBLISHED; // b/c the print drop down checks for it.                            
75                         }
76                         $this->availableLanguages[$row['language_code']][$row['char_set']] = new Language($row);
77                 }
78                 $this->numLanguages = count($this->availableLanguages);
79         }
80
81
82         /**
83         * Returns a valid Language Object based on the given language $code and optional
84         * $charset, FALSE if it can't be found.
85         * @access       public
86         * @param        string $code            The language code of the language to return.
87         * @param        string $charset         Optionally, the character set of the language to find.
88         * @return       boolean|Language        Returns FALSE if the requested language code and
89         *                                                               character set cannot be found. Returns a Language Object for the
90         *                                                               specified language code and character set.
91         * @see          getMyLanguage()
92         */
93         function getLanguage($code, $charset = '') {
94                 if (!$charset) {
95                         if (isset($this->availableLanguages[$code])) {
96                                 if (is_array($this->availableLanguages[$code]))
97                                         foreach ($this->availableLanguages[$code] as $language)
98                                                 return $language;
99 //                              return current($this->availableLanguages[$code]);
100                         } else {
101                                 debug('return false');
102                                 return FALSE;
103                         }
104                 }
105
106                 foreach ($this->availableLanguages[$code] as $language) {
107                         if ($language->getCharacterSet() == $charset) {
108                                 return $language;
109                         }
110                 }
111                 return FALSE;
112         }
113
114         /**
115         * Tries to detect the user's current language preference/setting from (in order):
116         * _GET, _POST, _SESSION, HTTP_ACCEPT_LANGUAGE, HTTP_USER_AGENT. If no match can be made
117         * then it tries to detect a default setting (defined in config.inc.php) or a fallback
118         * setting, false if all else fails.
119         * @access       public
120         * @return       boolean|Language        Returns a Language Object matching the user's current session.
121         *                                                               Returns FALSE if a valid Language Object cannot be found
122         *                                                               to match the request
123         * @see          getLanguage()
124         */
125         function getMyLanguage() {
126                 global $addslashes, $db; 
127
128                 if (isset($_GET) && !empty($_GET['lang']) && isset($this->availableLanguages[$_GET['lang']])) {
129                         $language = $this->getLanguage($_GET['lang']);
130
131                         if ($language) {
132                                 return $language;
133                         }
134
135                 } 
136                 if (isset($_POST) && !empty($_POST['lang']) && isset($this->availableLanguages[$_POST['lang']])) {
137                         $language = $this->getLanguage($_POST['lang']);
138
139                         if ($language) {
140                                 return $language;
141                         }
142
143                 } 
144                 if (isset($_SESSION) && isset($_SESSION['lang']) && !empty($_SESSION['lang']) && isset($this->availableLanguages[$_SESSION['lang']])) {
145                         $language = $this->getLanguage($_SESSION['lang']);
146
147                         if ($language) {
148                                 return $language;
149                         }
150                 }
151                 if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
152
153                         // Language is not defined yet :
154                         // try to find out user's language by checking its HTTP_ACCEPT_LANGUAGE
155                         $accepted    = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
156                         $acceptedCnt = count($accepted);
157                         reset($accepted);
158                         for ($i = 0; $i < $acceptedCnt; $i++) {
159                                 foreach ($this->availableLanguages as $codes) {
160                                         foreach ($codes as $language) {
161                                                 if ($language->isMatchHttpAcceptLanguage($accepted[$i])) {
162                                                         return $language;
163                                                 }
164                                         }
165                                 }
166                         }
167                 }
168
169                 if (!empty($_SERVER['HTTP_USER_AGENT'])) {
170
171                         // Language is not defined yet :
172                         // try to find out user's language by checking its HTTP_USER_AGENT
173                         foreach ($this->availableLanguages as $codes) {
174                                 foreach ($codes as $language) {
175                                         if ($language->isMatchHttpUserAgent($_SERVER['HTTP_USER_AGENT'])) {
176                                                 return $language;
177                                         }
178                                 }
179                         }
180                 }
181
182                 // Didn't catch any valid lang : we use the default settings
183                 if (isset($this->availableLanguages[DEFAULT_LANGUAGE])) {
184                         $language = $this->getLanguage(DEFAULT_LANGUAGE, DEFAULT_CHARSET);
185
186                         if ($language) {
187                                 return $language;
188                         }
189                 }
190
191                 // fail safe
192                 if (isset($this->availableLanguages[$this->default_lang])) {
193                         $language = $this->getLanguage($this->default_lang, $this->default_charset);
194
195                         if ($language) {
196                                 return $language;
197                         }
198                 }
199
200                 // else pick one at random:
201                 reset($this->availableLanguages);
202                 
203                 $unknown_language = current($this->availableLanguages);
204                 
205                 if (!$unknown_language) {
206                         return FALSE;
207                 }
208
209                 return current($unknown_language);
210         }
211
212         function getAvailableLanguages() {
213                 return $this->availableLanguages;
214         }
215
216         // public
217         function printDropdown($current_language, $name, $id) {
218                 echo '<select name="'.$name.'" id="'.$id.'">';
219
220                 foreach ($this->availableLanguages as $codes) {
221                         $language = current($codes);
222                         if ((defined('AT_DEVEL_TRANSLATE') && AT_DEVEL_TRANSLATE) || ($language->getStatus() == AT_LANG_STATUS_PUBLISHED)) {
223                                 echo '<option value="'.$language->getCode().'"';
224                                 if ($language->getCode() == $current_language) {
225                                         echo ' selected="selected"';
226                                 }
227                                 echo '>'.$language->getNativeName().'</option>';
228                         }
229                 }
230                 echo '</select>';
231         }
232
233         // public
234         function printList($current_language, $name, $id, $url) {
235
236                 $delim = false;
237                 foreach ($this->availableLanguages as $codes) {
238                         $language = current($codes);
239
240                         if ($language->getStatus() == AT_LANG_STATUS_PUBLISHED) {
241
242                                 if ($delim){
243                                         echo ' | ';
244                                 }
245
246                                 if ($language->getCode() == $current_language) {
247                                         echo '<strong>'.$language->getNativeName().'</strong>';
248                                 } else {
249                                         echo '<a href="'.$url.'lang='.$language->getCode().'">'.$language->getNativeName().'</a> ';
250                                 }
251
252                                 $delim = true;
253                         }
254                 }
255         }
256
257         // public
258         function getNumLanguages() {
259                 return $this->numLanguages;
260         }
261
262         // public
263         // checks whether or not the language exists/is available
264         function exists($code, $locale = '') {
265                 if ($locale) {
266                         return isset($this->availableLanguages[$code . AT_LANGUAGE_LOCALE_SEP . $locale]);
267                 }
268                 return isset($this->availableLanguages[$code]);
269         }
270
271         // public
272         // import language pack from specified file
273         function import($filename) {
274                 global $languageManager, $msg;
275
276                 $import_path = AT_CONTENT_DIR . 'import/';
277
278                 $archive = new PclZip($filename);
279                 if ($archive->extract(  PCLZIP_OPT_PATH,        $import_path) == 0) {
280                         exit('Error : ' . $archive->errorInfo(true));
281                 }
282
283                 $language_xml = @file_get_contents($import_path.'language.xml');
284
285                 $languageParser = new LanguageParser();
286                 $languageParser->parse($language_xml);
287                 $languageEditor = $languageParser->getLanguageEditor(0);
288
289                 if (($languageEditor->getAtutorVersion() != VERSION) 
290                         && (!defined('AT_DEVEL_TRANSLATE') || !AT_DEVEL_TRANSLATE)) 
291                         {
292                                 $msg->addError('LANG_WRONG_VERSION');
293                 }
294
295                 if (($languageEditor->getStatus() != AT_LANG_STATUS_PUBLISHED) 
296                         && ($languageEditor->getStatus() != AT_LANG_STATUS_COMPLETE) 
297                         && (!defined('AT_DEVEL_TRANSLATE') || !AT_DEVEL_TRANSLATE)) 
298                         {
299                                 $msg->addError('LANG_NOT_COMPLETE');
300                 }
301
302                 if ($languageManager->exists($languageEditor->getCode())) {
303                         $msg->addError('LANG_EXISTS');
304                 }
305
306                 if (!$msg->containsErrors()) {
307                         $languageEditor->import($import_path . 'language_text.sql');
308                         $msg->addFeedback('IMPORT_LANG_SUCCESS');
309                 }
310
311                 // remove the files:
312                 @unlink($import_path . 'language.xml');
313                 @unlink($import_path . 'language_text.sql');
314                 @unlink($import_path . 'readme.txt');
315                 @unlink($filename);
316         }
317
318         // public
319         // imports LIVE language from the atutor language database
320         function liveImport($language_code) {
321                 global $db;
322
323                 $tmp_lang_db = mysql_connect(AT_LANG_DB_HOST, AT_LANG_DB_USER, AT_LANG_DB_PASS);
324                 // set database connection using utf8
325                 mysql_query("SET NAMES 'utf8'", $tmp_lang_db);
326                 
327                 if (!$tmp_lang_db) {
328                         /* AT_ERROR_NO_DB_CONNECT */
329                         echo 'Unable to connect to db.';
330                         exit;
331                 }
332                 if (!mysql_select_db('dev_atutor_langs', $tmp_lang_db)) {
333                         echo 'DB connection established, but database "dev_atutor_langs" cannot be selected.';
334                         exit;
335                 }
336
337                 $sql = "SELECT * FROM languages_SVN WHERE language_code='$language_code'";
338                 $result = mysql_query($sql, $tmp_lang_db);
339
340                 if ($row = mysql_fetch_assoc($result)) {
341                         $row['reg_exp'] = addslashes($row['reg_exp']);
342                         $row['native_name'] = addslashes($row['native_name']);
343                         $row['english_name'] = addslashes($row['english_name']);
344
345                         $sql = "REPLACE INTO ".TABLE_PREFIX."languages VALUES ('{$row['language_code']}', '{$row['char_set']}', '{$row['direction']}', '{$row['reg_exp']}', '{$row['native_name']}', '{$row['english_name']}', 3)";
346                         $result = mysql_query($sql, $db);
347
348                         $sql = "SELECT * FROM language_text_SVN WHERE language_code='$language_code'";
349                         $result = mysql_query($sql, $tmp_lang_db);
350
351                         $sql = "REPLACE INTO ".TABLE_PREFIX."language_text VALUES ";
352                         while ($row = mysql_fetch_assoc($result)) {
353                                 $row['text'] = addslashes($row['text']);
354                                 $row['context'] = addslashes($row['context']);
355                                 $sql .= "('{$row['language_code']}', '{$row['variable']}', '{$row['term']}', '{$row['text']}', '{$row['revised_date']}', '{$row['context']}'),";
356                         }
357                         $sql = substr($sql, 0, -1);
358                         mysql_query($sql, $db);
359                 }
360         }
361         
362         function getXML() {
363                 global $db;
364
365                 $lang_xml = '<?xml version="1.0" encoding="iso-8859-1"?>
366                 <!-- These are ATutor language packs - http://www.atutor.ca-->
367
368                 <!DOCTYPE languages [
369                    <!ELEMENT language (atutor-version, code, charset, direction, reg-exp, native-name, english-name )>
370                    <!ELEMENT atutor-version (#PCDATA)>
371                    <!ELEMENT code (#PCDATA)>
372                    <!ELEMENT charset (#PCDATA)>
373                    <!ELEMENT direction (#PCDATA)>
374                    <!ELEMENT reg-exp (#PCDATA)>
375                    <!ELEMENT native-name (#PCDATA)>
376                    <!ELEMENT english-name (#PCDATA)>
377                    <!ELEMENT status (#PCDATA)>
378                    <!ATTLIST language code ID #REQUIRED>
379                 ]>
380
381                 <languages>';
382
383                 foreach ($this->availableLanguages as $codes) {
384                         foreach ($codes as $language) {
385                                 $lang_xml .= $language->getXML(TRUE);
386                         }
387                 }
388
389                 $lang_xml .= "\r\n".'</languages>';
390
391                 return $lang_xml;
392         }
393 }
394
395
396 ?>