19declare(strict_types=1);
22use PHPUnit\Framework\Attributes\DataProvider;
23use PHPUnit\Framework\TestCase;
31 private const string CALL =
'/new\s+\\\\?(?:\w+\\\\)*ComponentLanguageFileDirectory\s*\(/';
32 private const string CONTRIBUTION =
'/new\s+\\\\?(?:\w+\\\\)*ComponentLanguageFileDirectory\s*\(\s*\$this\s*,\s*([\'"])([A-Za-z0-9_]+)\1'
33 .
'(?:\s*,\s*([\'"])([^\'"]*)\3(?:\s*,\s*(?:null|([\'"])([^\'"]*)\5))?)?\s*,?\s*\)/i';
35 private static function root(): string
37 return (
string) realpath(__DIR__ .
'/../../../../../');
41 private static function code(
string $file): string
44 foreach (token_get_all((
string) file_get_contents($file)) as
$token) {
45 if (!is_array(
$token) || !in_array(
$token[0], [T_COMMENT, T_DOC_COMMENT],
true)) {
60 if ($cache !==
null) {
65 foreach (glob(self::root() .
'/components/*/*/*.php') ?: [] as $file) {
66 if (basename($file,
'.php') !== basename(dirname($file))) {
70 $calls = preg_match_all(self::CALL, $code);
71 $parsed = preg_match_all(self::CONTRIBUTION, $code, $matches, PREG_SET_ORDER);
72 if ($calls !== $parsed) {
73 $unparsed[] = substr($file, strlen(self::root()) + 1);
75 foreach ($matches as $match) {
77 $path = ($match[4] ??
'') ===
'' ?
'lang/' : $match[4];
80 'lang_dir' => dirname($file) .
'/' . trim($path,
'/'),
81 'pattern' => ($match[6] ??
'') ===
'' ?
$module .
'_%s' : $match[6],
87 return $cache = [
'modules' => $modules,
'unparsed' => $unparsed];
94 foreach (array_keys(self::contributions()[
'modules']) as
$module) {
103 self::assertGreaterThan(60, count(self::contributions()[
'modules']));
104 self::assertSame([], self::contributions()[
'unparsed'],
'ComponentLanguageFileDirectory with arguments other than string literals');
110 foreach (self::contributions()[
'modules'] as
$module => $contributions) {
111 foreach ($contributions as $contribution) {
112 $contributed[$contribution[
'lang_dir'] .
'/' . MigratedLanguageFilePaths::templateFileName($contribution[
'pattern'],
$module)] =
true;
116 foreach (glob(self::root() .
'/components/*/*/lang/*.pot') ?: [] as $pot) {
117 if (!isset($contributed[$pot])) {
118 $uncontributed[] = substr($pot, strlen(self::root()) + 1);
122 self::assertSame([], $uncontributed,
'.pot without ComponentLanguageFileDirectory contribution');
125 #[DataProvider('moduleProvider')]
129 self::assertCount(1, $contributions,
"module '$module' contributed more than once: " . json_encode(array_column($contributions,
'file')));
132 #[DataProvider('moduleProvider')]
135 foreach (self::contributions()[
'modules'][
$module] as [
'lang_dir' => $dir,
'pattern' =>
$pattern]) {
136 self::assertFileExists(
"$dir/" . MigratedLanguageFilePaths::templateFileName(
$pattern,
$module),
"module '$module': .pot missing");
137 self::assertFileExists(
"$dir/" . sprintf(
$pattern,
'en') .
'.po',
"module '$module': English .po missing");
141 #[DataProvider('moduleProvider')]
145 foreach (glob(self::root() .
'/lang/ilias_*.lang') ?: [] as $file) {
146 foreach (
new SplFileObject($file) as $number => $line) {
147 if (str_starts_with((
string) $line,
$module .
'#:#')) {
148 $offending[] = basename($file) .
':' . ($number + 1);
153 self::assertSame([], $offending,
"module '$module' still has lines in lang/ilias_*.lang");
The single place that knows where the files of a module migrated to PO/MO live:
Every module a component contributes via ComponentLanguageFileDirectory ships its ....
testContributionsAreFound()
testEveryShippedPotIsContributed()
static code(string $file)
const string CONTRIBUTION
testModuleIsRemovedFromLegacyLangFiles(string $module)
testModuleIsContributedExactlyOnce(string $module)
testModuleShipsPotAndEnglishPo(string $module)
if(!isset($arguments[0])) if(count( $arguments) > 3) if(! $remove_from_lang &&isset($arguments[2]) &&!is_dir($arguments[2])) $module