112423d020b8b78ebacfc50d147c48bd747244e4
[atutor.git] / docs / 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$
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                 require_once(AT_INCLUDE_PATH.'classes/pclzip.lib.php');
277                 require_once(AT_INCLUDE_PATH.'../mods/_core/languages/classes/LanguagesParser.class.php');
278                 
279                 $import_path = AT_CONTENT_DIR . 'import/';
280
281                 $archive = new PclZip($filename);
282                 if ($archive->extract(  PCLZIP_OPT_PATH,        $import_path) == 0) {
283                         exit('Error : ' . $archive->errorInfo(true));
284                 }
285
286                 $language_xml = @file_get_contents($import_path.'language.xml');
287
288                 $languageParser = new LanguageParser();
289                 $languageParser->parse($language_xml);
290                 $languageEditor = $languageParser->getLanguageEditor(0);
291
292                 if (($languageEditor->getAtutorVersion() != VERSION) 
293                         && (!defined('AT_DEVEL_TRANSLATE') || !AT_DEVEL_TRANSLATE)) 
294                         {
295                                 $msg->addError('LANG_WRONG_VERSION');
296                 }
297
298                 if (($languageEditor->getStatus() != AT_LANG_STATUS_PUBLISHED) 
299                         && ($languageEditor->getStatus() != AT_LANG_STATUS_COMPLETE) 
300                         && (!defined('AT_DEVEL_TRANSLATE') || !AT_DEVEL_TRANSLATE)) 
301                         {
302                                 $msg->addError('LANG_NOT_COMPLETE');
303                 }
304
305                 if ($languageManager->exists($languageEditor->getCode())) {
306                         $msg->addError('LANG_EXISTS');
307                 }
308
309                 if (!$msg->containsErrors()) {
310                         $languageEditor->import($import_path . 'language_text.sql');
311                         $msg->addFeedback('IMPORT_LANG_SUCCESS');
312                 }
313
314                 // remove the files:
315                 @unlink($import_path . 'language.xml');
316                 @unlink($import_path . 'language_text.sql');
317                 @unlink($import_path . 'readme.txt');
318                 @unlink($filename);
319         }
320
321         // public
322         // imports LIVE language from the atutor language database
323         function liveImport($language_code) {
324                 global $msg;
325                 
326                 $zip_file_content = @file_get_contents(AT_LIVE_LANG_PACK_URL.$language_code);
327                 
328                 if (!$zip_file_content || substr($zip_file_content, 0, 6) == "Error:") {
329                         $msg->addError(array('REMOTE_ERROR', $zip_file_content));
330                         return;
331                 }
332                 
333                 // write the downloaded language pack into a temporary file for pclzip to unpack
334                 $lang_pack_zip = AT_CONTENT_DIR . 'import/'.md5(time()).'.zip';
335                 $fp = fopen($lang_pack_zip, 'w');
336                 fwrite($fp, $zip_file_content);
337                 fclose($fp);
338                 
339                 $this->import($lang_pack_zip);
340                 @unlink($lang_pack_zip);
341         }
342         
343         function getXML() {
344                 global $db;
345
346                 $lang_xml = '<?xml version="1.0" encoding="iso-8859-1"?>
347                 <!-- These are ATutor language packs - http://www.atutor.ca-->
348
349                 <!DOCTYPE languages [
350                    <!ELEMENT language (atutor-version, code, charset, direction, reg-exp, native-name, english-name )>
351                    <!ELEMENT atutor-version (#PCDATA)>
352                    <!ELEMENT code (#PCDATA)>
353                    <!ELEMENT charset (#PCDATA)>
354                    <!ELEMENT direction (#PCDATA)>
355                    <!ELEMENT reg-exp (#PCDATA)>
356                    <!ELEMENT native-name (#PCDATA)>
357                    <!ELEMENT english-name (#PCDATA)>
358                    <!ELEMENT status (#PCDATA)>
359                    <!ATTLIST language code ID #REQUIRED>
360                 ]>
361
362                 <languages>';
363
364                 foreach ($this->availableLanguages as $codes) {
365                         foreach ($codes as $language) {
366                                 $lang_xml .= $language->getXML(TRUE);
367                         }
368                 }
369
370                 $lang_xml .= "\r\n".'</languages>';
371
372                 return $lang_xml;
373         }
374 }
375
376
377 ?>