ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilSetupLanguage.php
Go to the documentation of this file.
1<?php declare(strict_types=1);
2
44{
50 public $text = array();
51
58 public $lang_default = "en";
59
67 public $lang_path;
68
74 public $lang_key;
75
81 public $separator = "#:#";
82
88 public $comment_separator = "###";
89
90 protected $db;
91
100 public function __construct($a_lang_key)
101 {
102 $this->lang_key = $a_lang_key ?: $this->lang_default;
103 $il_absolute_path = realpath(dirname(__FILE__) . '/../../../../');
104 $this->lang_path = $il_absolute_path . "/lang";
105 $this->cust_lang_path = $il_absolute_path . "/Customizing/global/lang";
106 }
107
116 public function txt($a_topic, $a_default_lang_fallback_mod = '')
117 {
118 global $log;
119
120 if (empty($a_topic)) {
121 return "";
122 }
123
124 $translation = $this->text[$a_topic];
125
126 //get position of the comment_separator
127 $pos = strpos($translation, $this->comment_separator);
128
129 if ($pos !== false) {
130 // remove comment
131 $translation = substr($translation, 0, $pos);
132 }
133
134 if ($translation == "") {
135 $log->writeLanguageLog($a_topic, $this->lang_key);
136 return "-" . $a_topic . "-";
137 } else {
138 return $translation;
139 }
140 }
141
148 public function installLanguages($a_lang_keys, $a_local_keys)
149 {
150 global $ilDB;
151
152 if (empty($a_lang_keys)) {
153 $a_lang_keys = array();
154 }
155
156 if (empty($a_local_keys)) {
157 $a_local_keys = array();
158 }
159
160 $err_lang = array();
161
162 $db_langs = $this->getAvailableLanguages();
163
164 foreach ($a_lang_keys as $lang_key) {
165 if ($this->checkLanguage($lang_key)) {
166 $this->flushLanguage($lang_key, 'keep_local');
167 $this->insertLanguage($lang_key);
168
169 if (in_array($lang_key, $a_local_keys) && is_dir($this->cust_lang_path)) {
170 if ($this->checkLanguage($lang_key, "local")) {
171 $this->insertLanguage($lang_key, "local");
172 } else {
173 $err_lang[] = $lang_key;
174 }
175 }
176
177 // register language first time install
178 if (!array_key_exists($lang_key, $db_langs)) {
179 if (in_array($lang_key, $a_local_keys)) {
180 $itype = 'installed_local';
181 } else {
182 $itype = 'installed';
183 }
184 $lid = $ilDB->nextId("object_data");
185 $query = "INSERT INTO object_data " .
186 "(obj_id,type,title,description,owner,create_date,last_update) " .
187 "VALUES " .
188 "(" .
189 $ilDB->quote($lid, "integer") . "," .
190 $ilDB->quote("lng", "text") . "," .
191 $ilDB->quote($lang_key, "text") . "," .
192 $ilDB->quote($itype, "text") . "," .
193 $ilDB->quote('-1', "integer") . "," .
194 $ilDB->now() . "," .
195 $ilDB->now() .
196 ")";
197 $this->db->manipulate($query);
198 }
199 } else {
200 $err_lang[] = $lang_key;
201 }
202 }
203
204 foreach ($db_langs as $key => $val) {
205 if (!in_array($key, $err_lang)) {
206 if (in_array($key, $a_lang_keys)) {
207 if (in_array($key, $a_local_keys)) {
208 $ld = 'installed_local';
209 } else {
210 $ld = 'installed';
211 }
212 $query = "UPDATE object_data SET " .
213 "description = " . $ilDB->quote($ld, "text") . ", " .
214 "last_update = " . $ilDB->now() . " " .
215 "WHERE obj_id = " . $ilDB->quote($val["obj_id"], "integer") . " " .
216 "AND type = " . $ilDB->quote("lng", "text");
217 $ilDB->manipulate($query);
218 } else {
219 $this->flushLanguage($key, "all");
220
221 if (substr($val["status"], 0, 9) == "installed") {
222 $query = "UPDATE object_data SET " .
223 "description = " . $ilDB->quote("not_installed", "text") . ", " .
224 "last_update = " . $ilDB->now() . " " .
225 "WHERE obj_id = " . $ilDB->quote($val["obj_id"], "integer") . " " .
226 "AND type = " . $ilDB->quote("lng", "text");
227 $ilDB->manipulate($query);
228 }
229 }
230 }
231 }
232
233 return ($err_lang) ?: true;
234 }
235
236
237
243 public function getInstalledLanguages()
244 {
245 global $ilDB;
246
247 $arr = array();
248
249 $query = "SELECT * FROM object_data " .
250 "WHERE type = " . $ilDB->quote("lng", "text") . " " .
251 "AND " . $ilDB->like("description", "text", 'installed%');
252 $r = $ilDB->query($query);
253
254 while ($row = $ilDB->fetchObject($r)) {
255 $arr[] = $row->title;
256 }
257
258 return $arr;
259 }
260
267 {
268 global $ilDB;
269
270 $arr = array();
271
272 $query = "SELECT * FROM object_data " .
273 "WHERE type = " . $ilDB->quote("lng", "text") . " " .
274 "AND description = " . $ilDB->quote('installed_local', "text");
275 $r = $ilDB->query($query);
276
277 while ($row = $ilDB->fetchObject($r)) {
278 $arr[] = $row->title;
279 }
280
281 return $arr;
282 }
283
288 protected function getAvailableLanguages()
289 {
290 global $ilDB;
291
292 $arr = array();
293
294 $query = "SELECT * FROM object_data " .
295 "WHERE type = " . $ilDB->quote("lng", "text");
296 $r = $ilDB->query($query);
297
298 while ($row = $ilDB->fetchObject($r)) {
299 $arr[$row->title]["obj_id"] = $row->obj_id;
300 $arr[$row->title]["status"] = $row->description;
301 }
302
303 return $arr;
304 }
305
317 protected function checkLanguage($a_lang_key, $scope = '')
318 {
319 $scopeExtension = "";
320 if (!empty($scope)) {
321 if ($scope == 'global') {
322 $scope = '';
323 } else {
324 $scopeExtension = '.' . $scope;
325 }
326 }
327
328 $path = $this->lang_path;
329 if ($scope == "local") {
330 $path = $this->cust_lang_path;
331 }
332
333 $tmpPath = getcwd();
334 chdir($path);
335
336 // compute lang-file name format
337 $lang_file = "ilias_" . $a_lang_key . ".lang" . $scopeExtension;
338
339 // file check
340 if (!is_file($lang_file)) {
341 chdir($tmpPath);
342 return false;
343 }
344
345 // header check
346 if (!$content = $this->cut_header(file($lang_file))) {
347 chdir($tmpPath);
348 return false;
349 }
350
351 // check (counting) elements of each lang-entry
352 foreach ($content as $key => $val) {
353 $separated = explode($this->separator, trim($val));
354 $num = count($separated);
355
356 if ($num != 3) {
357 chdir($tmpPath);
358 return false;
359 }
360 }
361
362 chdir($tmpPath);
363
364 // no error occured
365 return true;
366 }
367
378 protected function cut_header($content)
379 {
380 foreach ($content as $key => $val) {
381 if (trim($val) == "<!-- language file start -->") {
382 return array_slice($content, $key + 1);
383 }
384 }
385
386 return false;
387 }
388
389
395 protected function flushLanguage($a_lang_key, $a_mode = 'all')
396 {
398
399 ilSetupLanguage::_deleteLangData($a_lang_key, ($a_mode == 'keep_local'));
400
401 if ($a_mode == 'all') {
402 $ilDB->manipulate("DELETE FROM lng_modules WHERE lang_key = " .
403 $ilDB->quote($a_lang_key, "text"));
404 }
405 }
406
412 public static function _deleteLangData($a_lang_key, $a_keep_local_change)
413 {
414 global $ilDB;
415
416 if (!$a_keep_local_change) {
417 $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = " .
418 $ilDB->quote($a_lang_key, "text"));
419 } else {
420 $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = " .
421 $ilDB->quote($a_lang_key, "text") .
422 " AND local_change IS NULL");
423 }
424 }
425
433 public function getLocalChanges($a_lang_key, $a_min_date = "", $a_max_date = "")
434 {
436
437 if ($a_min_date == "") {
438 $a_min_date = "1980-01-01 00:00:00";
439 }
440 if ($a_max_date == "") {
441 $a_max_date = "2200-01-01 00:00:00";
442 }
443
444 $q = sprintf(
445 "SELECT * FROM lng_data WHERE lang_key = %s " .
446 "AND local_change >= %s AND local_change <= %s",
447 $ilDB->quote($a_lang_key, "text"),
448 $ilDB->quote($a_min_date, "timestamp"),
449 $ilDB->quote($a_max_date, "timestamp")
450 );
451 $result = $ilDB->query($q);
452
453 $changes = array();
454 while ($row = $result->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
455 $changes[$row["module"]][$row["identifier"]] = $row["value"];
456 }
457 return $changes;
458 }
459
460
461 //TODO: remove redundant checks here!
469 protected function insertLanguage($lang_key, $scope = '')
470 {
471 $ilDB = &$this->db;
472
473 $lang_array = array();
474
475 $scopeExtension = "";
476 if (!empty($scope)) {
477 if ($scope == 'global') {
478 $scope = '';
479 } else {
480 $scopeExtension = '.' . $scope;
481 }
482 }
483
484 $path = $this->lang_path;
485 if ($scope == "local") {
486 $path = $this->cust_lang_path;
487 }
488
489 $tmpPath = getcwd();
490 chdir($path);
491
492 $lang_file = "ilias_" . $lang_key . ".lang" . $scopeExtension;
493 $change_date = null;
494
495 if (is_file($lang_file)) {
496 // initialize the array for updating lng_modules below
497 $lang_array = [];
498 $lang_array["common"] = [];
499
500 // remove header first
501 if ($content = $this->cut_header(file($lang_file))) {
502 // get the local changes from the database
503 if (empty($scope)) {
504 $local_changes = $this->getLocalChanges($lang_key);
505 } elseif ($scope == 'local') {
506 // set the change date to import time for a local file
507 // get the modification date of the local file
508 // get the newer local changes for a local file
509 $change_date = date("Y-m-d H:i:s", time());
510 $min_date = date("Y-m-d H:i:s", filemtime($lang_file));
511 $local_changes = $this->getLocalChanges($lang_key, $min_date);
512 }
513
514 $query_check = false;
515 $query = "INSERT INTO lng_data (module,identifier,lang_key,value,local_change,remarks) VALUES ";
516 foreach ($content as $key => $val) {
517 // split the line of the language file
518 // [0]: module
519 // [1]: identifier
520 // [2]: value
521 // [3]: comment (optional)
522 $separated = explode($this->separator, trim($val));
523
524 //get position of the comment_separator
525 $pos = strpos($separated[2], $this->comment_separator);
526
527 if ($pos !== false) {
528 //cut comment of
529 $separated[2] = substr($separated[2], 0, $pos);
530 }
531
532 // check if the value has a local change
533 if (isset($local_changes[$separated[0]])) {
534 $local_value = $local_changes[$separated[0]][$separated[1]] ?? null;
535 } else {
536 $local_value = "";
537 }
538
539 if (empty($scope)) {
540 if ($local_value != "" && $local_value != $separated[2]) {
541 // keep the locally changed value
542 $lang_array[$separated[0]][$separated[1]] = $local_value;
543 continue;
544 }
545 } elseif ($scope === "local") {
546 if ($local_value !== "") {
547 // keep a locally changed value that is newer than the local file
548 $lang_array[$separated[0]][$separated[1]] = $local_value;
549 continue;
550 }
551 }
552 $query .= sprintf(
553 "(%s,%s,%s,%s,%s,%s),",
554 $ilDB->quote($separated[0], "text"),
555 $ilDB->quote($separated[1], "text"),
556 $ilDB->quote($lang_key, "text"),
557 $ilDB->quote($separated[2], "text"),
558 $ilDB->quote($change_date, "timestamp"),
559 $ilDB->quote($separated[3] ?? null, "text")
560 );
561 $query_check = true;
562 $lang_array[$separated[0]][$separated[1]] = $separated[2];
563 }
564 $query = rtrim($query, ",") . " ON DUPLICATE KEY UPDATE value=VALUES(value),remarks=VALUES(remarks);";
565 if ($query_check) {
566 $ilDB->manipulate($query);
567 }
568 }
569
570 $query = "INSERT INTO lng_modules (module, lang_key, lang_array) VALUES ";
571 $modules_to_delete = [];
572 foreach ($lang_array as $module => $lang_arr) {
573 if ($scope === "local") {
574 $q = "SELECT * FROM lng_modules WHERE " .
575 " lang_key = " . $ilDB->quote($lang_key, "text") .
576 " AND module = " . $ilDB->quote($module, "text");
577 $set = $ilDB->query($q);
578 $row = $ilDB->fetchAssoc($set);
579 $arr2 = isset($row["lang_array"]) ? unserialize($row["lang_array"],
580 ["allowed_classes" => false]) : "";
581 if (is_array($arr2)) {
582 $lang_arr = array_merge($arr2, $lang_arr);
583 }
584 }
585 $query .= sprintf(
586 "(%s,%s,%s),",
587 $ilDB->quote($module, "text"),
588 $ilDB->quote($lang_key, "text"),
589 $ilDB->quote(serialize($lang_arr), "clob")
590 );
591 $modules_to_delete[] = $module;
592 }
593
594 $inModulesToDelete = $ilDB->in('module', $modules_to_delete, false, 'text');
595 $ilDB->manipulate(sprintf("DELETE FROM lng_modules WHERE lang_key = %s AND $inModulesToDelete",
596 $ilDB->quote($lang_key, "text")
597 ));
598
599 $query = rtrim($query, ",") . ";";
600 $ilDB->manipulate($query);
601 }
602
603 chdir($tmpPath);
604 }
605
611 public function getLocalLanguages()
612 {
613 $local_langs = array();
614 if (is_dir($this->cust_lang_path)) {
615 $d = dir($this->cust_lang_path);
616 $tmpPath = getcwd();
617 chdir($this->cust_lang_path);
618
619 // get available .lang.local files
620 while ($entry = $d->read()) {
621 if (is_file($entry) && (preg_match("~(^ilias_.{2}\.lang.local$)~", $entry))) {
622 $lang_key = substr($entry, 6, 2);
623 $local_langs[] = $lang_key;
624 }
625 }
626
627 chdir($tmpPath);
628 }
629
630 return $local_langs;
631 }
632
633 public function getInstallableLanguages()
634 {
635 $d = dir($this->lang_path);
636 $tmpPath = getcwd();
637 chdir($this->lang_path);
638
639 $installableLanguages = [];
640 // get available lang-files
641 while ($entry = $d->read()) {
642 if (is_file($entry) && (preg_match("~(^ilias_.{2}\.lang$)~", $entry))) {
643 $lang_key = substr($entry, 6, 2);
644 $installableLanguages[] = $lang_key;
645 }
646 }
647
648 chdir($tmpPath);
649
650 return $installableLanguages;
651 }
652
658 public function setDbHandler($a_db_handler)
659 {
660 if (empty($a_db_handler) or !is_object($a_db_handler)) {
661 return false;
662 }
663
664 $this->db = &$a_db_handler;
665
666 return true;
667 }
668
669 public function loadLanguageModule($a_module)
670 {
671 }
672} // END class.ilSetupLanguage
$result
An exception for terminatinating execution or to throw for unit testing.
language handling
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct($a_lang_key)
Constructor read the single-language file and put this in an array text.
cut_header($content)
Remove *.lang header information from '$content'.
flushLanguage($a_lang_key, $a_mode='all')
remove language data from database
txt($a_topic, $a_default_lang_fallback_mod='')
gets the text for a given topic
static _deleteLangData($a_lang_key, $a_keep_local_change)
Delete languge data.
insertLanguage($lang_key, $scope='')
insert language data from file in database
getInstalledLanguages()
get already installed languages (in db)
getAvailableLanguages()
get already registered languages (in db)
getInstalledLocalLanguages()
get already installed local languages (in db)
getLocalLanguages()
Searches for the existence of *.lang.local files.
getLocalChanges($a_lang_key, $a_min_date="", $a_max_date="")
get locally changed language entries
installLanguages($a_lang_keys, $a_local_keys)
install languages
setDbHandler($a_db_handler)
set db handler object @string object db handler
checkLanguage($a_lang_key, $scope='')
validate the logical structure of a lang-file
for( $i=6;$i< 13;$i++) for($i=1; $i< 13; $i++) $d
Definition: date.php:296
$query
global $ilDB