ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilSetupLanguage.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
43{
44 public array $text;
45 public string $lang_default = "en";
46 public string $lang_path;
47 public string $lang_key;
48 public string $separator = "#:#";
49 public string $comment_separator = "###";
50 protected ilDBInterface $db;
51
52 public function __construct(string $a_lang_key)
53 {
54 $this->lang_key = $a_lang_key ?: $this->lang_default;
55 $il_absolute_path = realpath(__DIR__ . "/../../../../../");
56 $this->lang_path = $il_absolute_path . "/lang";
57 $this->cust_lang_path = $il_absolute_path . "/lang/customizing";
58 }
59
67 public function txt(string $a_topic, string $a_default_lang_fallback_mod = ''): string
68 {
69 global $log;
70
71 if (empty($a_topic)) {
72 return "";
73 }
74
75 $translation = $this->text[$a_topic] ?? '';
76
77 //get position of the comment_separator
78 $pos = strpos($translation, $this->comment_separator);
79
80 if ($pos !== false) {
81 // remove comment
82 $translation = substr($translation, 0, $pos);
83 }
84
85 if ($translation === "") {
86 $log->writeLanguageLog($a_topic, $this->lang_key);
87 return "-" . $a_topic . "-";
88 }
89
90 return $translation;
91 }
92
100 public function installLanguages(array $a_lang_keys, array $a_local_keys)
101 {
102 global $ilDB;
103
104 if (empty($a_lang_keys)) {
105 $a_lang_keys = array();
106 }
107
108 if (empty($a_local_keys)) {
109 $a_local_keys = array();
110 }
111
112 $err_lang = array();
113
114 $db_langs = $this->getAvailableLanguages();
115
116 foreach ($a_lang_keys as $lang_key) {
117 if ($this->checkLanguage($lang_key)) {
118 $this->flushLanguage($lang_key, "keep_local");
119 $this->insertLanguage($lang_key);
120
121 if (in_array($lang_key, $a_local_keys, true) && is_dir($this->cust_lang_path)) {
122 if ($this->checkLanguage($lang_key, "local")) {
123 $this->insertLanguage($lang_key, "local");
124 } else {
125 $err_lang[] = $lang_key;
126 }
127 }
128
129 // register language first time install
130 if (!array_key_exists($lang_key, $db_langs)) {
131 if (in_array($lang_key, $a_local_keys, true)) {
132 $itype = "installed_local";
133 } else {
134 $itype = "installed";
135 }
136 $lid = $ilDB->nextId("object_data");
137 $query = "INSERT INTO object_data " .
138 "(obj_id,type,title,description,owner,create_date,last_update) " .
139 "VALUES " .
140 "(" .
141 $ilDB->quote($lid, "integer") . "," .
142 $ilDB->quote("lng", "text") . "," .
143 $ilDB->quote($lang_key, "text") . "," .
144 $ilDB->quote($itype, "text") . "," .
145 $ilDB->quote("-1", "integer") . "," .
146 $ilDB->now() . "," .
147 $ilDB->now() .
148 ")";
149 $ilDB->manipulate($query);
150 }
151 } else {
152 $err_lang[] = $lang_key;
153 }
154 }
155
156 foreach ($db_langs as $key => $val) {
157 if (!in_array($key, $err_lang, true)) {
158 if (in_array($key, $a_lang_keys, true)) {
159 if (in_array($key, $a_local_keys, true)) {
160 $ld = "installed_local";
161 } else {
162 $ld = "installed";
163 }
164 $query = "UPDATE object_data SET " .
165 "description = " . $ilDB->quote($ld, "text") . ", " .
166 "last_update = " . $ilDB->quote(gmdate("Y-m-d H:i:s"), "timestamp") . " " .
167 "WHERE obj_id = " . $ilDB->quote($val["obj_id"], "integer") . " " .
168 "AND type = " . $ilDB->quote("lng", "text");
169 $ilDB->manipulate($query);
170 } else {
171 $this->flushLanguage($key, "all");
172
173 if (strpos($val["status"], "installed") === 0) {
174 $query = "UPDATE object_data SET " .
175 "description = " . $ilDB->quote("not_installed", "text") . ", " .
176 "last_update = " . $ilDB->quote(gmdate("Y-m-d H:i:s"), "timestamp") . " " .
177 "WHERE obj_id = " . $ilDB->quote($val["obj_id"], "integer") . " " .
178 "AND type = " . $ilDB->quote("lng", "text");
179 $ilDB->manipulate($query);
180 }
181 }
182 }
183 }
184
185 return ($err_lang) ?: true;
186 }
187
191 public function getInstalledLanguages(): array
192 {
193 global $ilDB;
194
195 $arr = [];
196 if ($ilDB instanceof ilDBInterface) {
197 $query = "SELECT * FROM object_data " .
198 "WHERE type = " . $ilDB->quote("lng", "text") . " " .
199 "AND " . $ilDB->like("description", "text", "installed%");
200 $r = $ilDB->query($query);
201
202 while ($row = $ilDB->fetchObject($r)) {
203 $arr[] = $row->title;
204 }
205 }
206 return $arr;
207 }
208
212 public function getInstalledLocalLanguages(): array
213 {
214 global $ilDB;
215
216 $arr = [];
217 if ($ilDB instanceof ilDBInterface) {
218 $query = "SELECT * FROM object_data " .
219 "WHERE type = " . $ilDB->quote("lng", "text") . " " .
220 "AND description = " . $ilDB->quote("installed_local", "text");
221 $r = $ilDB->query($query);
222
223 while ($row = $ilDB->fetchObject($r)) {
224 $arr[] = $row->title;
225 }
226 }
227 return $arr;
228 }
229
233 protected function getAvailableLanguages(): array
234 {
235 global $ilDB;
236
237 $arr = array();
238
239 $query = "SELECT * FROM object_data " .
240 "WHERE type = " . $ilDB->quote("lng", "text");
241 $r = $ilDB->query($query);
242
243 while ($row = $ilDB->fetchObject($r)) {
244 $arr[$row->title]["obj_id"] = $row->obj_id;
245 $arr[$row->title]["status"] = $row->description;
246 }
247
248 return $arr;
249 }
250
262 protected function checkLanguage(string $a_lang_key, string $scope = ""): bool
263 {
264 $scopeExtension = "";
265 if (!empty($scope)) {
266 if ($scope === "global") {
267 $scope = "";
268 } else {
269 $scopeExtension = "." . $scope;
270 }
271 }
272
274 if ($scope === "local") {
276 }
277
278 $tmpPath = getcwd();
279 chdir($path);
280
281 // compute lang-file name format
282 $lang_file = "ilias_" . $a_lang_key . ".lang" . $scopeExtension;
283
284 // file check
285 if (!is_file($lang_file)) {
286 chdir($tmpPath);
287 return false;
288 }
289
290 // header check
291 if (!$content = $this->cut_header(file($lang_file))) {
292 chdir($tmpPath);
293 return false;
294 }
295
296 // check (counting) elements of each lang-entry
297 foreach ($content as $key => $val) {
298 $separated = explode($this->separator, trim($val));
299 $num = count($separated);
300
301 if ($num !== 3) {
302 chdir($tmpPath);
303 return false;
304 }
305 }
306
307 chdir($tmpPath);
308
309 // no error occured
310 return true;
311 }
312
323 protected function cut_header(array $content)
324 {
325 foreach ($content as $key => $val) {
326 if (trim($val) === "<!-- language file start -->") {
327 return array_slice($content, $key + 1);
328 }
329 }
330 return false;
331 }
332
338 protected function flushLanguage(string $a_lang_key, string $a_mode = "all"): void
339 {
340 global $ilDB;
341
342 self::_deleteLangData($a_lang_key, ($a_mode === "keep_local"));
343
344 if ($a_mode === "all") {
345 $ilDB->manipulate("DELETE FROM lng_modules WHERE lang_key = " .
346 $ilDB->quote($a_lang_key, "text"));
347 }
348 }
349
355 public static function _deleteLangData(string $a_lang_key, bool $a_keep_local_change): void
356 {
357 global $ilDB;
358
359 if (!$a_keep_local_change) {
360 $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = " .
361 $ilDB->quote($a_lang_key, "text"));
362 } else {
363 $ilDB->manipulate("DELETE FROM lng_data WHERE lang_key = " .
364 $ilDB->quote($a_lang_key, "text") .
365 " AND local_change IS NULL");
366 }
367 }
368
376 public function getLocalChanges(string $a_lang_key, string $a_min_date = "", string $a_max_date = ""): array
377 {
378 global $ilDB;
379
380 if ($a_min_date === "") {
381 $a_min_date = "1980-01-01 00:00:00";
382 }
383 if ($a_max_date === "") {
384 $a_max_date = "2200-01-01 00:00:00";
385 }
386
387 $q = sprintf(
388 "SELECT * FROM lng_data WHERE lang_key = %s " .
389 "AND local_change >= %s AND local_change <= %s",
390 $ilDB->quote($a_lang_key, "text"),
391 $ilDB->quote($a_min_date, "timestamp"),
392 $ilDB->quote($a_max_date, "timestamp")
393 );
394 $result = $ilDB->query($q);
395
396 $changes = array();
397 while ($row = $result->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
398 $changes[$row["module"]][$row["identifier"]] = $row["value"];
399 }
400 return $changes;
401 }
402
403
404 //TODO: remove redundant checks here!
411 protected function insertLanguage(string $lang_key, string $scope = ""): void
412 {
413 global $ilDB;
414
415 $lang_array = array();
416
417 $scopeExtension = "";
418 if (!empty($scope)) {
419 if ($scope === "global") {
420 $scope = "";
421 } else {
422 $scopeExtension = "." . $scope;
423 }
424 }
425
427 if ($scope === "local") {
429 }
430
431 $tmpPath = getcwd();
432 chdir($path);
433
434 $lang_file = "ilias_" . $lang_key . ".lang" . $scopeExtension;
435 $change_date = null;
436
437 if (is_file($lang_file)) {
438 // initialize the array for updating lng_modules below
439 $lang_array = [];
440 $lang_array["common"] = [];
441
442 // remove header first
443 if ($content = $this->cut_header(file($lang_file))) {
444 // get the local changes from the database
445 if (empty($scope)) {
446 $local_changes = $this->getLocalChanges($lang_key);
447 } elseif ($scope === "local") {
448 // set the change date to import time for a local file
449 // get the modification date of the local file
450 // get the newer local changes for a local file
451 $change_date = gmdate("Y-m-d H:i:s", time());
452 $min_date = gmdate("Y-m-d H:i:s", filemtime($lang_file));
453 $local_changes = $this->getLocalChanges($lang_key, $min_date);
454 }
455
456 $query_check = false;
457 $query = "INSERT INTO lng_data (module,identifier,lang_key,value,local_change,remarks) VALUES ";
458 foreach ($content as $key => $val) {
459 // split the line of the language file
460 // [0]: module
461 // [1]: identifier
462 // [2]: value
463 // [3]: comment (optional)
464 $separated = explode($this->separator, trim($val));
465
466 //get position of the comment_separator
467 $pos = strpos($separated[2], $this->comment_separator);
468
469 if ($pos !== false) {
470 //cut comment of
471 $separated[2] = substr($separated[2], 0, $pos);
472 }
473
474 // check if the value has a local change
475 if (isset($local_changes[$separated[0]])) {
476 $local_value = $local_changes[$separated[0]][$separated[1]] ?? "";
477 } else {
478 $local_value = "";
479 }
480
481 if (empty($scope)) {
482 if ($local_value !== "" && $local_value !== $separated[2]) {
483 // keep the locally changed value
484 $lang_array[$separated[0]][$separated[1]] = $local_value;
485 continue;
486 }
487 } elseif ($scope === "local") {
488 if ($local_value !== "") {
489 // keep a locally changed value that is newer than the local file
490 $lang_array[$separated[0]][$separated[1]] = $local_value;
491 continue;
492 }
493 }
494
495 $query .= sprintf(
496 "(%s,%s,%s,%s,%s,%s),",
497 $ilDB->quote($separated[0], "text"),
498 $ilDB->quote($separated[1], "text"),
499 $ilDB->quote($lang_key, "text"),
500 $ilDB->quote($separated[2], "text"),
501 $ilDB->quote($change_date, "timestamp"),
502 $ilDB->quote($separated[3] ?? null, "text")
503 );
504 $query_check = true;
505 $lang_array[$separated[0]][$separated[1]] = $separated[2];
506 }
507 $query = rtrim($query, ",") . " ON DUPLICATE KEY UPDATE value=VALUES(value),remarks=VALUES(remarks);";
508 if ($query_check) {
509 $ilDB->manipulate($query);
510 }
511 }
512
513 $query = "INSERT INTO lng_modules (module, lang_key, lang_array) VALUES ";
514 $modules_to_delete = [];
515 foreach ($lang_array as $module => $lang_arr) {
516 if ($scope === "local") {
517 $q = "SELECT * FROM lng_modules WHERE " .
518 " lang_key = " . $ilDB->quote($lang_key, "text") .
519 " AND module = " . $ilDB->quote($module, "text");
520 $set = $ilDB->query($q);
521 $row = $ilDB->fetchAssoc($set);
522 $arr2 = unserialize($row["lang_array"], ["allowed_classes" => false]);
523 if (is_array($arr2)) {
524 $lang_arr = array_merge($arr2, $lang_arr);
525 }
526 }
527 $query .= sprintf(
528 "(%s,%s,%s),",
529 $ilDB->quote($module, "text"),
530 $ilDB->quote($lang_key, "text"),
531 $ilDB->quote(serialize($lang_arr), "clob"),
532 );
533 $modules_to_delete[] = $module;
534 }
535
536 $inModulesToDelete = $ilDB->in('module', $modules_to_delete, false, 'text');
537 $ilDB->manipulate(sprintf(
538 "DELETE FROM lng_modules WHERE lang_key = %s AND $inModulesToDelete",
539 $ilDB->quote($lang_key, "text")
540 ));
541
542 $query = rtrim($query, ",") . ";";
543 $ilDB->manipulate($query);
544 }
545
546 chdir($tmpPath);
547 }
548
553 public function getLocalLanguages(): array
554 {
555 $local_langs = array();
556 if (is_dir($this->cust_lang_path)) {
557 $d = dir($this->cust_lang_path);
558 $tmpPath = getcwd();
559 chdir($this->cust_lang_path);
560
561 // get available .lang.local files
562 while ($entry = $d->read()) {
563 if (is_file($entry) && (preg_match("~(^ilias_.{2}\.lang.local$)~", $entry))) {
564 $lang_key = substr($entry, 6, 2);
565 $local_langs[] = $lang_key;
566 }
567 }
568
569 chdir($tmpPath);
570 }
571
572 return $local_langs;
573 }
574
578 public function getInstallableLanguages(): array
579 {
580 $d = dir($this->lang_path);
581 $tmpPath = getcwd();
582 chdir($this->lang_path);
583
584 $installableLanguages = [];
585 // get available lang-files
586 while ($entry = $d->read()) {
587 if (is_file($entry) && (preg_match("~(^ilias_.{2}\.lang$)~", $entry))) {
588 $lang_key = substr($entry, 6, 2);
589 $installableLanguages[] = $lang_key;
590 }
591 }
592
593 chdir($tmpPath);
594
595 return $installableLanguages;
596 }
597
603 public function setDbHandler(ilDBInterface $a_db_handler): bool
604 {
605 $this->db = &$a_db_handler;
606 return true;
607 }
608
609 public function loadLanguageModule(string $a_module): void
610 {
611 }
612}
language handling
string $cust_lang_path
writeLanguageLog(string $topic, string $lang_key)
Write language log.
language handling for setup
getLocalChanges(string $a_lang_key, string $a_min_date="", string $a_max_date="")
get locally changed language entries $a_lang_key language key $a_min_date minimum change date "yyyy-m...
cut_header(array $content)
Remove *.lang header information from '$content'.
installLanguages(array $a_lang_keys, array $a_local_keys)
install languages
txt(string $a_topic, string $a_default_lang_fallback_mod='')
gets the text for a given topic
flushLanguage(string $a_lang_key, string $a_mode="all")
remove language data from database $a_lang_key language key $a_mode "all" or "keep_local"
getInstalledLanguages()
get already installed languages (in db)
loadLanguageModule(string $a_module)
Load language module.
__construct(string $a_lang_key)
Constructor read the single-language file and put this in an array text.
getAvailableLanguages()
get already registered languages (in db)
getInstalledLocalLanguages()
get already installed local languages (in db)
getLocalLanguages()
Searches for the existence of *.lang.local files.
insertLanguage(string $lang_key, string $scope="")
insert language data from file in database
static _deleteLangData(string $a_lang_key, bool $a_keep_local_change)
Delete languge data.
checkLanguage(string $a_lang_key, string $scope="")
validate the logical structure of a lang-file
setDbHandler(ilDBInterface $a_db_handler)
set db handler object @string object db handler Return true on success
getInstallableLanguages()
Return installable languages.
Interface ilDBInterface.
$scope
Definition: ltiregstart.php:51
$path
Definition: ltiservices.php:30
$q
Definition: shib_logout.php:23