ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilObjLanguage.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once "./Services/Object/classes/class.ilObject.php";
5 
14 class ilObjLanguage extends ilObject
15 {
28 
29  var $key;
30  var $status;
31 
32 
40  function ilObjLanguage($a_id = 0, $a_call_by_reference = false)
41  {
42  global $lng;
43 
44  $this->type = "lng";
45  $this->ilObject($a_id,$a_call_by_reference);
46 
47  $this->type = "lng";
48  $this->key = $this->title;
49  $this->status = $this->desc;
50  $this->lang_default = $lng->lang_default;
51  $this->lang_user = $lng->lang_user;
52  $this->lang_path = $lng->lang_path;
53  $this->cust_lang_path = $lng->cust_lang_path;
54  $this->separator = $lng->separator;
55  $this->comment_separator = $lng->comment_separator;
56  }
57 
63  function getKey()
64  {
65  return $this->key;
66  }
67 
73  function getStatus()
74  {
75  return $this->status;
76  }
77 
81  function isSystemLanguage()
82  {
83  if ($this->key == $this->lang_default)
84  return true;
85  else
86  return false;
87  }
88 
92  function isUserLanguage()
93  {
94  if ($this->key == $this->lang_user)
95  {
96  return true;
97  }
98  else
99  {
100  return false;
101  }
102  }
103 
104 
110  function isInstalled()
111  {
112  if (substr($this->getStatus(), 0, 9) == "installed")
113  {
114  return true;
115  }
116  else
117  {
118  return false;
119  }
120  }
121 
128  function isLocal()
129  {
130  if (substr($this->getStatus(), 10) == "local")
131  {
132  return true;
133  }
134  else
135  {
136  return false;
137  }
138  }
139 
146  function install($scope = '')
147  {
148  if (!empty($scope))
149  {
150  if ($scope == 'global')
151  {
152  $scope = '';
153  }
154  else
155  {
156  $scopeExtension = '.' . $scope;
157  }
158  }
159 
160  if (($this->isInstalled() == false) ||
161  ($this->isInstalled() == true && $this->isLocal() == false && !empty($scope)))
162  {
163  if ($this->check($scope))
164  {
165  // lang-file is ok. Flush data in db and...
166  if (empty($scope))
167  {
168  $this->flush('keep_local');
169  }
170 
171  // ...re-insert data from lang-file
172  $this->insert($scope);
173 
174  // update information in db-table about available/installed languages
175  if (empty($scope))
176  {
177  $newDesc = 'installed';
178  }
179  else if ($scope == 'local')
180  {
181  $newDesc = 'installed_local';
182  }
183  $this->setDescription($newDesc);
184  $this->update();
185  $this->optimizeData();
186  return $this->getKey();
187  }
188  }
189  return "";
190  }
191 
192 
198  function uninstall()
199  {
200  if ((substr($this->status, 0, 9) == "installed") && ($this->key != $this->lang_default) && ($this->key != $this->lang_user))
201  {
202  $this->flush('all');
203  $this->setTitle($this->key);
204  $this->setDescription("not_installed");
205  $this->update();
206  $this->resetUserLanguage($this->key);
207 
208  return $this->key;
209  }
210  return "";
211  }
212 
216  static function refreshAll()
217  {
218  global $ilPluginAdmin;
219 
220  $languages = ilObject::_getObjectsByType("lng");
221 
222  foreach ($languages as $lang)
223  {
224  $langObj = new ilObjLanguage($lang["obj_id"],false);
225 
226  if ($langObj->isInstalled() == true)
227  {
228  if ($langObj->check())
229  {
230  $langObj->flush('keep_local');
231  $langObj->insert();
232  $langObj->setTitle($langObj->getKey());
233  $langObj->setDescription($langObj->getStatus());
234  $langObj->update();
235  $langObj->optimizeData();
236 
237  if ($langObj->isLocal() == true)
238  {
239  if ($langObj->check('local'))
240  {
241  $langObj->insert('local');
242  $langObj->setTitle($langObj->getKey());
243  $langObj->setDescription($langObj->getStatus());
244  $langObj->update();
245  $langObj->optimizeData();
246  }
247  }
248  }
249  }
250 
251  unset($langObj);
252  }
253 
254  // refresh languages of activated plugins
255  include_once("./Services/Component/classes/class.ilPluginSlot.php");
256  $slots = ilPluginSlot::getAllSlots();
257  foreach ($slots as $slot)
258  {
259  $act_plugins = $ilPluginAdmin->getActivePluginsForSlot($slot["component_type"],
260  $slot["component_name"], $slot["slot_id"]);
261  foreach ($act_plugins as $plugin)
262  {
263  include_once("./Services/Component/classes/class.ilPlugin.php");
264  $pl = ilPlugin::getPluginObject($slot["component_type"],
265  $slot["component_name"], $slot["slot_id"], $plugin);
266  if (is_object($pl))
267  {
268  $pl->updateLanguages();
269  }
270  }
271  }
272  }
273 
274 
280  static function _deleteLangData($a_lang_key, $a_keep_local_change)
281  {
282  global $ilDB;
283  if (!$a_keep_local_change)
284  {
285  $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = ".
286  $ilDB->quote($a_lang_key, "text"));
287  }
288  else
289  {
290  $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = ".
291  $ilDB->quote($a_lang_key, "text").
292  " AND local_change IS NULL");
293  }
294  }
295 
300  function flush($a_mode = 'all')
301  {
302  global $ilDB;
303 
304  ilObjLanguage::_deleteLangData($this->key, ($a_mode == 'keep_local'));
305 
306  if ($a_mode == 'all')
307  {
308  $ilDB->manipulate("DELETE FROM lng_modules WHERE lang_key = ".
309  $ilDB->quote($this->key, "text"));
310  }
311  }
312 
313 
320  function getLocalChanges($a_min_date = "", $a_max_date = "")
321  {
322  global $ilDB;
323 
324  if ($a_min_date == "")
325  {
326  $a_min_date = "1980-01-01 00:00:00";
327  }
328  if ($a_max_date == "")
329  {
330  $a_max_date = "2200-01-01 00:00:00";
331  }
332 
333  $q = sprintf("SELECT * FROM lng_data WHERE lang_key = %s ".
334  "AND local_change >= %s AND local_change <= %s",
335  $ilDB->quote($this->key, "text"), $ilDB->quote($a_min_date, "timestamp"),
336  $ilDB->quote($a_max_date, "timestamp"));
337  $result = $ilDB->query($q);
338 
339  $changes = array();
340  while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
341  {
342  $changes[$row["module"]][$row["identifier"]] = $row["value"];
343  }
344  return $changes;
345  }
346 
347 
353  function _getLastLocalChange($a_key)
354  {
355  global $ilDB;
356 
357  $q = sprintf("SELECT MAX(local_change) last_change FROM lng_data ".
358  "WHERE lang_key = %s AND local_change IS NOT NULL",
359  $ilDB->quote($a_key, "text"));
360  $result = $ilDB->query($q);
361 
362  if ($row = $result->fetchRow(DB_FETCHMODE_ASSOC))
363  {
364  return $row['last_change'];
365  }
366  else
367  {
368  return "";
369  }
370  }
371 
372 
378  function insert($scope = '')
379  {
380  global $ilDB;
381 
382  if (!empty($scope))
383  {
384  if ($scope == 'global')
385  {
386  $scope = '';
387  }
388  else
389  {
390  $scopeExtension = '.' . $scope;
391  }
392  }
393 
395  if ($scope == "local")
396  {
397  $path = $this->cust_lang_path;
398  }
399 
400  $tmpPath = getcwd();
401  chdir($path);
402 
403  $lang_file = "ilias_" . $this->key . ".lang" . $scopeExtension;
404 
405  if ($lang_file)
406  {
407  // initialize the array for updating lng_modules below
408  $lang_array = array();
409  $lang_array["common"] = array();
410 
411  // remove header first
412  if ($content = $this->cut_header(file($lang_file)))
413  {
414  if (empty($scope))
415  {
416  // reset change date for a global file
417  // get all local changes for a global file
418  $change_date = null;
419  $local_changes = $this->getLocalChanges();
420  }
421  else if ($scope == 'local')
422  {
423  // set the change date to import time for a local file
424  // get the modification date of the local file
425  // get the newer local changes for a local file
426  $change_date = date("Y-m-d H:i:s",time());
427  $min_date = date("Y-m-d H:i:s", filemtime($lang_file));
428  $local_changes = $this->getLocalChanges($min_date);
429  }
430 
431  foreach ($content as $key => $val)
432  {
433  // split the line of the language file
434  // [0]: module
435  // [1]: identifier
436  // [2]: value
437  // [3]: comment (optional)
438  $separated = explode($this->separator,trim($val));
439  $pos = strpos($separated[2], $this->comment_separator);
440  if ($pos !== false)
441  {
442  $separated[3] = substr($separated[2], $pos + strlen($this->comment_separator));
443  $separated[2] = substr($separated[2] , 0 , $pos);
444  }
445 
446  // check if the value has a local change
447  $local_value = $local_changes[$separated[0]][$separated[1]];
448 
449  if (empty($scope))
450  {
451  // import of a global language file
452 
453  if ($local_value != "" and $local_value != $separated[2])
454  {
455  // keep an existing and different local calue
456  $lang_array[$separated[0]][$separated[1]] = $local_value;
457  }
458  else
459  {
460  // check for double entries in global file
461  if ($double_checker[$separated[0]][$separated[1]][$this->key])
462  {
463  $this->ilias->raiseError("Duplicate Language Entry in $lang_file:\n$val",
464  $this->ilias->error_obj->MESSAGE);
465  }
466  $double_checker[$separated[0]][$separated[1]][$this->key] = true;
467 
468  // insert a new value if no local value exists
469  // reset local change date if the values are equal
470  ilObjLanguage::replaceLangEntry($separated[0], $separated[1],
471  $this->key, $separated[2], $change_date, $separated[3]);
472 
473  $lang_array[$separated[0]][$separated[1]] = $separated[2];
474  }
475  }
476  else if ($scope == 'local')
477  {
478  // import of a local language file
479 
480  if ($local_value != "")
481  {
482  // keep a locally changed value that is newer than the file
483  $lang_array[$separated[0]][$separated[1]] = $local_value;
484  }
485  else
486  {
487  // insert a new value if no global value exists
488  // (local files may have additional entries for customizations)
489  // set the change date to the import date
490  ilObjLanguage::replaceLangEntry($separated[0], $separated[1],
491  $this->key, $separated[2], $change_date, $separated[3]);
492 
493  $lang_array[$separated[0]][$separated[1]] = $separated[2];
494  }
495  }
496  }
497 
498  $ld = "";
499  if (empty($scope))
500  {
501  $ld = "installed";
502  }
503  else if ($scope == 'local')
504  {
505  $ld = "installed_local";
506  }
507  if ($ld)
508  {
509  $query = "UPDATE object_data SET " .
510  "description = ".$ilDB->quote($ld, "text").", " .
511  "last_update = ".$ilDB->now()." " .
512  "WHERE title = ".$ilDB->quote($this->key, "text")." " .
513  "AND type = 'lng'";
514  $ilDB->manipulate($query);
515  }
516  }
517 
518  foreach($lang_array as $module => $lang_arr)
519  {
520  if ($scope == "local")
521  {
522  $q = "SELECT * FROM lng_modules WHERE ".
523  " lang_key = ".$ilDB->quote($this->key, "text").
524  " AND module = ".$ilDB->quote($module, "text");
525  $set = $ilDB->query($q);
526  $row = $ilDB->fetchAssoc($set);
527  $arr2 = unserialize($row["lang_array"]);
528  if (is_array($arr2))
529  {
530  $lang_arr = array_merge($arr2, $lang_arr);
531  }
532  }
533  ilObjLanguage::replaceLangModule($this->key, $module, $lang_arr);
534  }
535  }
536 
537  chdir($tmpPath);
538  }
539 
543  static final function replaceLangModule($a_key, $a_module, $a_array)
544  {
545  global $ilDB;
546 
547  ilGlobalCache::flushAll();
548 
549  $ilDB->manipulate(sprintf("DELETE FROM lng_modules WHERE lang_key = %s AND module = %s",
550  $ilDB->quote($a_key, "text"), $ilDB->quote($a_module, "text")));
551 
552  /*$ilDB->manipulate(sprintf("INSERT INTO lng_modules (lang_key, module, lang_array) VALUES ".
553  "(%s,%s,%s)", $ilDB->quote($a_key, "text"),
554  $ilDB->quote($a_module, "text"),
555  $ilDB->quote(serialize($a_array), "clob")));*/
556  $ilDB->insert("lng_modules", array(
557  "lang_key" => array("text", $a_key),
558  "module" => array("text", $a_module),
559  "lang_array" => array("clob", serialize($a_array))
560  ));
561  }
562 
566  static final function replaceLangEntry($a_module, $a_identifier,
567  $a_lang_key, $a_value, $a_local_change = null, $a_remarks = null)
568  {
569  global $ilDB;
570 
571  ilGlobalCache::flushAll();
572 
573  if (isset($a_remarks))
574  {
575  $a_remarks = substr($a_remarks, 0, 250);
576  }
577  if ($a_remarks == '')
578  {
579  unset($a_remarks);
580  }
581 
582  if (isset($a_value))
583  {
584  $a_value = substr($a_value, 0, 4000);
585  }
586  if ($a_value == '')
587  {
588  unset($a_value);
589  }
590 
591  $ilDB->replace(
592  'lng_data',
593  array(
594  'module' => array('text',$a_module),
595  'identifier' => array('text',$a_identifier),
596  'lang_key' => array('text',$a_lang_key)
597  ),
598  array(
599  'value' => array('text',$a_value),
600  'local_change' => array('timestamp',$a_local_change),
601  'remarks' => array('text', $a_remarks)
602  )
603  );
604  return true;
605 
606  /*
607  $ilDB->manipulate(sprintf("DELETE FROM lng_data WHERE module = %s AND ".
608  "identifier = %s AND lang_key = %s",
609  $ilDB->quote($a_module, "text"), $ilDB->quote($a_identifier, "text"),
610  $ilDB->quote($a_lang_key, "text")));
611 
612 
613  $ilDB->manipulate(sprintf("INSERT INTO lng_data " .
614  "(module, identifier, lang_key, value, local_change) " .
615  "VALUES (%s,%s,%s,%s,%s)",
616  $ilDB->quote($a_module, "text"), $ilDB->quote($a_identifier, "text"),
617  $ilDB->quote($a_lang_key, "text"), $ilDB->quote($a_value, "text"),
618  $ilDB->quote($a_local_change, "timestamp")));
619  */
620  }
621 
625  static final function updateLangEntry($a_module, $a_identifier,
626  $a_lang_key, $a_value, $a_local_change = null, $a_remarks = null)
627  {
628  global $ilDB;
629 
630  if (isset($a_remarks))
631  {
632  $a_remarks = substr($a_remarks, 0, 250);
633  }
634  if ($a_remarks == '')
635  {
636  unset($a_remarks);
637  }
638 
639  if (isset($a_value))
640  {
641  $a_value = substr($a_value, 0, 4000);
642  }
643  if ($a_value == '')
644  {
645  unset($a_value);
646  }
647 
648  $ilDB->manipulate(sprintf("UPDATE lng_data " .
649  "SET value = %s, local_change = %s, remarks = %s ".
650  "WHERE module = %s AND identifier = %s AND lang_key = %s ",
651  $ilDB->quote($a_value, "text"), $ilDB->quote($a_local_change, "timestamp"),
652  $ilDB->quote($a_remarks, "text"),
653  $ilDB->quote($a_module, "text"), $ilDB->quote($a_identifier, "text"),
654  $ilDB->quote($a_lang_key, "text")));
655  }
656 
657 
661  static final function deleteLangEntry($a_module, $a_identifier, $a_lang_key)
662  {
663  global $ilDB;
664 
665  $ilDB->manipulate(sprintf("DELETE FROM lng_data " .
666  "WHERE module = %s AND identifier = %s AND lang_key = %s ",
667  $ilDB->quote($a_module, "text"),
668  $ilDB->quote($a_identifier, "text"),
669  $ilDB->quote($a_lang_key, "text")));
670 
671  return true;
672  }
673 
674 
681  function resetUserLanguage($lang_key)
682  {
683  global $ilDB;
684 
685  $query = "UPDATE usr_pref SET " .
686  "value = ".$ilDB->quote($this->lang_default, "text")." " .
687  "WHERE keyword = ".$ilDB->quote('language', "text")." ".
688  "AND value = ".$ilDB->quote($lang_key, "text");
689  $ilDB->manipulate($query);
690  }
691 
700  function cut_header($content)
701  {
702  foreach ($content as $key => $val)
703  {
704  if (trim($val) == "<!-- language file start -->")
705  {
706  return array_slice($content,$key +1);
707  }
708  }
709 
710  return false;
711  }
712 
718  function optimizeData()
719  {
720  global $ilDB;
721 
722  $ilDB->optimizeTable("lng_data");
723  return true;
724  }
725 
735  function check($scope = '')
736  {
737  include_once("./Services/Utilities/classes/class.ilStr.php");
738 
739  if (!empty($scope))
740  {
741  if ($scope == 'global')
742  {
743  $scope = '';
744  }
745  else
746  {
747  $scopeExtension = '.' . $scope;
748  }
749  }
750 
752  if ($scope == "local")
753  {
754  $path = $this->cust_lang_path;
755  }
756 
757  $tmpPath = getcwd();
758 
759  // dir check
760  if (!is_dir($path))
761  {
762  $this->ilias->raiseError("Directory not found: ".$path, $this->ilias->error_obj->MESSAGE);
763  }
764 
765  chdir($path);
766 
767  // compute lang-file name format
768  $lang_file = "ilias_" . $this->key . ".lang" . $scopeExtension;
769 
770  // file check
771  if (!is_file($lang_file))
772  {
773  $this->ilias->raiseError("File not found: ".$lang_file,$this->ilias->error_obj->MESSAGE);
774  }
775 
776  // header check
777  $content = $this->cut_header(file($lang_file));
778  if ($content === false)
779  {
780  $this->ilias->raiseError("Wrong Header in ".$lang_file,$this->ilias->error_obj->MESSAGE);
781  }
782 
783  // check (counting) elements of each lang-entry
784  $line = 0;
785  foreach ($content as $key => $val)
786  {
787  $separated = explode($this->separator, trim($val));
788  $num = count($separated);
789  ++$n;
790  if ($num != 3)
791  {
792  $line = $n + 36;
793  $this->ilias->raiseError("Wrong parameter count in ".$lang_file." in line $line (Value: $val)! Please check your language file!",$this->ilias->error_obj->MESSAGE);
794  }
795  if (!ilStr::isUtf8($separated[2]))
796  {
797  $this->ilias->raiseError("Non UTF8 character found in ".$lang_file." in line $line (Value: $val)! Please check your language file!",$this->ilias->error_obj->MESSAGE);
798  }
799  }
800 
801  chdir($tmpPath);
802 
803  // no error occured
804  return true;
805  }
806 
810  static function countUsers($a_lang)
811  {
812  global $ilDB, $lng;
813 
814  $set = $ilDB->query("SELECT COUNT(*) cnt FROM usr_data ud JOIN usr_pref up".
815  " ON ud.usr_id = up.usr_id ".
816  " WHERE up.value = ".$ilDB->quote($a_lang, "text").
817  " AND up.keyword = ".$ilDB->quote("language", "text"));
818  $rec = $ilDB->fetchAssoc($set);
819 
820  // add users with no usr_pref set to default language
821  if ($a_lang == $lng->lang_default)
822  {
823  $set2 = $ilDB->query("SELECT COUNT(*) cnt FROM usr_data ud LEFT JOIN usr_pref up".
824  " ON (ud.usr_id = up.usr_id AND up.keyword = ".$ilDB->quote("language", "text").")".
825  " WHERE up.value IS NULL ");
826  $rec2 = $ilDB->fetchAssoc($set2);
827  }
828 
829  return (int) $rec["cnt"] + (int) $rec2["cnt"];
830  }
831 
832 
833 } // END class.LanguageObject
834 ?>