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