ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.ilSetupLanguage.php
Go to the documentation of this file.
1 <?php
2 
19 declare(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 }
$scope
Definition: ltiregstart.php:47
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
language handling for setup
$path
Definition: ltiservices.php:29
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
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)
getInstalledLocalLanguages()
get already installed local languages (in db)
loadLanguageModule(string $a_module)
$q
Definition: shib_logout.php:23
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
static _deleteLangData(string $a_lang_key, bool $a_keep_local_change)
Delete languge data.
$r