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