ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
convert_module_to_po.php File Reference

Go to the source code of this file.

Variables

 if (PHP_SAPI !=='cli')
 Pilot conversion tool for the PO/MO migration. More...
 
 $printable
 Makes control characters (e.g. More...
 
 $read_file
 Read once, so the lines and the hash checked by –remove-from-lang come from the same bytes. More...
 
 $body_lines
 The lines of $content the installer reads (see LanguageFileParsing::cutHeader()). More...
 
 $has_start_marker
 
 $read_lines
 
 $module_lines
 
 $entries_of
 
 $parse_module
 
 $find_duplicate_keys
 A legacy .lang file can define the same identifier twice for one module (uniqueness validation of the FR "PO-Files for improving language handling", 2.4). More...
 
 $format_keys
 
 $without_module_lines
 $content without the lines of $module - exactly those $read_lines reports, and only behind the line "<!-- language file start -->" (the installer ignores everything before it; only called for files with that line). More...
 
 $is_fuzzy_marker = LegacyFuzzyMarker::matches(...)
 Whether a ### comment is the dated "not translated yet" marker (-> "#, fuzzy") rather than a note (-> "#."), see LegacyFuzzyMarker (shared with the installation). More...
 
 $singular_form_index
 The form that serves n = 1 if it serves no other n, else null. More...
 
 $singular_form_of
 The form of the plural message $key that gets the singular key's value, or null: only if the singular key is translated (not empty, not from the reference language, no "new variable" marker) and the rule has a form for n = 1 alone. More...
 
 $plural_forms_of
 
 $copies_own_value
 Whether the own value of the plural message $key was copied into several forms (flagged fuzzy, see the file docblock). More...
 
 $build_catalog
 
 $removal_target_problem
 Why $output_argument is no place –remove-from-lang may rely on, or null: it must be the existing components/<Vendor>/<Component>/lang whose component class contributes a ComponentLanguageFileDirectory for $module there with the file name pattern $pattern - otherwise the installation would not find the .po files and the module would lose its values. More...
 
 $existing_headers
 
 $write
 
 $arguments = []
 
 $pattern = null
 
 $skip_unmigratable_keys = false
 
 $remove_from_lang = false
 
foreach(array_slice($argv, 1) as $argument) $usage
 
if(!isset($arguments[0])) if(count( $arguments) > 3) if(! $remove_from_lang &&isset($arguments[2]) &&!is_dir($arguments[2])) $module = $arguments[0]
 
 $reference_lang_key = $arguments[1] ?? 'en'
 
 try
 
catch(InvalidArgumentException $e) $repo_root = dirname(__DIR__, 5)
 
if($remove_from_lang) $plural_config_file = __DIR__ . '/plurals.json'
 
 $plural_config = ['plural_forms' => [], 'modules' => []]
 
if(is_file($plural_config_file)) else
 
 $plural_rules = []
 
 $plural_definitions
 
 $output_dir = isset($arguments[2]) ? rtrim($arguments[2], '/') : (__DIR__ . '/output/' . $module)
 
 $lang_dir = $repo_root . '/lang'
 
 $lang_files = glob($lang_dir . '/ilias_*.lang')
 
if($lang_files===[]) $per_language = []
 
 $read_files = []
 
 $files_without_marker = []
 
 $removal_problems = []
 
 $duplicates = []
 
 $unsafe_files = []
 
foreach($lang_files as $file) if( $unsafe_files !==[]) if($files_without_marker !==[] && $remove_from_lang) foreach( $files_without_marker as $file) if($removal_problems !==[]) $invalid_encoding = []
 
foreach( $per_language as $lang_key=> $entries) if($invalid_encoding !==[]) if(array_sum(array_column( $read_files, 'lines'))===0) if(!isset($per_language[$reference_lang_key])) $reference_keys = array_map('strval', array_keys($per_language[$reference_lang_key]))
 
 $duplicate_report = []
 
 $identical_duplicate_report = []
 
foreach($duplicates as $lang_key=> $keys) if( $duplicate_report !==[]) if($identical_duplicate_report !==[]) $unmigratable_keys = []
 
foreach($per_language as $lang_key=> $entries) if( $unmigratable_keys !==[] &&! $skip_unmigratable_keys) if($unmigratable_keys !==[]) $reference_entries = $per_language[$reference_lang_key]
 
 $source_lang_keys = array_values(array_unique([$reference_lang_key, 'de', 'en']))
 
if($reference_entries===[]) $markup_policy = new TranslationMarkupPolicy()
 
 $markup_report = []
 
 $markup_messages = []
 
foreach( $per_language as $lang_key=> $entries) foreach($markup_messages as $message=> $lines) $own_entry_counts = array_map('count', $per_language)
 
 $filled = []
 
foreach($per_language as $lang_key=> $entries) $plural_problems = []
 
foreach($plural_definitions as $key=> $definition) if( $plural_definitions !==[]) if($plural_problems !==[]) $language_names = []
 
 $english_lang_file = $repo_root . '/lang/ilias_en.lang'
 
if(is_file($english_lang_file)) if( $language_names===[]) foreach(array_keys($per_language) as $lang_key) $pot_path = $output_dir . '/' . MigratedLanguageFilePaths::templateFileName($pattern, $module)
 
 $contents = []
 
 $report = []
 
 $pot_headers = $existing_headers($pot_path)
 
 $all_ok = true
 
 foreach ( $report as $row)
 
if(! $all_ok) if(!is_dir($output_dir) &&! @mkdir($output_dir, 0775, true) &&!is_dir($output_dir)) $written = []
 
if(! $remove_from_lang) $new_lang_contents = []
 
 $changed_files = []
 
foreach( $read_files as $lang_key=> $read) if ( $changed_files !==[])
 
 $removed_total = 0
 
 foreach ( $new_lang_contents as $lang_key=>[ $new_content, $removed])
 

Variable Documentation

◆ $all_ok

$all_ok = true

Definition at line 1053 of file convert_module_to_po.php.

◆ $arguments

◆ $body_lines

$body_lines
Initial value:
= static function (string $content): array {
$lines = explode("\n", $content);
foreach ($lines as $number => $line) {
if (trim($line) === '<!-- language file start -->') {
return array_slice($lines, $number + 1, null, true);
}
}
return [];
}

The lines of $content the installer reads (see LanguageFileParsing::cutHeader()).

Returns
array<int, string> line number (0-based) => line, split at "\n" only like file()

Definition at line 125 of file convert_module_to_po.php.

◆ $build_catalog

$build_catalog
Parameters
array<array-key,array{valuestring, comment: ?string}> $reference_entries msgid order + fallback extracted comments
array<string,array{valuestring, comment: ?string}>|null $translation_entries null => POT (no msgstr, no fuzzy)
array<string,string>$existing_headers headers of an already existing target file
array<string,array{singular?string, plural_id?: string}> $plural_definitions msgid => definition
string | null$language_nameEnglish name of the language, null => keep an existing "Language-Team"
array<string,true>$filled_keys keys whose value was taken from the reference language (-> fuzzy)
bool$is_source_languageoriginal texts (see $source_lang_keys): a plural value copied into several forms is not fuzzy

Definition at line 394 of file convert_module_to_po.php.

◆ $changed_files

$changed_files = []

Definition at line 1092 of file convert_module_to_po.php.

◆ $contents

◆ $copies_own_value

$copies_own_value
Initial value:
= static function (
string $key,
array $definition,
array $entries,
PluralForms $plural_forms,
array $filled_keys
) use ($singular_form_of): bool {
$own_forms = $plural_forms->getCount()
- ($singular_form_of($key, $definition, $entries, $plural_forms, $filled_keys) === null ? 0 : 1);
return ($entries[$key]['value'] ?? '') !== '' && $own_forms > 1;
}
The plural rule of a language, as declared by the "Plural-Forms" header of a gettext catalog (nplural...
Definition: PluralForms.php:42
$singular_form_of
The form of the plural message $key that gets the singular key's value, or null: only if the singular...

Whether the own value of the plural message $key was copied into several forms (flagged fuzzy, see the file docblock).

Parameters
array<string,array{valuestring, comment: ?string}> $entries
array{singular?string, plural_id?: string} $definition
array<string,true>$filled_keys

Definition at line 371 of file convert_module_to_po.php.

◆ $duplicate_report

$duplicate_report = []

Definition at line 757 of file convert_module_to_po.php.

◆ $duplicates

◆ $english_lang_file

$english_lang_file = $repo_root . '/lang/ilias_en.lang'

Definition at line 896 of file convert_module_to_po.php.

◆ $entries_of

$entries_of
Initial value:
= static function (array $lines): array {
$entries = [];
foreach ($lines as [$key, $raw_value]) {
$comment = null;
$value = $raw_value;
$comment_pos = strpos($raw_value, '###');
if ($comment_pos !== false) {
$value = substr($raw_value, 0, $comment_pos);
$comment = trim(substr($raw_value, $comment_pos + 3));
}
$entries[$key] = ['value' => $value, 'comment' => $comment];
}
return $entries;
}
$comment
Definition: buildRTE.php:72
Parameters
list<array{0string, 1: string}> $lines see $module_lines - a later line of the same key wins
Returns
array<string, array{value: string, comment: ?string}>

Definition at line 191 of file convert_module_to_po.php.

◆ $existing_headers

$existing_headers
Initial value:
= static function (string $file): array {
try {
return is_file($file) ? TranslationCatalog::fromPoFile($file)->getHeaders() : [];
} catch (RuntimeException $e) {
fwrite(STDERR, "WARNING: the existing $file is not readable, its headers are not kept (the file is replaced): "
. $e->getMessage() . "\n");
return [];
}
}

Definition at line 537 of file convert_module_to_po.php.

◆ $files_without_marker

$files_without_marker = []

Definition at line 662 of file convert_module_to_po.php.

◆ $filled

$filled = []

Definition at line 860 of file convert_module_to_po.php.

◆ $find_duplicate_keys

$find_duplicate_keys
Initial value:
= static function (array $lines): array {
$raw_values = [];
foreach ($lines as [$key, $raw_value]) {
$raw_values[$key][] = $raw_value;
}
foreach ($raw_values as $key => $values) {
if (count($values) > 1) {
$duplicates[(string) $key] = count(array_unique($values)) === 1;
}
}
return $duplicates;
}

A legacy .lang file can define the same identifier twice for one module (uniqueness validation of the FR "PO-Files for improving language handling", 2.4).

Parameters
list<array{0string, 1: string}> $lines see $module_lines
Returns
array<string, bool> identifier occurring more than once => whether all occurrences have the same value and "###" comment as the installer reads them (surrounding whitespace and a part after a further "#:#" ignored)

Definition at line 222 of file convert_module_to_po.php.

◆ $format_keys

$format_keys
Initial value:
= static function (array $keys) use ($printable): string {
return implode(', ', array_map(
static fn(int|string $key): string => (string) $key === '' ? '"" (empty key)' : $printable((string) $key),
$keys
));
}
$printable
Makes control characters (e.g.
Parameters
array<array-key>$keys

Definition at line 240 of file convert_module_to_po.php.

◆ $has_start_marker

$has_start_marker
Initial value:
= static function (string $content): bool {
foreach (explode("\n", $content) as $line) {
if (trim($line) === '<!-- language file start -->') {
return true;
}
}
return false;
}

Definition at line 136 of file convert_module_to_po.php.

◆ $identical_duplicate_report

$identical_duplicate_report = []

Definition at line 758 of file convert_module_to_po.php.

◆ $invalid_encoding

foreach( $lang_files as $file) if($unsafe_files !==[]) if( $files_without_marker !==[] &&$remove_from_lang) foreach($files_without_marker as $file) if ( $removal_problems !==[]) $invalid_encoding = []

Definition at line 724 of file convert_module_to_po.php.

◆ $is_fuzzy_marker

$is_fuzzy_marker = LegacyFuzzyMarker::matches(...)

Whether a ### comment is the dated "not translated yet" marker (-> "#, fuzzy") rather than a note (-> "#."), see LegacyFuzzyMarker (shared with the installation).

Definition at line 291 of file convert_module_to_po.php.

◆ $lang_dir

$lang_dir = $repo_root . '/lang'

Definition at line 650 of file convert_module_to_po.php.

◆ $lang_files

◆ $language_names

foreach( $plural_definitions as $key=> $definition) if($plural_definitions !==[]) if ( $plural_problems !==[]) $language_names = []

Definition at line 895 of file convert_module_to_po.php.

◆ $markup_messages

$markup_messages = []

Definition at line 833 of file convert_module_to_po.php.

◆ $markup_policy

if ( $reference_entries===[]) $markup_policy = new TranslationMarkupPolicy()

◆ $markup_report

$markup_report = []

Definition at line 832 of file convert_module_to_po.php.

◆ $module

if(!isset( $arguments[0])) if(count($arguments) > 3) if (! $remove_from_lang &&isset( $arguments[2]) &&!is_dir( $arguments[2])) $module = $arguments[0]

Definition at line 597 of file convert_module_to_po.php.

Referenced by ILIAS\BookingManager\Bookings\Table\BookingsTable\__construct(), ILIAS\Language\Setup\LanguageDataNotSavedException\__construct(), ilLanguage\__destruct(), ilObjLanguageExt\_deleteValues(), ilObjLanguageExt\_getRemarks(), ilRTESettings\_getUsedHTMLTags(), ilObjLanguageExt\_getValues(), addGlobal_ilDB(), ConvertModuleToPoToolTest\addRegisteredComponent(), ILIAS\Language\ComponentTranslation\ShippedPoMerger\addToTemplate(), LanguageInstallationManagerMigratedModulesTestCase\applyLngDataDelete(), ShippedLanguageFilesCompiledObjectiveTest\artifactPath(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\assertValidModule(), ILIAS\Language\ComponentTranslation\ShippedPoMerger\backupFileNames(), ILIAS\Language\ComponentTranslation\ShippedPoMerger\backupShippedPoFiles(), PoMigrationWriteBackTest\bootstrapOverlayFromShipped(), SyncMigratedFilesAfterDeleteModeImportTest\bootstrapOverlayFromShipped(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuildTest\breakPo(), ILIAS\Init\Environment\HttpPathBuilder\build(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuildTest\build(), ilSoapFunctions\buildHTTPPath(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\buildKeys(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\buildKeysFile(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\buildMoFile(), SaveValuesMergesOntoOverlayTest\callCurrentModuleContent(), PoMigrationLoadLanguageModuleTest\callLoadFromMigratedLanguageFile(), UninstallRemovesMigratedMoFilesTest\callLoadFromMigratedLanguageFile(), MigratedPoFixture\catalog(), IdentifierTxtTest\catalog(), ILIAS\Help\Module\ModuleRetrieval\collectData(), PoMigrationLoadLanguageModuleTest\contributeFixtureModule(), PluralTxtTest\contributeModule(), ShippedPoModulesConsistencyTest\contributions(), ilObjLanguageExt\currentModuleContent(), ILIAS\Language\Activities\RepositoryProvider\currentModuleEntries(), LanguageInstallationManagerMigratedModulesTestCase\db(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\deltaOf(), ResetMigratedLocalChangesTest\directory(), ILIAS\Notifications\ilNotificationDatabaseHandler\disableListeners(), LanguageInstallationManagerMigratedModulesTestCase\droppedIdentifiers(), ILIAS\Language\ComponentTranslation\IdentifierUniqueness\duplicatesIn(), ILIAS\Language\Setup\LanguageInstallationManager\duplicatesOfCustomizingLines(), MigratedLanguageFileSyncEditableTest\editable(), ILIAS\Notifications\ilNotificationSystem\enableListeners(), ILIAS\Notifications\ilNotificationDatabaseHandler\enableListeners(), ILIAS\Notifications\ilNotificationSystem\enableUserListeners(), ilLanguage\exists(), ILIAS\Language\ComponentTranslation\IdentifierUniqueness\filterAddable(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\findCollisions(), ILIAS\Language\ComponentTranslation\IdentifierUniqueness\findDuplicatesAmong(), ILIAS\Language\Activities\RepositoryProvider\findDuplicatesOf(), ILIAS\Language\ComponentTranslation\IdentifierUniqueness\findDuplicatesOf(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\findModuleEntry(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\findModulesWithOverlay(), ILIAS\Language\ComponentTranslation\ShippedPoMerger\findShippedChangesSinceBackup(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\findShippedFiles(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\findShippedModuleFiles(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\findShippedTemplates(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\flatModuleValues(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\formerCatalog(), ILIAS\Filesystem\Configuration\DatabaseBackedFilesystemConfig\fromSettingsTable(), ilClassificationBlockGUI\getHTML(), ILIAS\Language\Activities\AddLanguageEntry\getInputDescription(), ilLanguageStatisticsTable\getItems(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\getKeys(), ILIAS\Language\ComponentTranslation\TranslationInMemoryRepository\getKeys(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\getPluralText(), ILIAS\Language\ComponentTranslation\TranslationInMemoryRepository\getPluralText(), ILIAS\Language\ComponentTranslation\MigratedTranslations\getProblem(), ilObjLanguageExt\getShippedChangesSinceBackup(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\getText(), ILIAS\Language\ComponentTranslation\TranslationInMemoryRepository\getText(), ILIAS\Notifications\ilNotificationDatabaseHandler\getUsersByListener(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\hashes(), ILIAS\Language\Activities\RepositoryProvider\hasUnreadableContent(), PoMigrationLoadLanguageModuleTest\indexedDirectory(), ilLanguagesInstalledAndUpdatedObjective\informAboutInvalidMarkupInLocalChanges(), ILIAS\Language\Setup\LanguageInstallationManager\insertLanguageForApplyingLocalChanges(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\invalidateModule(), ilObjLanguageExt\isMaintainedInPoFiles(), ILIAS\FileDelivery\Setup\DeliveryMethodObjective\isModXSendFileLoaded(), ILIAS\Language\Setup\LanguageInstallationManager\isReadableOverlay(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\isRevision(), ILIAS\Language\ComponentTranslation\MigratedTranslations\isShippedModule(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\isValidModule(), ILIAS\Language\ComponentTranslation\MigratedTranslationsTest\keys(), ILIAS\Language\Activities\RepositoryProvider\languagesWithoutPluralForm(), PoMigrationWriteBackTest\loadFixturePo(), SyncMigratedFilesAfterDeleteModeImportTest\loadFixturePo(), ilDBPdo\loadModule(), ILIAS\Language\Setup\LanguageInstallationManager\loadOverlay(), SyncMigratedFilesAfterDeleteModeImportTest\loadOverlayPo(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\loadShippedFuzzyIdentifiers(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\loadShippedModuleEntries(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\loadShippedModules(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\loadShippedNotes(), ILIAS\Language\Tests\Activities\RepositoryProviderTest\managerFor(), ilObjLanguageExt\mergeIntoDatabase(), ilObjLanguageExt\mergeLocalChangesIntoShippedPoFiles(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\moduleEntries(), ShippedPoModulesConsistencyTest\moduleProvider(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\modulesWithLocalChangesTakenOver(), ilLanguage\moduleText(), ilLanguage\moduleTexts(), ResetMigratedLocalChangesTest\overlayBase(), PoMigrationWriteBackTest\overlayBase(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\overlayDirectory(), SyncMigratedFilesAfterDeleteModeImportTest\overlayDirectory(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\overlayDomain(), AdminGuiReadsValuesFromMigratedFileTest\overlayFile(), SyncMigratedFilesAfterDeleteModeImportTest\overlayFixtureDirectories(), SyncMigratedFilesAfterDeleteModeImportTest\overlayMoExists(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\overlayMoFile(), UninstallRemovesMigratedMoFilesTest\overlayPath(), UninstallRemovesPluginMigratedMoFilesTest\overlayPath(), SyncMigratedFilesAfterDeleteModeImportTest\overlayRemarks(), ILIAS\Language\Activities\AddLanguageEntry\perform(), PluralTxtTest\pluralCatalog(), ilLanguage\pluralTxt(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\readManifest(), ilLanguage\readModuleTexts(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\readOverlayEntries(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\readPointerOf(), ilObjLanguageExt\readShippedMigratedModules(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\remarksOf(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\removeOverlayFiles(), ILIAS\Language\Setup\LanguageInstallationManager\removeOverlays(), ILIAS\Notifications\ilNotificationUserIterator\rewind(), ilHelpGUI\search(), PoMigrationWriteBackTest\seedFixtureModule(), SyncMigratedFilesAfterDeleteModeImportTest\seedFixtureModule(), LanguageInstallationManagerMigratedUnshippedOverlaysTest\seedGhostOverlay(), ResetMigratedLocalChangesTest\seedOverlay(), UninstallRemovesMigratedMoFilesTest\seedOverlay(), UninstallRemovesPluginMigratedMoFilesTest\seedOverlay(), MigratedLanguageFileSyncTestCase\seedShipped(), UninstallRemovesMigratedMoFilesTest\seedShippedModule(), UninstallRemovesPluginMigratedMoFilesTest\seedShippedModule(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\servedState(), MigratedPoFixture\servedTexts(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuildTest\servedValues(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\servesShippedPo(), ilObjLanguageExt\setOverlayRemarks(), ILIAS\ObjectGroup\Setup\ilObjectGroupRebrandMigration\settingsKeywordExists(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuildTest\ship(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\shippedDomain(), ILIAS\Language\Activities\RepositoryProvider\shippedModuleFile(), ilObjLanguageExt\shippedModuleValues(), UninstallRemovesMigratedMoFilesTest\shippedPath(), UninstallRemovesPluginMigratedMoFilesTest\shippedPath(), MigratedLanguageFileSyncTestCase\shippedPo(), ILIAS\Language\Tests\Activities\RepositoryProviderTest\shippedPoDirectory(), ILIAS\Language\ComponentTranslation\ShippedTranslationsTest\shippedPoPath(), ResetMigratedLocalChangesTest\shipPo(), ILIAS\Language\ComponentTranslation\MigratedTranslations\shipsPoFor(), ILIAS\Language\ComponentTranslation\MigratedTranslations\shipsPoWithoutBuild(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\sourceParts(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\splitPluralDelta(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\state(), ILIAS\Language\Setup\LanguageInstallationManager\syncMigratedModules(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\templateFileName(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\templateKeys(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\templateLockFile(), ILIAS\Language\Tests\Activities\AddLanguageEntryWritesTest\testAddsEntryForEachInstalledLanguageWithANonEmptyValueAndSkipsEmptyOnes(), ShippedPoMergerTest\testAFailingMarkingOfTheOverlayIsReportedAndTheFilesStayWrittenAndTheNextMergeMakesUpForIt(), ILIAS\Language\Tests\Activities\AddLanguageEntryValidationTest\testAFormKeyWithNoSuchFormInAShippedMessageRejectsTheRequestBeforeAnyWrite(), ILIAS\Language\Tests\Activities\AddLanguageEntryWritesTest\testALanguageWhoseModuleCacheUpdateReportsAnUnwrittenOverlayIsListed(), ILIAS\Language\Tests\Activities\AddLanguageEntryWritesTest\testALanguageWithUnreadableModuleContentIsReportedUnwrittenAndNeverWritten(), ILIAS\Language\Tests\Activities\AddLanguageEntryValidationTest\testAnIdentifierExistingInAnotherModuleRejectsTheRequestBeforeAnyWrite(), ILIAS\Language\Tests\Activities\AddLanguageEntryWritesTest\testASkippedLanguageIsNeverListedAsHavingAnUnwrittenOverlay(), ILIAS\Language\Tests\Activities\AddLanguageEntryWritesTest\testAThrowingReplaceLangEntryPartwayThroughTheWriteLoopLeavesEarlierLanguagesWritten(), MigratedLanguageFilePathsTest\testBuildMoFileRejectsAModuleThatIsNotAPlainFileName(), ShippedPoModulesConsistencyTest\testEveryShippedPotIsContributed(), OfflineHandlingTest\testFileObjectSupportsOfflineHandling(), UninstallRemovesPluginMigratedMoFilesTest\testIsANoOpWhenClientDataDirIsNotResolvable(), UninstallRemovesPluginMigratedMoFilesTest\testIsANoOpWhenTheModuleHasNoOverlayForALanguageItShips(), UninstallRemovesPluginMigratedMoFilesTest\testLogsAndSwallowsARemovalFailureForOneLanguageWithoutAbortingOthers(), ShippedPoMergerTest\testMergeContinuesOtherModulesWhenTheDatabaseCallbackThrowsForOne(), ShippedPoModulesConsistencyTest\testModuleIsContributedExactlyOnce(), ShippedPoModulesConsistencyTest\testModuleIsRemovedFromLegacyLangFiles(), ShippedPoModulesConsistencyTest\testModuleShipsPotAndEnglishPo(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuildTest\testServesShippedPoIsTrueOnlyForThePoTheBuildWasMadeFrom(), MigratedLanguageFilePathsTest\testTemplateFileName(), MigratedAndLegacyModulesTest\testTheModuleLoadedLastWinsAlsoAcrossMigratedAndLegacyModules(), MigratedLanguageFileSyncReadersTest\testTheShippedPoCacheNeverGrowsBeyondItsConfiguredLimit(), UninstallRemovesPluginMigratedMoFilesTest\testUninstallDoesNotTouchAnotherModulesOverlay(), UninstallRemovesPluginMigratedMoFilesTest\testUninstallRemovesBothOverlayFilesForEveryLanguageThePluginShipsButLeavesTheShippedPoUntouched(), ILIAS\Language\ComponentTranslation\MigratedTranslationsTest\text(), ilLanguage\txt(), ILIAS\Language\Activities\RepositoryProvider\updateModuleCache(), ilObjLanguageExt\updateRemark(), ILIAS\LegalDocuments\ConsumerToolbox\Blocks\userManagementAgreeDateField(), ilObjLanguageExt\withModuleLock(), ilObjLanguageExt\withoutUnreadableModules(), ILIAS\Language\ComponentTranslation\TranslationGettextRepository\withOverlay(), LanguageInstallationManagerTest\writeLangFile(), ILIAS\Language\ComponentTranslation\MigratedTranslationsTest\writeOverlay(), MigratedPoFixture\writeOverlayRevision(), ILIAS\Language\ComponentTranslation\MigratedLanguageFileSync\writeRevision(), and ShippedLanguageFilesCompiledObjectiveTest\writeShippedPo().

◆ $module_lines

$module_lines
Initial value:
= static function (string $file, string $content, string $module) use ($read_lines): array {
$lines = [];
foreach ($read_lines($file, $content) as [$mod, $key, $raw_value]) {
if ($mod === $module) {
$lines[] = [$key, $raw_value];
}
}
return $lines;
}
if(!isset($arguments[0])) if(count( $arguments) > 3) if(! $remove_from_lang &&isset($arguments[2]) &&!is_dir($arguments[2])) $module
Returns
list<array{0: string, 1: string}> [key, raw value] of every line of $module in file order

Definition at line 176 of file convert_module_to_po.php.

◆ $new_lang_contents

if (! $remove_from_lang) $new_lang_contents = []

Definition at line 1091 of file convert_module_to_po.php.

◆ $output_dir

$output_dir = isset($arguments[2]) ? rtrim($arguments[2], '/') : (__DIR__ . '/output/' . $module)

Definition at line 649 of file convert_module_to_po.php.

◆ $own_entry_counts

foreach($per_language as $lang_key=> $entries) foreach ( $markup_messages as $message=> $lines) $own_entry_counts = array_map('count', $per_language)

Definition at line 859 of file convert_module_to_po.php.

◆ $parse_module

$parse_module
Initial value:
= static function (string $file, string $module) use ($read_file, $module_lines, $entries_of): array {
return $entries_of($module_lines($file, $read_file($file), $module));
}
$read_file
Read once, so the lines and the hash checked by –remove-from-lang come from the same bytes.
Returns
array<string, array{value: string, comment: ?string}>

Definition at line 210 of file convert_module_to_po.php.

◆ $pattern

if (preg_match('/\A[A-Za-z0-9_]+\z/', $module) !==1||preg_match('/\A[A-Za-z0-9_]+\z/', $reference_lang_key) !==1) $pattern = null

Definition at line 558 of file convert_module_to_po.php.

Referenced by ILIAS\Filesystem\Finder\Finder\addVCSPattern(), ILIAS\KeyValueStorage\Subject\SubjectId\assertIdentifier(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\assertValidShippedFileNamePattern(), ILIAS\components\DataCollection\Fields\Formula\FormulaParser\Result\MathResultResolver\calculateFunctions(), ilAssLacCompositeValidator\checkOperatorExistForExpression(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuildTest\directoryWithPattern(), MigratedLanguageFilePathsTest\directoryWithPattern(), ShippedLanguageFilesCompiledObjectiveTest\directoryWithPattern(), ilShibbolethRoleAssignmentRule\doesMatch(), ILIAS\Notifications\ilNotificationDatabaseHandler\fillPlaceholders(), ilDidacticTemplateAction\filterRoles(), HTML_Template_IT\findBlocks(), ILIAS\Notifications\ilNotificationDatabaseHandler\findPlaceholders(), ILIAS\Language\ComponentTranslation\ShippedTranslationsBuild\findShippedFiles(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\findShippedPoFiles(), ilECSUpdateSteps9\fix_duplicate_import_types(), ilAuthModeDetermination\getAuthModeSequence(), ilHTLMMigration\getFileNameCallback(), ilMobMigration\getFileNameCallback(), ILIAS\Export\ImportHandler\File\XML\Export\Handler\getILIASPath(), ILIAS\Export\ImportHandler\File\Handler\getPathPart(), ILIAS\UI\Implementation\Component\Symbol\Icon\Renderer\getStandardIconPath(), iso8601_to_timestamp(), ILIAS\Refinery\String\MakeClickable\match(), ilObjLanguageExt\matchesLikePattern(), ilDBPdoMySQLFieldDefinition\matchPattern(), ilDidacticTemplateImport\parseBlockRoleAction(), ilDidacticTemplateImport\parseLocalPolicyAction(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\shippedFileNamePattern(), ilBookingManagerBookingInfoMigration\step(), ilBookingManagerObjectInfoMigration\step(), ilExercisePeerFeedbackMigration\step(), ilExerciseSampleSolutionMigration\step(), ILIAS\Language\ComponentTranslation\MigratedLanguageFilePaths\templateFileName(), MigratedLanguageFilePathsTest\testAssertValidShippedFileNamePatternAcceptsValidPatterns(), MigratedLanguageFilePathsTest\testAssertValidShippedFileNamePatternRejectsInvalidPatterns(), AdminGuiReadsValuesFromMigratedFileTest\testConsecutivePercentSignsMatchLikeASinglePercentSign(), ShippedPoModulesConsistencyTest\testModuleShipsPotAndEnglishPo(), MigratedLanguageFilePathsTest\testTemplateFileName(), AdminGuiReadsValuesFromMigratedFileTest\testThePatternFilterOfAMigratedModuleFollowsSqlLikeSemantics(), timestamp_to_iso8601(), ILIAS\components\DataCollection\Fields\Formula\FormulaParser\Token\Tokenizer\tokenizeMath(), CapabilityTest\updateREADME(), ilAssLacCompositeValidator\validateSubTree(), ilShibbolethRoleAssignmentRule\wildcardCompare(), and ilLDAPRoleAssignmentRule\wildcardCompare().

◆ $per_language

if ( $lang_files===[]) $per_language = []

Definition at line 659 of file convert_module_to_po.php.

◆ $plural_config

$plural_config = ['plural_forms' => [], 'modules' => []]

Definition at line 624 of file convert_module_to_po.php.

◆ $plural_config_file

if ( $remove_from_lang) $plural_config_file = __DIR__ . '/plurals.json'

Definition at line 623 of file convert_module_to_po.php.

◆ $plural_definitions

foreacharray< string, array{singular?:string, plural_id?:string}> $plural_definitions
Initial value:
= array_map(
static fn(mixed $definition): array => is_array($definition) ? $definition : [],
$plural_config['modules'][$module] ?? []
)

Definition at line 645 of file convert_module_to_po.php.

◆ $plural_forms_of

$plural_forms_of
Initial value:
= static function (
string $key,
array $definition,
array $entries,
PluralForms $plural_forms,
array $filled_keys
) use ($singular_form_of): array {
$forms = array_fill(0, $plural_forms->getCount(), $entries[$key]['value'] ?? '');
$singular_form = $singular_form_of($key, $definition, $entries, $plural_forms, $filled_keys);
if ($singular_form !== null) {
$forms[$singular_form] = $entries[$definition['singular']]['value'];
}
return $forms;
}
Parameters
array<string,array{valuestring, comment: ?string}> $entries
array{singular?string, plural_id?: string} $definition
array<string,true>$filled_keys
Returns
list<string>

Definition at line 349 of file convert_module_to_po.php.

◆ $plural_problems

foreach ( $per_language as $lang_key=> $entries) $plural_problems = []

Definition at line 874 of file convert_module_to_po.php.

◆ $plural_rules

$plural_rules = []

Definition at line 635 of file convert_module_to_po.php.

◆ $pot_headers

$pot_headers = $existing_headers($pot_path)

Definition at line 930 of file convert_module_to_po.php.

◆ $pot_path

if(is_file( $english_lang_file)) if($language_names===[]) foreach (array_keys( $per_language) as $lang_key) $pot_path = $output_dir . '/' . MigratedLanguageFilePaths::templateFileName($pattern, $module)

Definition at line 927 of file convert_module_to_po.php.

◆ $printable

$printable
Initial value:
= static function (string $text): string {
return addcslashes($text, "\0..\37\177");
}
$text
Definition: xapiexit.php:21

Makes control characters (e.g.

the ESC of a terminal escape sequence) visible in everything printed from a .lang file or the command line.

Definition at line 104 of file convert_module_to_po.php.

◆ $read_file

$read_file
Initial value:
= static function (string $file): string {
$content = file_get_contents($file);
if ($content === false) {
throw new RuntimeException("Cannot read $file");
}
return $content;
}

Read once, so the lines and the hash checked by –remove-from-lang come from the same bytes.

Definition at line 111 of file convert_module_to_po.php.

◆ $read_files

$read_files = []

Definition at line 661 of file convert_module_to_po.php.

Referenced by ilComponentDefinitionReaderTest\setUp().

◆ $read_lines

$read_lines
Initial value:
= static function (string $file, string $content) use ($body_lines): array {
$entries = [];
foreach ($body_lines($content) as $number => $line) {
$parts = explode('#:#', trim($line));
if (count($parts) < 3) {
continue;
}
if (count($parts) > 3) {
fwrite(STDERR, sprintf(
"WARNING: %s:%d contains \"#:#\" in its value - only the part before it is used, like the installer does.\n",
$file,
$number + 1
));
}
$entries[] = [$parts[0], $parts[1], $parts[2]];
}
return $entries;
}
$body_lines
The lines of $content the installer reads (see LanguageFileParsing::cutHeader()).
Parameters
string$contentof the .lang file $file (only named in warnings)
Returns
list<array{0: string, 1: string, 2: string}> [module, key, raw value] of every entry line

Definition at line 150 of file convert_module_to_po.php.

◆ $reference_entries

foreach( $per_language as $lang_key=> $entries) if($unmigratable_keys !==[] &&! $skip_unmigratable_keys) if ( $unmigratable_keys !==[]) $reference_entries = $per_language[$reference_lang_key]

Definition at line 819 of file convert_module_to_po.php.

◆ $reference_keys

foreach($per_language as $lang_key=> $entries) if( $invalid_encoding !==[]) if(array_sum(array_column($read_files, 'lines'))===0) if (!isset( $per_language[ $reference_lang_key])) $reference_keys = array_map('strval', array_keys($per_language[$reference_lang_key]))

Definition at line 753 of file convert_module_to_po.php.

◆ $reference_lang_key

$reference_lang_key = $arguments[1] ?? 'en'

Definition at line 598 of file convert_module_to_po.php.

◆ $removal_problems

$removal_problems = []

Definition at line 663 of file convert_module_to_po.php.

◆ $removal_target_problem

$removal_target_problem

Why $output_argument is no place –remove-from-lang may rely on, or null: it must be the existing components/<Vendor>/<Component>/lang whose component class contributes a ComponentLanguageFileDirectory for $module there with the file name pattern $pattern - otherwise the installation would not find the .po files and the module would lose its values.

A text check without bootstrap: only ‘new ComponentLanguageFileDirectory($this, ’<module>'[, '<path>'[, '<pattern>']]) with string literals as positional arguments in an assignment to$contribute[LanguageFileDirectory::class]` is recognised (comments ignored); any other form is refused.

Definition at line 479 of file convert_module_to_po.php.

◆ $remove_from_lang

$remove_from_lang = false

Definition at line 560 of file convert_module_to_po.php.

◆ $removed_total

$removed_total = 0

Definition at line 1110 of file convert_module_to_po.php.

◆ $repo_root

catch (InvalidArgumentException $e) $repo_root = dirname(__DIR__, 5)

Definition at line 612 of file convert_module_to_po.php.

◆ $report

◆ $singular_form_index

$singular_form_index
Initial value:
= static function (PluralForms $plural_forms): ?int {
if ($plural_forms->getCount() < 2) {
return null;
}
$index = $plural_forms->formIndexFor(1);
foreach ([...range(0, 200), 1000, 1001, 1011, 100000, 1000000, 1000001, 2000000] as $n) {
if ($n !== 1 && $plural_forms->formIndexFor($n) === $index) {
return null;
}
}
return $index;
}

The form that serves n = 1 if it serves no other n, else null.

Found by evaluating the rule (not its formula text): form 0 in en, de, es, it, cs, pl; form 1 in ar; null where that form also serves 0 (fr, pt), 21, 101 (ru, hr, sl) and in single-form languages.

Definition at line 298 of file convert_module_to_po.php.

◆ $singular_form_of

$singular_form_of
Initial value:
= static function (
string $key,
array $definition,
array $entries,
PluralForms $plural_forms,
array $filled_keys
$singular_key = $definition['singular'] ?? null;
if (
($entries[$key]['value'] ?? '') === ''
|| $singular_key === null
|| ($entries[$singular_key]['value'] ?? '') === ''
|| isset($filled_keys[$singular_key])
) {
return null;
}
$singular_comment = $entries[$singular_key]['comment'] ?? null;
if ($singular_comment !== null && $is_fuzzy_marker($singular_comment)) {
return null;
}
return $singular_form_index($plural_forms);
}
$singular_form_index
The form that serves n = 1 if it serves no other n, else null.
$is_fuzzy_marker
Whether a ### comment is the dated "not translated yet" marker (-> "#, fuzzy") rather than a note (->...

The form of the plural message $key that gets the singular key's value, or null: only if the singular key is translated (not empty, not from the reference language, no "new variable" marker) and the rule has a form for n = 1 alone.

Else every form keeps the own value: an untranslated placeholder must not replace a translated form.

Parameters
array<string,array{valuestring, comment: ?string}> $entries the language's entries of the module
array{singular?string, plural_id?: string} $definition
array<string,true>$filled_keys keys whose value was taken from the reference language

Definition at line 320 of file convert_module_to_po.php.

◆ $skip_unmigratable_keys

$skip_unmigratable_keys = false

Definition at line 559 of file convert_module_to_po.php.

◆ $source_lang_keys

$source_lang_keys = array_values(array_unique([$reference_lang_key, 'de', 'en']))

Definition at line 822 of file convert_module_to_po.php.

◆ $unmigratable_keys

foreach( $duplicates as $lang_key=> $keys) if($duplicate_report !==[]) if ( $identical_duplicate_report !==[]) $unmigratable_keys = []

Definition at line 788 of file convert_module_to_po.php.

◆ $unsafe_files

$unsafe_files = []

Definition at line 666 of file convert_module_to_po.php.

◆ $usage

◆ $without_module_lines

$without_module_lines

$content without the lines of $module - exactly those $read_lines reports, and only behind the line "<!-- language file start -->" (the installer ignores everything before it; only called for files with that line).

Every other byte stays: header, comments, line endings, order, a missing final line break.

Returns
array{0: string, 1: int} the new content and the number of removed lines

Definition at line 254 of file convert_module_to_po.php.

◆ $write

$write
Initial value:
= static function (string $file, string $content): void {
if (file_put_contents($file, $content) === false) {
throw new RuntimeException("Cannot write $file");
}
}

Definition at line 547 of file convert_module_to_po.php.

Referenced by ILIAS\Style\Content\Access\StyleAccessManager\enableWrite().

◆ $written

◆ else

if (is_file( $plural_config_file)) else
Initial value:
{
echo "NOTE: no plurals.json next to the tool - no Plural-Forms headers and no plural messages are written.\n"

Definition at line 632 of file convert_module_to_po.php.

◆ foreach [1/2]

foreach($new_lang_contents as $lang_key=>[$new_content, $removed]) (   $new_lang_contents as)

Definition at line 1111 of file convert_module_to_po.php.

◆ foreach [2/2]

◆ if [1/2]

foreach($read_files as $lang_key=> $read) if($changed_files !==[]) (   $changed_files ! = = [])

Definition at line 1103 of file convert_module_to_po.php.

◆ if [2/2]

if(PHP_SAPI !=='cli') ( PHP_SAPI !  = = 'cli')

Pilot conversion tool for the PO/MO migration.

Reads the legacy lang/ilias_<lang>.lang files of one language module and writes, via the language component's TranslationCatalog adapter (so the tool writes exactly what the runtime reads):

  • A POT template (<module>.pot, or the file name pattern without "%s", see –pattern)
  • One PO file per shipped language (<module>_<lang>.po, or named by –pattern)

The entries have no msgctxt: a file belongs to one module (the directory's prefix) and stays valid when the module is renamed (e.g. a plugin that becomes a component). The runtime still reads files with the module as msgctxt.

No .mo file is written: the .po files are the shipped source of truth and are compiled by Setup's build (ShippedTranslationsBuild) into artifacts/language/. The per-installation overlay only holds local changes.

Headers of an existing target .po are kept, so a re-run only changes what the .lang files changed. The "Plural-Forms" header comes from plurals.json next to this tool. "Language-Team" is the English language name from meta_l_<lang> of lang/ilias_en.lang, or, once "meta" is migrated, of a shipped components/<Vendor>/<Component>/lang/meta_en.po (default file name pattern only).

The reference language (default "en") gives the msgids, their order and the .pot. A reference key that a language lacks or has empty gets the reference value, flagged "fuzzy" (fuzzy entries are shipped like all others). A key only other languages have cannot be taken over (see –skip-unmigratable-keys). A value with markup the build cleans (TranslationMarkupPolicy) is kept (WARNING), unless cleaning leaves nothing: then it counts as missing. The reference language's "###" note becomes "#.", another own note a translator comment "# " (msgmerge keeps it).

Plural messages (plurals.json, "modules"): the tool invents no text, it distributes existing values (one taken from the reference language counts). Where the rule has a form for n = 1 alone (found by evaluating the rule: form 0 in en, de, es, it, cs, pl; form 1 in ar), that form gets the configured singular key's value - only if the language translated it (not empty, not from the reference language, no "new variable" marker) - and every other form the message's own value; otherwise every form is the own value. The msgid_plural is "<msgid>_plural" unless configured. The fuzzy flag follows the own value, and is also set where the own value was copied into several forms - except in the source languages (reference language, de, en). The singular key stays an entry of its own.

Deliberately declares no named classes or functions: this file lives inside the classmap-scanned components/ tree, and anything named here would end up in Composer's classmap and Setup's class discovery. Everything is a closure.

Usage: php convert_module_to_po.php [–pattern=<pattern>] [–skip-unmigratable-keys] [–remove-from-lang] <module> [referenceLangKey (default "en")] [outputDir] –pattern file name of a language without ".po", "%s" = language key (default "<module>_%s"); must match the pattern of the module's ComponentLanguageFileDirectory –skip-unmigratable-keys instead of failing: leave out (WARNING on stderr) every key the reference language does not have, the empty key and every key containing " [" (plural form syntax "<key> [<form>]"), and use one occurrence of a key that occurs more than once with the same value and comment every time, as the installer reads them (other duplicates of a left out key only warn, all others fail); left out keys are not part of the round-trip check –remove-from-lang only after a completely successful run (every file written and round-tripped): remove every line of the module - the left out ones included - from every lang/ilias_<lang>.lang read (atomically per file, all other bytes unchanged; computed and checked before anything is written). Requires (checked first) an existing outputDir components/<Vendor>/<Component>/lang whose <Component>.php already contributes the module's ComponentLanguageFileDirectory, no symbolic link in lang/ and the start marker in every lang/ilias_<lang>.lang <module> is required. Unknown options (anything starting with "-") and a fourth argument fail; module and reference language must match [A-Za-z0-9_]+; a given outputDir must exist. An existing unreadable target .po/.pot is replaced without its headers (WARNING). Like the installer, a .lang file is only read behind its line "<!-- language file start -->"; a file without that line is skipped with a WARNING (a FAILURE with –remove-from-lang). A module without any line in lang/ fails without writing anything (most likely migrated already). Every check runs before anything is written: a failing run writes no .po/.pot and changes no .lang file (except on write errors or a .lang file changed during the run, both reported). The self-check reads every .po back and compiles it. Example: php convert_module_to_po.php tos en ../../../TermsOfService/lang

Definition at line 84 of file convert_module_to_po.php.

◆ try

try
Initial value:
{
MigratedLanguageFilePaths::assertValidShippedFileNamePattern($pattern)

Definition at line 605 of file convert_module_to_po.php.