ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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 {
23  public $separator;
25  public $lang_default;
26  public $lang_user;
27  public $lang_path;
28 
29  public $key;
30  public $status;
31 
32 
40  public function __construct($a_id = 0, $a_call_by_reference = false)
41  {
42  global $lng;
43 
44  $this->type = "lng";
45  parent::__construct($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 
58 
63  public static function getInstalledLanguages()
64  {
65  $objects = array();
66  $languages = ilObject::_getObjectsByType("lng");
67  foreach ($languages as $lang) {
68  $langObj = new ilObjLanguage($lang["obj_id"], false);
69  if ($langObj->isInstalled()) {
70  $objects[] = $langObj;
71  } else {
72  unset($langObj);
73  }
74  }
75  return $objects;
76  }
77 
78 
84  public function getKey()
85  {
86  return $this->key;
87  }
88 
94  public function getStatus()
95  {
96  return $this->status;
97  }
98 
102  public function isSystemLanguage()
103  {
104  if ($this->key == $this->lang_default) {
105  return true;
106  } else {
107  return false;
108  }
109  }
110 
114  public function isUserLanguage()
115  {
116  if ($this->key == $this->lang_user) {
117  return true;
118  } else {
119  return false;
120  }
121  }
122 
123 
129  public function isInstalled()
130  {
131  if (substr($this->getStatus(), 0, 9) == "installed") {
132  return true;
133  } else {
134  return false;
135  }
136  }
137 
144  public function isLocal()
145  {
146  if (substr($this->getStatus(), 10) == "local") {
147  return true;
148  } else {
149  return false;
150  }
151  }
152 
159  public function install($scope = '')
160  {
161  if (!empty($scope)) {
162  if ($scope == 'global') {
163  $scope = '';
164  } else {
165  $scopeExtension = '.' . $scope;
166  }
167  }
168 
169  if (($this->isInstalled() == false) ||
170  ($this->isInstalled() == true && $this->isLocal() == false && !empty($scope))) {
171  if ($this->check($scope)) {
172  // lang-file is ok. Flush data in db and...
173  if (empty($scope)) {
174  $this->flush('keep_local');
175  }
176 
177  // ...re-insert data from lang-file
178  $this->insert($scope);
179 
180  // update information in db-table about available/installed languages
181  if (empty($scope)) {
182  $newDesc = 'installed';
183  } elseif ($scope == 'local') {
184  $newDesc = 'installed_local';
185  }
186  $this->setDescription($newDesc);
187  $this->update();
188  return $this->getKey();
189  }
190  }
191  return "";
192  }
193 
194 
200  public function uninstall()
201  {
202  if ((substr($this->status, 0, 9) == "installed") && ($this->key != $this->lang_default) && ($this->key != $this->lang_user)) {
203  $this->flush('all');
204  $this->setTitle($this->key);
205  $this->setDescription("not_installed");
206  $this->update();
207  $this->resetUserLanguage($this->key);
208 
209  return $this->key;
210  }
211  return "";
212  }
213 
214 
219  public function refresh()
220  {
221  if ($this->isInstalled() == true) {
222  if ($this->check()) {
223  $this->flush('keep_local');
224  $this->insert();
225  $this->setTitle($this->getKey());
226  $this->setDescription($this->getStatus());
227  $this->update();
228 
229  if ($this->isLocal() == true) {
230  if ($this->check('local')) {
231  $this->insert('local');
232  $this->setTitle($this->getKey());
233  $this->setDescription($this->getStatus());
234  $this->update();
235  }
236  }
237  return true;
238  }
239  }
240  return false;
241  }
242 
246  public static function refreshAll()
247  {
248  $languages = ilObject::_getObjectsByType("lng");
249  $refreshed = array();
250 
251  foreach ($languages as $lang) {
252  $langObj = new ilObjLanguage($lang["obj_id"], false);
253  if ($langObj->refresh()) {
254  $refreshed[] = $langObj->getKey();
255  }
256  unset($langObj);
257  }
258 
259  self::refreshPlugins($refreshed);
260  }
261 
262 
267  public static function refreshPlugins($a_lang_keys = null)
268  {
269  global $ilPluginAdmin;
270 
271  // refresh languages of activated plugins
272  include_once("./Services/Component/classes/class.ilPluginSlot.php");
273  $slots = ilPluginSlot::getAllSlots();
274  foreach ($slots as $slot) {
275  $act_plugins = $ilPluginAdmin->getActivePluginsForSlot(
276  $slot["component_type"],
277  $slot["component_name"],
278  $slot["slot_id"]
279  );
280  foreach ($act_plugins as $plugin) {
281  include_once("./Services/Component/classes/class.ilPlugin.php");
283  $slot["component_type"],
284  $slot["component_name"],
285  $slot["slot_id"],
286  $plugin
287  );
288  if (is_object($pl)) {
289  $pl->updateLanguages($a_lang_keys);
290  }
291  }
292  }
293  }
294 
295 
301  public static function _deleteLangData($a_lang_key, $a_keep_local_change = false)
302  {
303  global $ilDB;
304  if (!$a_keep_local_change) {
305  $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = " .
306  $ilDB->quote($a_lang_key, "text"));
307  } else {
308  $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = " .
309  $ilDB->quote($a_lang_key, "text") .
310  " AND local_change IS NULL");
311  }
312  }
313 
318  public function flush($a_mode = 'all')
319  {
320  global $ilDB;
321 
322  ilObjLanguage::_deleteLangData($this->key, ($a_mode == 'keep_local'));
323 
324  if ($a_mode == 'all') {
325  $ilDB->manipulate("DELETE FROM lng_modules WHERE lang_key = " .
326  $ilDB->quote($this->key, "text"));
327  }
328  }
329 
330 
337  public function getLocalChanges($a_min_date = "", $a_max_date = "")
338  {
339  global $ilDB;
340 
341  if ($a_min_date == "") {
342  $a_min_date = "1980-01-01 00:00:00";
343  }
344  if ($a_max_date == "") {
345  $a_max_date = "2200-01-01 00:00:00";
346  }
347 
348  $q = sprintf(
349  "SELECT * FROM lng_data WHERE lang_key = %s " .
350  "AND local_change >= %s AND local_change <= %s",
351  $ilDB->quote($this->key, "text"),
352  $ilDB->quote($a_min_date, "timestamp"),
353  $ilDB->quote($a_max_date, "timestamp")
354  );
355  $result = $ilDB->query($q);
356 
357  $changes = array();
358  while ($row = $result->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
359  $changes[$row["module"]][$row["identifier"]] = $row["value"];
360  }
361  return $changes;
362  }
363 
364 
370  public static function _getLastLocalChange($a_key)
371  {
372  global $ilDB;
373 
374  $q = sprintf(
375  "SELECT MAX(local_change) last_change FROM lng_data " .
376  "WHERE lang_key = %s AND local_change IS NOT NULL",
377  $ilDB->quote($a_key, "text")
378  );
379  $result = $ilDB->query($q);
380 
381  if ($row = $result->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
382  return $row['last_change'];
383  } else {
384  return "";
385  }
386  }
387 
388 
395  public static function _getLocalChangesByModule($a_key, $a_module)
396  {
398  global $ilDB;
399 
400  $changes = array();
401  $result = $ilDB->queryF(
402  "SELECT * FROM lng_data WHERE lang_key = %s AND module = %s AND local_change IS NOT NULL",
403  array('text', 'text'),
404  array($a_key, $a_module)
405  );
406 
407  while ($row = $ilDB->fetchAssoc($result)) {
408  $changes[$row['identifier']] = $row['value'];
409  }
410  return $changes;
411  }
412 
413 
419  public function insert($scope = '')
420  {
421  global $ilDB;
422 
423  if (!empty($scope)) {
424  if ($scope == 'global') {
425  $scope = '';
426  } else {
427  $scopeExtension = '.' . $scope;
428  }
429  }
430 
432  if ($scope == "local") {
433  $path = $this->cust_lang_path;
434  }
435 
436  $lang_file = $path . "/ilias_" . $this->key . ".lang" . $scopeExtension;
437 
438  if (is_file($lang_file)) {
439  // initialize the array for updating lng_modules below
440  $lang_array = array();
441  $lang_array["common"] = array();
442 
443  // remove header first
444  if ($content = $this->cut_header(file($lang_file))) {
445  if (empty($scope)) {
446  // reset change date for a global file
447  // get all local changes for a global file
448  $change_date = null;
449  $local_changes = $this->getLocalChanges();
450  } elseif ($scope == 'local') {
451  // set the change date to import time for a local file
452  // get the modification date of the local file
453  // get the newer local changes for a local file
454  $change_date = date("Y-m-d H:i:s", time());
455  $min_date = date("Y-m-d H:i:s", filemtime($lang_file));
456  $local_changes = $this->getLocalChanges($min_date);
457  }
458 
459  foreach ($content as $key => $val) {
460  // split the line of the language file
461  // [0]: module
462  // [1]: identifier
463  // [2]: value
464  // [3]: comment (optional)
465  $separated = explode($this->separator, trim($val));
466  $pos = strpos($separated[2], $this->comment_separator);
467  if ($pos !== false) {
468  $separated[3] = substr($separated[2], $pos + strlen($this->comment_separator));
469  $separated[2] = substr($separated[2], 0, $pos);
470  }
471 
472  // check if the value has a local change
473  $local_value = $local_changes[$separated[0]][$separated[1]];
474 
475  if (empty($scope)) {
476  // import of a global language file
477 
478  if ($local_value != "" and $local_value != $separated[2]) {
479  // keep an existing and different local calue
480  $lang_array[$separated[0]][$separated[1]] = $local_value;
481  } else {
482  // check for double entries in global file
483  if ($double_checker[$separated[0]][$separated[1]][$this->key]) {
484  $this->ilias->raiseError(
485  "Duplicate Language Entry in $lang_file:\n$val",
486  $this->ilias->error_obj->MESSAGE
487  );
488  }
489  $double_checker[$separated[0]][$separated[1]][$this->key] = true;
490 
491  // insert a new value if no local value exists
492  // reset local change date if the values are equal
494  $separated[0],
495  $separated[1],
496  $this->key,
497  $separated[2],
498  $change_date,
499  $separated[3]
500  );
501 
502  $lang_array[$separated[0]][$separated[1]] = $separated[2];
503  }
504  } elseif ($scope == 'local') {
505  // import of a local language file
506 
507  if ($local_value != "") {
508  // keep a locally changed value that is newer than the file
509  $lang_array[$separated[0]][$separated[1]] = $local_value;
510  } else {
511  // insert a new value if no global value exists
512  // (local files may have additional entries for customizations)
513  // set the change date to the import date
515  $separated[0],
516  $separated[1],
517  $this->key,
518  $separated[2],
519  $change_date,
520  $separated[3]
521  );
522 
523  $lang_array[$separated[0]][$separated[1]] = $separated[2];
524  }
525  }
526  }
527 
528  $ld = "";
529  if (empty($scope)) {
530  $ld = "installed";
531  } elseif ($scope == 'local') {
532  $ld = "installed_local";
533  }
534  if ($ld) {
535  $query = "UPDATE object_data SET " .
536  "description = " . $ilDB->quote($ld, "text") . ", " .
537  "last_update = " . $ilDB->now() . " " .
538  "WHERE title = " . $ilDB->quote($this->key, "text") . " " .
539  "AND type = 'lng'";
540  $ilDB->manipulate($query);
541  }
542  }
543 
544  foreach ($lang_array as $module => $lang_arr) {
545  if ($scope == "local") {
546  $q = "SELECT * FROM lng_modules WHERE " .
547  " lang_key = " . $ilDB->quote($this->key, "text") .
548  " AND module = " . $ilDB->quote($module, "text");
549  $set = $ilDB->query($q);
550  $row = $ilDB->fetchAssoc($set);
551  $arr2 = unserialize($row["lang_array"]);
552  if (is_array($arr2)) {
553  $lang_arr = array_merge($arr2, $lang_arr);
554  }
555  }
556  ilObjLanguage::replaceLangModule($this->key, $module, $lang_arr);
557  }
558  }
559  }
560 
564  final public static function replaceLangModule($a_key, $a_module, $a_array)
565  {
566  global $DIC;
567  $ilDB = $DIC->database();
568 
569  ilGlobalCache::flushAll();
570 
571  $ilDB->manipulate(sprintf(
572  "DELETE FROM lng_modules WHERE lang_key = %s AND module = %s",
573  $ilDB->quote($a_key, "text"),
574  $ilDB->quote($a_module, "text")
575  ));
576 
577  /*$ilDB->manipulate(sprintf("INSERT INTO lng_modules (lang_key, module, lang_array) VALUES ".
578  "(%s,%s,%s)", $ilDB->quote($a_key, "text"),
579  $ilDB->quote($a_module, "text"),
580  $ilDB->quote(serialize($a_array), "clob")));*/
581  $ilDB->insert("lng_modules", array(
582  "lang_key" => array("text", $a_key),
583  "module" => array("text", $a_module),
584  "lang_array" => array("clob", serialize((array) $a_array))
585  ));
586 
587  // check if the module is correctly saved
588  // see mantis #20046 and #19140
589  $result = $ilDB->queryF(
590  "SELECT lang_array FROM lng_modules WHERE lang_key = %s AND module = %s",
591  array('text','text'),
592  array($a_key, $a_module)
593  );
594  $row = $ilDB->fetchAssoc($result);
595 
596  $unserialied = unserialize($row['lang_array']);
597  if (!is_array($unserialied)) {
599  $ilErr = $DIC['ilErr'];
600  $ilErr->raiseError(
601  "Data for module '" . $a_module . "' of language '" . $a_key . "' is not correctly saved. " .
602  "Please check the collation of your database tables lng_data and lng_modules. It must be utf8_unicode_ci.",
603  $ilErr->MESSAGE
604  );
605  }
606  }
607 
611  final public static function replaceLangEntry(
612  $a_module,
613  $a_identifier,
614  $a_lang_key,
615  $a_value,
616  $a_local_change = null,
617  $a_remarks = null
618  ) {
619  global $ilDB;
620 
621  ilGlobalCache::flushAll();
622 
623  if (isset($a_remarks)) {
624  $a_remarks = substr($a_remarks, 0, 250);
625  }
626  if ($a_remarks == '') {
627  unset($a_remarks);
628  }
629 
630  if (isset($a_value)) {
631  $a_value = substr($a_value, 0, 4000);
632  }
633  if ($a_value == '') {
634  unset($a_value);
635  }
636 
637  $ilDB->replace(
638  'lng_data',
639  array(
640  'module' => array('text',$a_module),
641  'identifier' => array('text',$a_identifier),
642  'lang_key' => array('text',$a_lang_key)
643  ),
644  array(
645  'value' => array('text',$a_value),
646  'local_change' => array('timestamp',$a_local_change),
647  'remarks' => array('text', $a_remarks)
648  )
649  );
650  return true;
651 
652  /*
653  $ilDB->manipulate(sprintf("DELETE FROM lng_data WHERE module = %s AND ".
654  "identifier = %s AND lang_key = %s",
655  $ilDB->quote($a_module, "text"), $ilDB->quote($a_identifier, "text"),
656  $ilDB->quote($a_lang_key, "text")));
657 
658 
659  $ilDB->manipulate(sprintf("INSERT INTO lng_data " .
660  "(module, identifier, lang_key, value, local_change) " .
661  "VALUES (%s,%s,%s,%s,%s)",
662  $ilDB->quote($a_module, "text"), $ilDB->quote($a_identifier, "text"),
663  $ilDB->quote($a_lang_key, "text"), $ilDB->quote($a_value, "text"),
664  $ilDB->quote($a_local_change, "timestamp")));
665  */
666  }
667 
671  final public static function updateLangEntry(
672  $a_module,
673  $a_identifier,
674  $a_lang_key,
675  $a_value,
676  $a_local_change = null,
677  $a_remarks = null
678  ) {
679  global $ilDB;
680 
681  if (isset($a_remarks)) {
682  $a_remarks = substr($a_remarks, 0, 250);
683  }
684  if ($a_remarks == '') {
685  unset($a_remarks);
686  }
687 
688  if (isset($a_value)) {
689  $a_value = substr($a_value, 0, 4000);
690  }
691  if ($a_value == '') {
692  unset($a_value);
693  }
694 
695  $ilDB->manipulate(sprintf(
696  "UPDATE lng_data " .
697  "SET value = %s, local_change = %s, remarks = %s " .
698  "WHERE module = %s AND identifier = %s AND lang_key = %s ",
699  $ilDB->quote($a_value, "text"),
700  $ilDB->quote($a_local_change, "timestamp"),
701  $ilDB->quote($a_remarks, "text"),
702  $ilDB->quote($a_module, "text"),
703  $ilDB->quote($a_identifier, "text"),
704  $ilDB->quote($a_lang_key, "text")
705  ));
706  }
707 
708 
712  final public static function deleteLangEntry($a_module, $a_identifier, $a_lang_key)
713  {
714  global $ilDB;
715 
716  $ilDB->manipulate(sprintf(
717  "DELETE FROM lng_data " .
718  "WHERE module = %s AND identifier = %s AND lang_key = %s ",
719  $ilDB->quote($a_module, "text"),
720  $ilDB->quote($a_identifier, "text"),
721  $ilDB->quote($a_lang_key, "text")
722  ));
723 
724  return true;
725  }
726 
727 
734  public function resetUserLanguage($lang_key)
735  {
736  global $ilDB;
737 
738  $query = "UPDATE usr_pref SET " .
739  "value = " . $ilDB->quote($this->lang_default, "text") . " " .
740  "WHERE keyword = " . $ilDB->quote('language', "text") . " " .
741  "AND value = " . $ilDB->quote($lang_key, "text");
742  $ilDB->manipulate($query);
743  }
744 
753  public static function cut_header($content)
754  {
755  foreach ($content as $key => $val) {
756  if (trim($val) == "<!-- language file start -->") {
757  return array_slice($content, $key +1);
758  }
759  }
760 
761  return false;
762  }
763 
770  public function optimizeData()
771  {
772  // Mantis #22313: removed table optimization
773  return true;
774  }
775 
785  public function check($scope = '')
786  {
787  include_once("./Services/Utilities/classes/class.ilStr.php");
788 
789  if (!empty($scope)) {
790  if ($scope == 'global') {
791  $scope = '';
792  } else {
793  $scopeExtension = '.' . $scope;
794  }
795  }
796 
798  if ($scope == "local") {
799  $path = $this->cust_lang_path;
800  }
801 
802  $tmpPath = getcwd();
803 
804  // dir check
805  if (!is_dir($path)) {
806  $this->ilias->raiseError("Directory not found: " . $path, $this->ilias->error_obj->MESSAGE);
807  }
808 
809  chdir($path);
810 
811  // compute lang-file name format
812  $lang_file = "ilias_" . $this->key . ".lang" . $scopeExtension;
813 
814  // file check
815  if (!is_file($lang_file)) {
816  $this->ilias->raiseError("File not found: " . $lang_file, $this->ilias->error_obj->MESSAGE);
817  }
818 
819  // header check
820  $content = $this->cut_header(file($lang_file));
821  if ($content === false) {
822  $this->ilias->raiseError("Wrong Header in " . $lang_file, $this->ilias->error_obj->MESSAGE);
823  }
824 
825  // check (counting) elements of each lang-entry
826  $line = 0;
827  foreach ($content as $key => $val) {
828  $separated = explode($this->separator, trim($val));
829  $num = count($separated);
830  ++$n;
831  if ($num != 3) {
832  $line = $n + 36;
833  $this->ilias->raiseError("Wrong parameter count in " . $lang_file . " in line $line (Value: $val)! Please check your language file!", $this->ilias->error_obj->MESSAGE);
834  }
835  if (!ilStr::isUtf8($separated[2])) {
836  $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);
837  }
838  }
839 
840  chdir($tmpPath);
841 
842  // no error occured
843  return true;
844  }
845 
849  public static function countUsers($a_lang)
850  {
851  global $ilDB, $lng;
852 
853  $set = $ilDB->query("SELECT COUNT(*) cnt FROM usr_data ud JOIN usr_pref up" .
854  " ON ud.usr_id = up.usr_id " .
855  " WHERE up.value = " . $ilDB->quote($a_lang, "text") .
856  " AND up.keyword = " . $ilDB->quote("language", "text"));
857  $rec = $ilDB->fetchAssoc($set);
858 
859  // add users with no usr_pref set to default language
860  if ($a_lang == $lng->lang_default) {
861  $set2 = $ilDB->query("SELECT COUNT(*) cnt FROM usr_data ud LEFT JOIN usr_pref up" .
862  " ON (ud.usr_id = up.usr_id AND up.keyword = " . $ilDB->quote("language", "text") . ")" .
863  " WHERE up.value IS NULL ");
864  $rec2 = $ilDB->fetchAssoc($set2);
865  }
866 
867  return (int) $rec["cnt"] + (int) $rec2["cnt"];
868  }
869 } // END class.LanguageObject
optimizeData()
optimizes the db-table langdata
static getPluginObject($a_ctype, $a_cname, $a_slot_id, $a_pname)
Get plugin object.
global $ilErr
Definition: raiseError.php:16
isUserLanguage()
check if language is system language
$result
global $DIC
Definition: saml.php:7
Class ilObjLanguage.
static getInstalledLanguages()
Get the language objects of the installed languages.
static _getObjectsByType($a_obj_type="", $a_owner="")
Get objects by type.
static countUsers($a_lang)
Count number of users that use a language.
isInstalled()
Check language object status, and return true if language is installed.
insert($scope='')
insert language data from file into database
__construct($a_id=0, $a_call_by_reference=false)
Constructor.
setTitle($a_title)
set object title
if($modEnd===false) $module
Definition: module.php:59
getStatus()
get language status
uninstall()
uninstall current language
check($scope='')
Validate the logical structure of a lang file.
static _deleteLangData($a_lang_key, $a_keep_local_change=false)
Delete languge data.
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
getLocalChanges($a_min_date="", $a_max_date="")
get locally changed language entries
isSystemLanguage()
check if language is system language
static deleteLangEntry($a_module, $a_identifier, $a_lang_key)
Delete lang entry.
refresh()
refresh current language
resetUserLanguage($lang_key)
search ILIAS for users which have selected &#39;$lang_key&#39; as their prefered language and reset them to d...
redirection script todo: (a better solution should control the processing via a xml file) ...
Reload workbook from saved file
$query
$n
Definition: RandomTest.php:85
install($scope='')
install current language
Create styles array
The data for the language used.
flush($a_mode='all')
remove language data from database
global $ilDB
static refreshAll()
Refresh all installed languages.
isLocal()
Check language object status, and return true if a local language file is installed.
setDescription($a_desc)
set object description
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
static updateLangEntry( $a_module, $a_identifier, $a_lang_key, $a_value, $a_local_change=null, $a_remarks=null)
Replace lang entry.
update()
update object in db
static _getLastLocalChange($a_key)
get the date of the last local change
static refreshPlugins($a_lang_keys=null)
static replaceLangEntry( $a_module, $a_identifier, $a_lang_key, $a_value, $a_local_change=null, $a_remarks=null)
Replace lang entry.
static getAllSlots()
Get all plugin slots.
static cut_header($content)
remove lang-file haeder information from &#39;$content&#39; This function seeks for a special keyword where t...
static isUtf8($a_str)
Check whether string is utf-8.
getKey()
get language key