19declare(strict_types=1);
28use PHPUnit\Framework\MockObject\MockObject;
29use PHPUnit\Framework\MockObject\Stub;
30use PHPUnit\Framework\TestCase;
41 $db = $this->createMock(ilDBInterface::class);
42 $db->method(
'nextId')->willReturn(42);
43 $db->method(
'quote')->willReturnCallback(
44 static fn(mixed $value):
string =>
"'" . (
string) $value .
"'"
46 $db->method(
'now')->willReturn(
'NOW()');
47 $db->method(
'manipulate')->willReturn(1);
58 $db = $this->createStub(ilDBInterface::class);
59 $db->method(
'nextId')->willReturn(42);
60 $db->method(
'quote')->willReturnCallback(
61 static fn(mixed $value):
string =>
"'" . (
string) $value .
"'"
63 $db->method(
'now')->willReturn(
'NOW()');
64 $db->method(
'manipulate')->willReturn(1);
72 ?\DateTimeImmutable $now =
null
80 (string) realpath(__DIR__ .
'/../../../../../'),
82 $now !== null ? static fn(): \DateTimeImmutable => $now : null
88 $db = $this->createDatabaseMock();
89 $db->expects($this->once())
90 ->method(
'manipulate')
91 ->with($this->logicalAnd(
92 $this->stringContains(
'UPDATE object_data'),
93 $this->stringContains(
"last_update = '2026-01-02 03:04:05'")
96 $manager = $this->createManager(
98 $this->createStub(InstalledLanguageRepository::class),
99 new \DateTimeImmutable(
'2026-01-02 03:04:05',
new \DateTimeZone(
'UTC'))
102 $manager->registerInstalledLanguage(
104 [
'de' => [
'obj_id' => 7,
'status' =>
'not_installed']],
111 $db = $this->createDatabaseMock();
112 $db->expects($this->once())
113 ->method(
'manipulate')
114 ->with($this->logicalAnd(
115 $this->stringContains(
'INSERT INTO object_data'),
116 $this->stringContains(
'NOW(),NOW()')
119 $manager = $this->createManager(
121 $this->createStub(InstalledLanguageRepository::class),
122 new \DateTimeImmutable(
'2026-01-02 03:04:05',
new \DateTimeZone(
'UTC'))
125 $manager->registerInstalledLanguage(
'de', [], []);
130 $db = $this->createDatabaseStub();
132 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
137 $repository = $this->createStub(InstalledLanguageRepository::class);
138 $repository->method(
'getAvailableLanguages')->willReturn([
139 'fr' => [
'obj_id' => 3,
'status' =>
'installed'],
141 $repository->method(
'getLocalLanguages')->willReturn([]);
143 $manager = $this->createManager(
146 new \DateTimeImmutable(
'2026-01-02 03:04:05',
new \DateTimeZone(
'UTC'))
150 $result = $manager->installLanguages([]);
152 $this->assertTrue($result);
153 $bookkeeping_update = array_values(array_filter(
155 static fn(
string $query):
bool => str_contains($query,
'UPDATE object_data')
157 $this->assertCount(1, $bookkeeping_update);
158 $this->assertStringContainsString(
"description = 'not_installed'", $bookkeeping_update[0]);
159 $this->assertStringContainsString(
"last_update = '2026-01-02 03:04:05'", $bookkeeping_update[0]);
164 $db = $this->createDatabaseMock();
165 $db->expects($this->once())
166 ->method(
'manipulate')
167 ->with($this->logicalAnd(
168 $this->stringContains(
'DELETE FROM lng_data'),
169 $this->stringContains(
'local_change IS NULL')
172 $manager = $this->createManager($db, $this->createStub(InstalledLanguageRepository::class));
174 $manager->flushLanguageForInstallation(
'de');
179 $db = $this->createDatabaseStub();
181 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
186 $manager = $this->createManager($db, $this->createStub(InstalledLanguageRepository::class));
188 $manager->flushLanguageForUninstallation(
'de');
190 $this->assertCount(2, $calls);
191 $this->assertStringContainsString(
'DELETE FROM lng_data', $calls[0]);
192 $this->assertStringNotContainsString(
'local_change IS NULL', $calls[0]);
193 $this->assertStringContainsString(
'DELETE FROM lng_modules', $calls[1]);
202 $root = $this->createTempInstallationRoot();
203 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'test',
'Global Value']]);
204 $this->writeLangFile($root .
'/lang/customizing/ilias_de.lang.local', [[
'common',
'test',
'Custom Value']]);
208 $db = $this->createDatabaseStub();
209 $db->method(
'in')->willReturn(
"module IN ('common')");
210 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
215 $repository = $this->createMock(InstalledLanguageRepository::class);
217 $repository->expects($this->never())->method(
'getLocalChanges');
226 $manager->insertLanguageForRemovingLocalChanges(
'de');
228 $insert = array_values(array_filter(
230 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_data')
232 $this->assertCount(1, $insert);
233 $this->assertStringContainsString(
"'Global Value'", $insert[0]);
234 $this->assertStringNotContainsString(
'Custom Value', $insert[0]);
236 $this->removeDirectory($root);
245 $root = $this->createTempInstallationRoot();
246 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'test',
'Global Value']]);
247 $this->writeLangFile($root .
'/lang/customizing/ilias_de.lang.local', [[
'common',
'test',
'Custom Value']]);
251 $db = $this->createDatabaseStub();
252 $db->method(
'in')->willReturn(
"module IN ('common')");
253 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
258 $repository = $this->createStub(InstalledLanguageRepository::class);
259 $repository->method(
'getLocalChanges')->willReturn([]);
266 static fn(): \DateTimeImmutable =>
new \DateTimeImmutable(
'2026-01-02 03:04:05',
new \DateTimeZone(
'UTC'))
269 $manager->insertLanguageForInstallation(
'de');
271 $insert = array_values(array_filter(
273 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_data')
275 $this->assertCount(1, $insert);
276 $this->assertStringContainsString(
"'Global Value'", $insert[0]);
277 $this->assertStringContainsString(
"'Custom Value'", $insert[0]);
279 $this->removeDirectory($root);
290 $root = $this->createTempInstallationRoot();
291 $this->writeLangFile($root .
'/lang/ilias_de.lang', [
292 [
'common',
'locally_changed',
'Global Value'],
293 [
'common',
'plain',
'Plain Global'],
296 $local_entries = [[
'common',
'newer_in_db',
'From Local File']];
297 for ($i = 0; $i < 200; $i++) {
298 $local_entries[] = [
'common',
'override_' . $i,
'Local ' . $i];
300 $this->writeLangFile($root .
'/lang/customizing/ilias_de.lang.local', $local_entries);
305 $db = $this->createDatabaseStub();
306 $db->method(
'in')->willReturn(
"module IN ('common')");
307 $db->method(
'manipulate')->willReturnCallback(
308 static function (
string $query) use (&$inserts):
int {
309 if (str_starts_with($query,
'INSERT INTO lng_data')) {
316 $repository = $this->createStub(InstalledLanguageRepository::class);
317 $repository->method(
'getLocalChanges')->willReturnCallback(
318 static function (
string $lang_key,
string $min_date =
'') use (&$calls): array {
321 return $min_date ===
''
322 ? [
'common' => [
'locally_changed' =>
'DB Local Change']]
323 : [
'common' => [
'newer_in_db' =>
'DB Is Newer']];
332 static fn(): \DateTimeImmutable =>
new \DateTimeImmutable(
'2026-01-02 03:04:05',
new \DateTimeZone(
'UTC'))
335 $manager->insertLanguageForInstallation(
'de');
338 $this->assertSame(2, $calls);
340 $this->assertCount(1, $inserts);
341 $insert = $inserts[0];
343 $this->assertStringNotContainsString(
"'Global Value'", $insert);
344 $this->assertStringContainsString(
"'Plain Global'", $insert);
346 $this->assertStringNotContainsString(
"'From Local File'", $insert);
347 $this->assertStringContainsString(
"'Local 0'", $insert);
348 $this->assertStringContainsString(
"'Local 199'", $insert);
350 $this->removeDirectory($root);
360 $root = $this->createTempInstallationRoot();
361 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'test',
'Global Value']]);
362 $this->writeLangFile($root .
'/lang/customizing/ilias_de.lang.local', [[
'common',
'test',
'Custom Value']]);
366 $db = $this->createDatabaseStub();
367 $db->method(
'in')->willReturn(
"module IN ('common')");
368 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
373 $repository = $this->createMock(InstalledLanguageRepository::class);
374 $repository->expects($this->once())
375 ->method(
'getLanguageEntries')
380 $repository->method(
'getLocalChanges')->willReturn([]);
389 $manager->insertLanguageForApplyingLocalChanges(
'de');
391 $insert = array_values(array_filter(
393 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_data')
395 $this->assertCount(1, $insert);
396 $this->assertStringContainsString(
"'Custom Value'", $insert[0]);
397 $this->assertStringNotContainsString(
'Global Value', $insert[0]);
399 $flush = array_values(array_filter(
401 static fn(
string $query):
bool => str_starts_with($query,
'DELETE FROM lng_data')
403 $this->assertCount(0, $flush);
405 $this->removeDirectory($root);
416 $root = $this->createTempInstallationRoot();
418 $this->writeLangFile(
419 $root .
'/lang/customizing/ilias_de.lang.local',
420 [[
'common',
'overridden',
'New Custom Value']]
425 $db = $this->createDatabaseStub();
426 $db->method(
'in')->willReturn(
"module IN ('common')");
427 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
432 $repository = $this->createStub(InstalledLanguageRepository::class);
433 $repository->method(
'getLanguageEntries')->willReturnMap([
436 'overridden' =>
'Old Value',
437 'untouched_by_customizing' =>
'Still Here',
449 $manager->insertLanguageForApplyingLocalChanges(
'de');
451 $modules_insert = array_values(array_filter(
453 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_modules')
455 $this->assertCount(1, $modules_insert);
456 $serialized = serialize([
457 'overridden' =>
'New Custom Value',
458 'untouched_by_customizing' =>
'Still Here',
460 $this->assertStringContainsString($serialized, $modules_insert[0]);
462 $this->removeDirectory($root);
472 $root = $this->createTempInstallationRoot();
473 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'greeting',
'Hallo']]);
477 $db = $this->createDatabaseStub();
478 $db->method(
'in')->willReturn(
"module IN ('common')");
479 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
484 $repository = $this->createStub(InstalledLanguageRepository::class);
485 $repository->method(
'checkLanguage')->willReturnMap([
488 $repository->method(
'getAvailableLanguages')->willReturn([]);
489 $repository->method(
'getLocalLanguages')->willReturn([]);
490 $repository->method(
'getLocalChanges')->willReturn([]);
499 $result = $manager->installLanguages([
'de']);
501 $this->assertTrue($result);
503 $inserts_object_data = array_values(array_filter(
505 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO object_data')
507 $this->assertCount(1, $inserts_object_data);
508 $this->assertStringContainsString(
"'de'", $inserts_object_data[0]);
509 $this->assertStringContainsString(
"'installed'", $inserts_object_data[0]);
510 $this->assertStringNotContainsString(
"'installed_local'", $inserts_object_data[0]);
512 $keep_local_flush = array_values(array_filter(
514 static fn(
string $query):
bool => str_contains($query,
'DELETE FROM lng_data')
515 && str_contains($query,
'local_change IS NULL')
517 $this->assertCount(1, $keep_local_flush);
519 $this->removeDirectory($root);
529 $root = $this->createTempInstallationRoot();
530 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'greeting',
'Hallo']]);
534 $db = $this->createDatabaseStub();
535 $db->method(
'in')->willReturn(
"module IN ('common')");
536 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
541 $repository = $this->createStub(InstalledLanguageRepository::class);
542 $repository->method(
'checkLanguage')->willReturnMap([
546 $repository->method(
'getAvailableLanguages')->willReturn([
548 'xx' => [
'obj_id' => 5,
'status' =>
'installed'],
550 $repository->method(
'getLocalLanguages')->willReturn([]);
551 $repository->method(
'getLocalChanges')->willReturn([]);
560 $result = $manager->installLanguages([
'de',
'xx']);
562 $this->assertSame([
'xx'], $result);
564 $inserts_object_data = array_values(array_filter(
566 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO object_data')
568 $this->assertCount(1, $inserts_object_data);
569 $this->assertStringContainsString(
"'de'", $inserts_object_data[0]);
572 foreach ($calls as $query) {
573 $this->assertStringNotContainsString(
"obj_id = '5'", $query);
574 $this->assertStringNotContainsString(
"lang_key = 'xx'", $query);
577 $this->removeDirectory($root);
587 $root = $this->createTempInstallationRoot();
588 $this->writeLangFile($root .
'/lang/ilias_fr.lang', [[
'common',
'greeting',
'Bonjour']]);
592 $db = $this->createDatabaseStub();
593 $db->method(
'in')->willReturn(
"module IN ('common')");
594 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
599 $repository = $this->createStub(InstalledLanguageRepository::class);
600 $repository->method(
'checkLanguage')->willReturn(
true);
601 $repository->method(
'getAvailableLanguages')->willReturn([
602 'fr' => [
'obj_id' => 9,
'status' =>
'installed'],
604 $repository->method(
'getLocalLanguages')->willReturn([]);
605 $repository->method(
'getLocalChanges')->willReturn([]);
614 $result = $manager->installLanguages([
'fr']);
615 $this->assertTrue($result);
619 $full_flush_deletes = array_values(array_filter(
621 static fn(
string $query):
bool => $query ===
"DELETE FROM lng_modules WHERE lang_key = 'fr'"
623 $this->assertCount(0, $full_flush_deletes);
625 foreach ($calls as $query) {
626 $this->assertStringNotContainsString(
'not_installed', $query);
630 $object_data_updates = array_values(array_filter(
632 static fn(
string $query):
bool => str_starts_with($query,
'UPDATE object_data')
634 $this->assertCount(1, $object_data_updates);
635 $this->assertStringContainsString(
"obj_id = '9'", $object_data_updates[0]);
636 $this->assertStringContainsString(
"description = 'installed'", $object_data_updates[0]);
638 $this->removeDirectory($root);
649 $db = $this->createDatabaseStub();
651 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
656 $repository = $this->createStub(InstalledLanguageRepository::class);
657 $repository->method(
'getAvailableLanguages')->willReturn([
658 'de' => [
'obj_id' => 4,
'status' =>
'not_installed'],
660 $repository->method(
'getLocalLanguages')->willReturn([]);
662 $manager = $this->createManager($db, $repository);
664 $result = $manager->installLanguages([]);
666 $this->assertTrue($result);
668 $this->assertStringContainsString(
669 "DELETE FROM lng_modules WHERE lang_key = 'de'",
670 implode(
"\n", $calls)
674 $updates = array_values(array_filter(
676 static fn(
string $query):
bool => str_starts_with($query,
'UPDATE object_data')
678 $this->assertCount(0, $updates);
688 $root = $this->createTempInstallationRoot();
690 $root .
'/lang/ilias_de.lang',
691 "<!-- language file start -->\n"
692 .
"assessment#:#discard_answer#:#Delete Answer###fau: testNav\n"
697 $db = $this->createDatabaseStub();
698 $db->method(
'in')->willReturn(
"module IN ('assessment')");
699 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
704 $repository = $this->createStub(InstalledLanguageRepository::class);
705 $repository->method(
'getLocalChanges')->willReturn([]);
714 $manager->insertLanguageForInstallation(
'de');
716 $insert = array_values(array_filter(
718 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_data')
720 $this->assertCount(1, $insert);
723 $this->assertStringContainsString(
"'Delete Answer'", $insert[0]);
724 $this->assertStringNotContainsString(
'Delete Answer###', $insert[0]);
727 $this->assertStringContainsString(
730 'The "###" comment suffix must be stored in the remarks column of lng_data, not discarded.'
733 $this->removeDirectory($root);
742 $root = $this->createTempInstallationRoot();
743 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'test',
'Plain Value']]);
747 $db = $this->createDatabaseStub();
748 $db->method(
'in')->willReturn(
"module IN ('common')");
749 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
754 $repository = $this->createStub(InstalledLanguageRepository::class);
755 $repository->method(
'getLocalChanges')->willReturn([]);
764 $manager->insertLanguageForInstallation(
'de');
766 $insert = array_values(array_filter(
768 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_data')
770 $this->assertCount(1, $insert);
771 $this->assertStringContainsString(
"'Plain Value'", $insert[0]);
773 $this->assertMatchesRegularExpression(
776 'Expected the tuple to end in (...,local_change=\'\',remarks=\'\') for a line without a comment suffix.'
779 $this->removeDirectory($root);
790 $root = $this->createTempInstallationRoot();
791 mkdir($root .
'/lang/file', 0777,
true);
793 $root .
'/lang/file/ilias_de.lang',
794 "<!-- language file start -->\nadd_file#:#Add File\n"
799 $db = $this->createDatabaseStub();
800 $db->method(
'in')->willReturn(
"module IN ('file')");
801 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
806 $repository = $this->createStub(InstalledLanguageRepository::class);
807 $repository->method(
'getLocalChanges')->willReturn([]);
814 $this->createPrefixedComponentDirectory(
'lang/file/',
'file')
820 $manager->insertLanguageForInstallation(
'de');
822 $insert = array_values(array_filter(
824 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_data')
826 $this->assertCount(1, $insert);
828 $this->assertStringContainsString(
"('file','add_file','de','Add File'", $insert[0]);
830 $this->removeDirectory($root);
840 $root = $this->createTempInstallationRoot();
841 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'hello',
'Welt']]);
845 $db = $this->createDatabaseStub();
846 $db->method(
'in')->willReturn(
"module IN ('common')");
847 $db->method(
'manipulate')->willReturnCallback(
static function (
string $query) use (&$calls):
int {
852 $repository = $this->createStub(InstalledLanguageRepository::class);
853 $repository->method(
'getLocalChanges')->willReturn([]);
862 $manager->insertLanguageForInstallation(
'de');
865 $inserts = array_values(array_filter(
867 static fn(
string $query):
bool => str_starts_with($query,
'INSERT INTO lng_modules')
869 $this->assertCount(1, $inserts);
870 $this->assertStringContainsString(
"'common'", $inserts[0]);
872 $this->removeDirectory($root);
879 public function __construct(
private string $path,
private string $prefix)
883 public function getPrefix():
string
885 return $this->prefix;
888 public function getPath():
string
893 public function getSuffix():
string
898 public function isLocal():
bool
907 $root = $this->createTempInstallationRoot();
908 $this->writeLangFile($root .
'/lang/ilias_de.lang', [[
'common',
'test',
'Global Value']]);
911 $db = $this->createDatabaseMock();
912 $db->method(
'in')->willReturn(
"module IN ('common')");
914 $repository = $this->createMock(InstalledLanguageRepository::class);
915 $repository->method(
'getLocalChanges')->willReturn([]);
917 $cache = $this->createMock(TranslationCache::class);
918 $cache->expects($this->once())->method(
'invalidate')->with(
'de');
929 $manager->insertLanguageForInstallation(
'de');
931 $this->removeDirectory($root);
937 $cache = $this->createMock(TranslationCache::class);
938 $cache->expects($this->once())->method(
'invalidate')->with(
'de');
941 $this->createDatabaseMock(),
943 (
string) realpath(__DIR__ .
'/../../../../../'),
944 $this->createMock(InstalledLanguageRepository::class),
949 $manager->flushLanguageForUninstallation(
'de');
954 $cache = $this->createMock(TranslationCache::class);
955 $cache->expects($this->never())->method(
'invalidate');
958 $this->createDatabaseMock(),
960 (
string) realpath(__DIR__ .
'/../../../../../'),
961 $this->createMock(InstalledLanguageRepository::class),
966 $manager->flushLanguageForInstallation(
'de');
971 $dir = sys_get_temp_dir() .
'/ilias_lang_test_' . bin2hex(random_bytes(8));
972 mkdir($dir .
'/lang/customizing', 0777,
true);
981 $lines = [
"<!-- language file start -->"];
982 foreach ($entries as [
$module, $identifier, $value]) {
983 $lines[] =
"{$module}#:#{$identifier}#:#{$value}";
985 file_put_contents($path, implode(
"\n", $lines) .
"\n");
993 $items = scandir($dir);
994 foreach ($items as $item) {
995 if ($item ===
'.' || $item ===
'..') {
998 $path = $dir .
'/' . $item;
1000 $this->removeDirectory($path);
Write access to the language installation: installing, flushing and registering languages in the data...
Pins last_update handling of the object_data bookkeeping rows: the UPDATE path sets it via the manage...
testRegisterInstalledLanguageInsertUsesDbNowNotTheClock()
testFlushLanguageForUninstallationInvalidatesTheTranslationCache()
testFlushLanguageForInstallationKeepsTheTranslationCache()
testRegisterInstalledLanguageUpdateUsesInjectedClockForLastUpdate()
testInsertLanguageForRemovingLocalChangesIgnoresCustomizingDirectory()
Reinstalling a language while removing its local changes must not re-apply the customizing directory'...
createTempInstallationRoot()
testFlushLanguageForInstallationKeepsLocalChanges()
createDatabaseStub()
Stub variant of createDatabaseMock() for tests without ->expects(): a plain createMock() there trigge...
testInstallLanguagesRegistersBrandNewLanguage()
installLanguages() registers a language that passes validation and is not yet in object_data via the ...
testInstallLanguagesDoesNotReUpdateAlreadyNotInstalledLanguage()
A language already marked "not_installed" is still flushed but gets no redundant "UPDATE ....
testLocalChangesAreLookedUpOncePerDirectoryNotPerEntry()
The local-changes lookup depends only on language and file mtime and nothing in the loop writes to th...
testInsertLanguageUsesDirectoryPrefixAsModuleForComponentFiles()
The two-field lines (identifier#:#value) of a component directory are written with the directory's pr...
createPrefixedComponentDirectory(string $path, string $prefix)
testInstallLanguagesResyncsAlreadyKnownRequestedLanguage()
A known, still requested language gets its bookkeeping row refreshed via registerInstalledLanguage(),...
testInsertLanguageForInstallationStillMergesCustomizingDirectory()
The ordinary installation path still merges the customizing directory's file on top of the global one...
removeDirectory(string $dir)
writeLangFile(string $path, array $entries)
testInsertLanguageForApplyingLocalChangesOnlyReadsCustomizingDirectory()
insertLanguageForApplyingLocalChanges() reads only the customizing directory: no base content in the ...
createManager(ilDBInterface $db, InstalledLanguageRepository $repository, ?\DateTimeImmutable $now=null)
testInsertLanguageLeavesRemarksNullWhenLineHasNoCommentSuffix()
A line without a "###" suffix leaves the remarks column NULL, not an empty string or the text "null".
testInsertLanguageInvalidatesTheTranslationCache()
testInsertLanguageStoresCommentSuffixInRemarksColumn()
A .lang line may carry a "###comment" suffix (e.g.
testFlushLanguageForUninstallationDeletesEverything()
testInstallLanguagesReportsFailedLanguageAndLeavesItUntouched()
A language failing checkLanguage() is reported as failed (a list, not true) and skipped in the second...
testInsertLanguageForApplyingLocalChangesPreservesUnrelatedSeedEntriesInModulesCache()
insertLanguage() rebuilds the lng_modules row from the seed plus the given directories: if the seed h...
testInsertLanguageDoesNotErrorForModuleWithoutContributedDirectory()
A module read from the *.lang data but never contributed as a LanguageFileDirectory (most modules,...
testInstallLanguagesSetsLastUpdateOnUninstallUsingInjectedClock()
if(!isset($arguments[0])) if(count( $arguments) > 3) if(! $remove_from_lang &&isset($arguments[2]) &&!is_dir($arguments[2])) $module
return['3gp', '7z', 'ai', 'aif', 'aifc', 'aiff', 'au', 'arw', 'avi', 'backup', 'bak', 'bas', 'bpmn', 'bpmn2', 'bmp', 'bib', 'bibtex', 'bz', 'bz2', 'c', 'c++', 'cc', 'cct', 'cdf', 'cer', 'class', 'cls', 'conf', 'cpp', 'crt', 'crs', 'crw', 'cr2', 'css', 'cst', 'csv', 'cur', 'db', 'dcr', 'des', 'dng', 'doc', 'docx', 'dot', 'dotx', 'dtd', 'dvi', 'el', 'eps', 'epub', 'f', 'f77', 'f90', 'flv', 'for', 'g3', 'gif', 'gl', 'gan', 'ggb', 'gsd', 'gsm', 'gtar', 'gz', 'gzip', 'h', 'hpp', 'htm', 'html', 'htmls', 'ibooks', 'ico', 'ics', 'ini', 'ipynb', 'java', 'jbf', 'jpeg', 'jpg', 'js', 'jsf', 'jso', 'json', 'latex', 'lang', 'less', 'log', 'lsp', 'ltx', 'm1v', 'm2a', 'm2v', 'm3u', 'm4a', 'm4v', 'markdown', 'm', 'mat', 'md', 'mdl', 'mdown', 'mid', 'min', 'midi', 'mobi', 'mod', 'mov', 'movie', 'mp2', 'mp3', 'mp4', 'mpa', 'mpeg', 'mpg', 'mph', 'mpga', 'mpp', 'mpt', 'mpv', 'mpx', 'mv', 'mw', 'mv4', 'nb', 'nbp', 'nef', 'nif', 'niff', 'obj', 'obm', 'odt', 'ods', 'odp', 'odg', 'odf', 'oga', 'ogg', 'ogv', 'old', 'p', 'pas', 'pbm', 'pcl', 'pct', 'pcx', 'pdf', 'pgm', 'pic', 'pict', 'png', 'por', 'pov', 'project', 'properties', 'ppa', 'ppm', 'pps', 'ppsx', 'ppt', 'pptx', 'ppz', 'ps', 'psd', 'pwz', 'qt', 'qtc', 'qti', 'qtif', 'r', 'ra', 'ram', 'rar', 'rast', 'rda', 'rev', 'rexx', 'ris', 'rf', 'rgb', 'rm', 'rmd', 'rmi', 'rmm', 'rmp', 'rt', 'rtf', 'rtx', 'rv', 's', 's3m', 'sav', 'sbs', 'sec', 'sdml', 'sgm', 'sgml', 'smi', 'smil', 'srt', 'sps', 'spv', 'stl', 'svg', 'swa', 'swf', 'swz', 'tar', 'tex', 'texi', 'texinfo', 'text', 'tgz', 'tif', 'tiff', 'ttf', 'txt', 'tmp', 'uvproj', 'vdf', 'vimeo', 'viv', 'vivo', 'vrml', 'vsdx', 'vtt', 'wav', 'webm', 'wmv', 'wmx', 'wmz', 'woff', 'wwd', 'xhtml', 'xif', 'xls', 'xlsx', 'xmind', 'xml', 'xsl', 'xsd', 'zip']
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
A directory of language files with a path and a prefix for them.
Read-only access to the installed languages (database) and the available or valid language files (fil...
Cache of the translations of a language, which must be invalidated whenever lng_modules changes.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc