ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
ilObjLanguageExt Class Reference

Class ilObjLanguageExt. More...

+ Inheritance diagram for ilObjLanguageExt:
+ Collaboration diagram for ilObjLanguageExt:

Public Member Functions

 getGlobalLanguageFile ()
 Read and get the global language file as an object. More...
 
 setLocal (bool $a_local=true)
 Set the local status of the language. More...
 
 getLongDescription ()
 Get the full language description. More...
 
 getDataPath ()
 Return the path for language data written by ILIAS. More...
 
 getLangPath ()
 Get the language files path. More...
 
 getCustLangPath ()
 Get the customized language files path. More...
 
 getAllRemarks ()
 Get all remarks from the database. More...
 
 getEffectiveRemarks ()
 The remark as the admin table shows it: the local remark, else the note of the shipped .po (#, else #. More...
 
 getAllValues (array $a_modules=array(), string $a_pattern="", array $a_topics=array())
 Get all values from the database; a migrated module is read from its shipped .po with the overlay delta on top (see _getValues()). More...
 
 getChangedValues (array $a_modules=array(), string $a_pattern="", array $a_topics=array())
 Get only the changed values (source as in getAllValues()) which differ from the original language file. More...
 
 getUnchangedValues (array $a_modules=array(), string $a_pattern="", array $a_topics=array())
 Get only the unchanged values (source as in getAllValues()) which are equal to the original language file. More...
 
 getAddedValues (array $a_modules=array(), string $a_pattern='', array $a_topics=array())
 Get only the entries which don't exist in the shipped language files (see getShippedValues()) - source as in getAllValues() More...
 
 getCommentedValues (array $a_modules=array(), string $a_pattern="", array $a_topics=array())
 Get all values for which the shipped language files have a comment (see getShippedComments()) - source as in getAllValues() More...
 
 getMergedValues ()
 Get the local values merged into the shipped values (see getShippedValues()), source as in getAllValues() More...
 
 getMergedRemarks ()
 Get the local remarks merged into the comments of the shipped language files (see getShippedComments()) More...
 
 getShippedValues ()
 The global language file, except for modules maintained in PO files: their shipped .po is used (see LanguageInstallationManager). More...
 
 getShippedComments ()
 Counterpart of getShippedValues(): modules maintained in PO files contribute the comments of their shipped .po. More...
 
 getShippedCommentsForDisplay ()
 For display only (admin GUI): adds the "not translated yet" marker for fuzzy entries (see withFuzzyMarkers()). More...
 
 getModulesMaintainedInPoFiles ()
 Every module maintained in PO files for this language (its shipped .po exists). More...
 
 getUnreadableShippedPoModules ()
 The modules maintained in PO files whose shipped .po cannot be read - see getShippedValues(). More...
 
 mergeLocalChangesIntoGlobalLanguageFile (bool $write_global_file=true)
 The "merge" maintenance action of the developer mode (LANGMODE): More...
 
 hasLocalChangesOutsidePoModules ()
 Whether "merge" has something to write into the global language file: a local change (a changed remark sets local_change as well, see _saveValues()) of a module outside the PO files. More...
 
 backupShippedPoFiles (string $directory)
 The backup the filter "conflicts" compares with (see getShippedChangesSinceBackup()), written by the "save_dist" action next to the backup of the global language file. More...
 
 getShippedChangesSinceBackup (ilLanguageFile $former_file, string $po_backup_directory)
 Entries of the global language file (without modules maintained in PO files) and of their shipped .po that differ from the backup; a module without backup contributes nothing. More...
 
 getSkippedInvalidMarkupValues ()
 The values the last importLanguageFile() with $skipInvalidEntries left out for their markup. More...
 
 getSkippedDuplicateValues ()
 The values the last importLanguageFile() with $skipInvalidEntries left out as duplicates of another module. More...
 
- Public Member Functions inherited from ilObjLanguage
 __construct (int $a_id=0, bool $a_call_by_reference=false, ?LanguageFileDirectoryManager $language_file_directory_manager=null)
 Constructor. More...
 
 getKey ()
 get language key More...
 
 getStatus ()
 get language status More...
 
 isSystemLanguage ()
 check if language is system language More...
 
 isUserLanguage ()
 check if language is system language More...
 
 isInstalled ()
 Check language object status, and return true if language is installed. More...
 
 uninstall ()
 uninstall current language More...
 
 refresh ()
 refresh current language More...
 
 flush (string $a_mode="all")
 remove language data from database $a_mode "all" or "keep_local" More...
 
 getLocalChanges (string $a_min_date="", string $a_max_date="")
 get locally changed language entries More...
 
 insert ()
 insert language data from file into database, customizing included More...
 
 getModulesWithUnwrittenOverlay ()
 Modules whose PO/MO overlay could not be written or removed by the last operation (the database was written regardless). More...
 
 removeLocalChanges ()
 Reinstalls the language purely from the global/component files. More...
 
 resetUserLanguage (string $lang_key)
 search ILIAS for users which have selected '$lang_key' as their prefered language and reset them to default language (english). More...
 
 optimizeData ()
 optimizes the db-table langdata More...
 
 check (bool $shipped_only=false)
 Validate the logical structure of a lang file. More...
 
- Public Member Functions inherited from ilObject
 getObjectProperties ()
 
 flushObjectProperties ()
 
 withReferences ()
 determines whether objects are referenced or not (got ref ids or not) More...
 
 processAutoRating ()
 
 read ()
 
 getId ()
 
 setId (int $id)
 
 setRefId (int $ref_id)
 
 getRefId ()
 
 getType ()
 
 setType (string $type)
 
 getPresentationTitle ()
 get presentation title Normally same as title Overwritten for sessions More...
 
 getTitle ()
 
 getUntranslatedTitle ()
 Get untranslated object title WebDAV needs to access the untranslated title of an object. More...
 
 setTitle (string $title)
 
 getDescription ()
 
 setDescription (string $description)
 
 getLongDescription ()
 get object long description (stored in object_description) More...
 
 getImportId ()
 
 setImportId (string $import_id)
 
 setOfflineStatus (bool $status)
 
 getOfflineStatus ()
 
 supportsOfflineHandling ()
 
 getOwner ()
 
 getOwnerName ()
 get full name of object owner More...
 
 setOwner (int $usr_id)
 
 getCreateDate ()
 Get create date in YYYY-MM-DD HH-MM-SS format. More...
 
 getLastUpdateDate ()
 Get last update date in YYYY-MM-DD HH-MM-SS format. More...
 
 create ()
 note: title, description and type should be set when this function is called More...
 
 update ()
 
 MDUpdateListener (string $element)
 Metadata update listener. More...
 
 createMetaData ()
 
 updateMetaData ()
 
 deleteMetaData ()
 
 updateOwner ()
 update owner of object in db More...
 
 putInTree (int $parent_ref_id)
 maybe this method should be in tree object!? More...
 
 setPermissions (int $parent_ref_id)
 
 setParentRolePermissions (int $parent_ref_id)
 Initialize the permissions of parent roles (local roles of categories, global roles...) This method is overwritten in e.g. More...
 
 createReference ()
 creates reference for object More...
 
 countReferences ()
 
 delete ()
 delete object or referenced object (in the case of a referenced object, object data is only deleted if last reference is deleted) This function removes an object entirely from system!! More...
 
 initDefaultRoles ()
 init default roles settings Purpose of this function is to create a local role folder and local roles, that are needed depending on the object type. More...
 
 applyDidacticTemplate (int $tpl_id)
 
 getXMLZip ()
 
 getHTMLDirectory ()
 
 appendCopyInfo (int $target_id, int $copy_id, int $new_obj_id)
 Prepend Copy info if object with same name exists in that container. More...
 
 cloneDependencies (int $target_id, int $copy_id)
 Clone object dependencies. More...
 
 cloneMetaData (ilObject $target_obj)
 Copy meta data. More...
 
 selfOrParentWithRatingEnabled ()
 
 getPossibleSubObjects (bool $filter=true)
 get all possible sub objects of this type the object can decide which types of sub objects are possible jut in time overwrite if the decision distinguish from standard model More...
 

Static Public Member Functions

static _getShippedMigratedComments (string $a_lang_key, array $a_modules=[])
 For display only (like getShippedCommentsForDisplay()), e.g. More...
 
static findInvalidMarkupOfChangedValues (string $a_lang_key, array $values)
 The values a save into $a_lang_key would change and that contain markup TranslationMarkupPolicy does not allow, see TranslationMarkupPolicy::findInvalidChangedValues(). More...
 
static _getModules (string $a_lang_key)
 Get all modules of a language. More...
 
static _getRemarks (string $a_lang_key, bool $a_all_changed=false)
 Get all remarks of a language. More...
 
static _getValues (string $a_lang_key, array $a_modules=array(), array $a_topics=array(), string $a_pattern='', string $a_state='')
 Get the translations of specified topics. More...
 
static _saveValues (string $a_lang_key, array $a_values=array(), array $a_remarks=array())
 Save a set of translation in the database. More...
 
static _deleteValues (string $a_lang_key, array $a_values=array())
 Delete a set of translation in the database. More...
 
- Static Public Member Functions inherited from ilObjLanguage
static getInstalledLanguages ()
 Get the language objects of the installed languages. More...
 
static getLangKeysOfInstalledLanguages ()
 Return the language keys of the installed languages. More...
 
static refreshPlugins (?array $a_lang_keys=null)
 Refresh languages of activated plugins $a_lang_keys keys of languages to be refreshed (not yet supported, all available will be refreshed) More...
 
static _deleteLangData (string $a_lang_key, bool $a_keep_local_change=false)
 Delete languge data $a_lang_key lang key. More...
 
static _getLastLocalChange (string $a_key)
 get the date of the last local change $a_key language key Return change_date "yyyy-mm-dd hh:mm:ss" More...
 
static _getLocalChangesByModule (string $a_key, string $a_module)
 Get the local changes of a language module. More...
 
static replaceLangModule (string $a_key, string $a_module, array $a_array, bool $refresh_original_from_shipped=false)
 Replace language module array. More...
 
static replaceLangEntry (string $a_module, string $a_identifier, string $a_lang_key, string $a_value, ?string $a_local_change=null, ?string $a_remarks=null)
 Replace lang entry. More...
 
static updateLangEntry (string $a_module, string $a_identifier, string $a_lang_key, string $a_value, ?string $a_local_change=null, ?string $a_remarks=null)
 Replace lang entry. More...
 
static deleteLangEntry (string $a_module, string $a_identifier, string $a_lang_key)
 Delete lang entry. More...
 
static cut_header (array $content)
 remove lang-file haeder information from '$content' This function seeks for a special keyword where the language information starts. More...
 
static countUsers (string $a_lang)
 Count number of users that use a language. More...
 
- Static Public Member Functions inherited from ilObject
static _lookupObjIdByImportId (string $import_id)
 Get (latest) object id for an import id. More...
 
static _lookupImportId (int $obj_id)
 
static _lookupOwnerName (int $owner_id)
 Lookup owner name for owner id. More...
 
static _getIdForImportId (string $import_id)
 
static _getAllReferences (int $id)
 get all reference ids for object ID More...
 
static _lookupTitle (int $obj_id)
 
static lookupOfflineStatus (int $obj_id)
 Lookup offline status using objectDataCache. More...
 
static _lookupOwner (int $obj_id)
 Lookup owner user ID for object ID. More...
 
static _getIdsForTitle (string $title, string $type='', bool $partial_match=false)
 
static _lookupDescription (int $obj_id)
 
static _lookupLastUpdate (int $obj_id, bool $formatted=false)
 
static _getLastUpdateOfObjects (array $obj_ids)
 
static _lookupObjId (int $ref_id)
 
static _setDeletedDate (int $ref_id, int $deleted_by)
 
static setDeletedDates (array $ref_ids, int $user_id)
 
static _resetDeletedDate (int $ref_id)
 
static _lookupDeletedDate (int $ref_id)
 
static _writeTitle (int $obj_id, string $title)
 write title to db (static) More...
 
static _writeDescription (int $obj_id, string $desc)
 write description to db (static) More...
 
static _writeImportId (int $obj_id, string $import_id)
 write import id to db (static) More...
 
static _lookupType (int $id, bool $reference=false)
 
static _isInTrash (int $ref_id)
 
static _hasUntrashedReference (int $obj_id)
 checks whether an object has at least one reference that is not in trash More...
 
static _lookupObjectId (int $ref_id)
 
static _getObjectsDataForType (string $type, bool $omit_trash=false)
 get all objects of a certain type More...
 
static _exists (int $id, bool $reference=false, ?string $type=null)
 checks if an object exists in object_data More...
 
static _getObjectsByType (string $obj_type="", ?int $owner=null)
 
static _prepareCloneSelection (array $ref_ids, string $new_type, bool $show_path=true)
 Prepare copy wizard object selection. More...
 
static getIconForType (string $type)
 
static _getIcon (int $obj_id=0, string $size="big", string $type="", bool $offline=false)
 Get icon for repository item. More...
 
static collectDeletionDependencies (array &$deps, int $ref_id, int $obj_id, string $type, int $depth=0)
 Collect deletion dependencies. More...
 
static getDeletionDependencies (int $obj_id)
 Get deletion dependencies. More...
 
static getLongDescriptions (array $obj_ids)
 
static getAllOwnedRepositoryObjects (int $user_id)
 
static fixMissingTitles ($type, array &$obj_title_map)
 Try to fix missing object titles. More...
 
static _lookupCreationDate (int $obj_id)
 
static _getObjectTypeIdByTitle (string $type, ?\ilDBInterface $ilDB=null)
 

Private Member Functions

 writeLocalChangesIntoGlobalLanguageFile ()
 
 mergeLocalChangesIntoShippedPoFiles ()
 
 shippedMigratedModules ()
 
 moduleEntriesOf (array $values)
 
 syncMigratedFilesAfterDeleteModeImport (array $modules_before_delete, array $to_save, array $remarks)
 A module that existed before the "delete" wipe but is absent from the imported file is never visited by _saveValues(); its orphaned overlay would keep serving stale values. More...
 

Static Private Member Functions

static requestedLocalRemark (string $requested, string $stored, string $note)
 The shipped note itself is no local remark (''), an empty remark removes the local one; a shipped note cannot be hidden locally. More...
 
static withFuzzyMarkers (array $comments, array $shipped)
 Appends SHIPPED_FUZZY_MARKER_TOPIC to the shipped note of every fuzzy entry. More...
 
static mergeIntoDatabase (string $a_lang_key, string $module, array $identifiers, array $remark_identifiers)
 Database part of the merge into the shipped .po: the lng_data rows of $identifiers lose local_change - unlike the global language file, since the next update compares local changes with the shipped value (see LanguageInstallationManager::resolveMigratedModule()) and a remaining one would come back once the shipped value changes. More...
 
static readShippedMigratedModules (string $a_lang_key, array $only_modules=[])
 An unreadable shipped .po is logged and listed in "unreadable_modules" (its module stays in "modules"); callers decide whether that is fatal (importLanguageFile()) or a warning. More...
 
static shippedValuesAndComments (ilLanguageFile $global_file, array $shipped)
 $global_file with every readable module maintained in PO files replaced by its shipped .po, see getShippedValues(). More...
 
static withoutModules (array $values, array $modules, string $separator)
 
static matchesLikePattern (string $value, string $pattern)
 PHP counterpart of the ‘UPPER(value) LIKE UPPER(’%<pattern>')` condition of getValues() (see ilDBInterface::like()): case-insensitive, "%" any sequence, "</em>" any character, "\" escapes. More...
 
static saveValues (string $a_lang_key, array $a_values, array $a_remarks, bool $merge_onto_current_content)
 With $merge_onto_current_content false the saved entries are each module's complete new content ("delete"-mode import). More...
 
static withPluralFormKeys (array $entries, array $shipped_migrated, string $separator)
 Replaces the plain identifier of a plural message of a module maintained in PO files by the key of its default form (see MigratedLanguageFileSync::defaultFormKeyOf()), the form its lng_data row stands for. More...
 
static shippedModuleValues (array $shipped_migrated, string $module, string $separator)
 identifier => value out of the values of readShippedMigratedModules(). More...
 
static setOverlayRemarks (string $a_lang_key, string $module, array $changes)
 Writes $changes (identifier => remark, '' removes it) into the overlay; false if that failed (logged), lng_data holds them regardless. More...
 
static normalizedRemarks (array $a_remarks)
 Remarks as stored, identically for lng_data and the overlay: cut to 250 characters (not bytes); one that is not valid UTF-8 is dropped (logged), it would make the overlay unreadable. More...
 
static isMaintainedInPoFiles (string $a_lang_key, string $module)
 Whether $module is maintained in PO files for $a_lang_key (its shipped .po exists). More...
 
static updateRemark (string $module, string $identifier, string $a_lang_key, string $remark)
 Sets only the remark of an existing lng_data row ('' removes it), like replaceLangEntry() cuts it to 250 characters. More...
 
static writePluralRows (string $a_lang_key, string $module, array $content, array $shipped_values, array $plural_rows, string $save_date)
 The database holds a plural message only under its identifier, with the value of its default form, marked as local change only if that differs from the shipped default form (a local change of another form lives in the overlay only): after a rollback a later update of the legacy .lang files is not held back by it. More...
 
static currentModuleContent (string $a_lang_key, string $module)
 The content a partial save/delete is applied to: for a PO module its shipped state plus overlay, never its DB rows; null (reported) if unreadable, as applying to nothing would reset every unsaved entry. More...
 
static withoutUnreadableModules (string $a_lang_key, array $entries, string $separator, array &$skipped_modules)
 Drops the entries of modules whose content cannot be read (see currentModuleContent()), before anything is written. More...
 
static withModuleLock (string $a_lang_key, string $module, \Closure $callback)
 See MigratedLanguageFileSync::withOverlayLock(). More...
 

Private Attributes

const string SHIPPED_FUZZY_MARKER_TOPIC = 'lng_not_translated'
 Language variable of the admin GUI marker for an entry that is fuzzy (not translated yet) in its shipped .po. More...
 
array $shipped_migrated_modules = null
 
array $skipped_invalid_markup_values = []
 
array $skipped_duplicate_values = []
 

Additional Inherited Members

- Data Fields inherited from ilObjLanguage
string $separator
 separator of module, comment separator, identifier & values in language files More...
 
string $comment_separator
 
string $lang_default
 
string $lang_user
 
string $lang_path
 
string $key
 
string $status
 
string $cust_lang_path
 
string $absolute_path
 
- Data Fields inherited from ilObject
const TITLE_LENGTH = 255
 
const DESC_LENGTH = 128
 
const LONG_DESC_LENGTH = 4000
 
const TABLE_OBJECT_DATA = "object_data"
 
array $objectList
 
string $untranslatedTitle
 
- Protected Member Functions inherited from ilObject
 doMDUpdateListener (string $a_element)
 
 beforeMDUpdateListener (string $a_element)
 
 doCreateMetaData ()
 
 beforeCreateMetaData ()
 
 doUpdateMetaData ()
 
 beforeUpdateMetaData ()
 
 doDeleteMetaData ()
 
 beforeDeleteMetaData ()
 
 handleAutoRating ()
 
 hasAutoRating ()
 
- Protected Attributes inherited from ilObject
ilLogger $obj_log
 
ILIAS $ilias
 
ilObjectDefinition $obj_definition
 
ilDBInterface $db
 
ilLogger $log
 
ilErrorHandling $error
 
ilTree $tree
 
ilAppEventHandler $app_event_handler
 
ilRbacAdmin $rbac_admin
 
ilRbacReview $rbac_review
 
ilObjUser $user
 
ilLanguage $lng
 
LOMServices $lom_services
 
bool $call_by_reference
 
int $max_title = self::TITLE_LENGTH
 
int $max_desc = self::DESC_LENGTH
 
bool $add_dots = true
 
int $ref_id = null
 
string $type = ""
 
string $title = ""
 
string $desc = ""
 
string $long_desc = ""
 
int $owner = 0
 
string $create_date = ""
 
string $last_update = ""
 
string $import_id = ""
 
bool $register = false
 

Detailed Description

Member Function Documentation

◆ _deleteValues()

static ilObjLanguageExt::_deleteValues ( string  $a_lang_key,
array  $a_values = array() 
)
static

Delete a set of translation in the database.

$a_lang_key language key $a_values module.separator.topic => value

Returns
list<string> see _saveValues()

Definition at line 1751 of file class.ilObjLanguageExt.php.

1751 : array
1752 {
1753 global $DIC;
1754 $lng = $DIC->language();
1755
1756 $delete_array = array();
1758 $a_values = self::withoutUnreadableModules($a_lang_key, $a_values, $lng->separator, $modules_with_unwritten_overlay);
1759 $shipped_migrated = null;
1760 $shipped_by_module = [];
1761 $plural_rows = [];
1762 $db_comments = null;
1763 $remark_changes = [];
1764
1765 // save the single translations in lng_data
1766 foreach ($a_values as $key => $value) {
1767 $keys = explode($lng->separator, $key);
1768 if (count($keys) === 2) {
1769 $module = $keys[0];
1770 $topic = $keys[1];
1771 $delete_array[$module][$topic] = $value;
1772
1773 // a form of a plural message has no row of its own: the message's row is rewritten once, see below
1774 if (PluralFormKey::parse($topic) !== null) {
1775 $shipped_migrated ??= self::readShippedMigratedModules($a_lang_key);
1776 $shipped_by_module[$module] ??= self::shippedModuleValues($shipped_migrated, $module, $lng->separator);
1777 }
1778 $plural_identifier = isset($shipped_by_module[$module])
1779 ? MigratedLanguageFileSync::pluralMessageOf($topic, $shipped_by_module[$module])
1780 : null;
1781 if ($plural_identifier !== null) {
1782 // the remark of the identifier is kept
1783 $db_comments ??= self::_getRemarks($a_lang_key);
1784 $plural_rows[$module][$plural_identifier] = $db_comments[$module . $lng->separator . $plural_identifier] ?? null;
1785 continue;
1786 }
1787 ilObjLanguage::deleteLangEntry($module, $topic, $a_lang_key);
1788 // the remark goes with the row, for a PO module also from its overlay
1789 if (self::isMaintainedInPoFiles($a_lang_key, $module)) {
1790 $remark_changes[$module][$topic] = '';
1791 }
1792 }
1793 }
1794
1795 // save the serialized module entries in lng_modules
1796 $save_date = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->format('Y-m-d H:i:s');
1797 foreach ($delete_array as $module => $entries) {
1798 $module = (string) $module;
1799 $module_plural_rows = $plural_rows[$module] ?? [];
1800 $shipped_module_values = $shipped_by_module[$module] ?? [];
1801 $module_remark_changes = $remark_changes[$module] ?? [];
1803 $a_lang_key,
1804 $module,
1805 static function () use ($a_lang_key, $module, $entries, $module_plural_rows, $shipped_module_values, $save_date, $module_remark_changes): bool {
1806 // without a current content nothing is left to keep; the entries to delete must not be written back
1807 $current = self::currentModuleContent($a_lang_key, $module);
1808 if ($current === null) {
1809 return false;
1810 }
1811 $content = array_diff_key($current, $entries);
1812 $written = ilObjLanguage::replaceLangModule($a_lang_key, $module, $content);
1813 self::writePluralRows($a_lang_key, $module, $content, $shipped_module_values, $module_plural_rows, $save_date);
1814 return self::setOverlayRemarks($a_lang_key, $module, $module_remark_changes) && $written;
1815 }
1816 );
1817 if (!$written) {
1819 }
1820 }
1821
1823 }
static shippedModuleValues(array $shipped_migrated, string $module, string $separator)
identifier => value out of the values of readShippedMigratedModules().
static currentModuleContent(string $a_lang_key, string $module)
The content a partial save/delete is applied to: for a PO module its shipped state plus overlay,...
static readShippedMigratedModules(string $a_lang_key, array $only_modules=[])
An unreadable shipped .po is logged and listed in "unreadable_modules" (its module stays in "modules"...
static _getRemarks(string $a_lang_key, bool $a_all_changed=false)
Get all remarks of a language.
static writePluralRows(string $a_lang_key, string $module, array $content, array $shipped_values, array $plural_rows, string $save_date)
The database holds a plural message only under its identifier, with the value of its default form,...
static setOverlayRemarks(string $a_lang_key, string $module, array $changes)
Writes $changes (identifier => remark, '' removes it) into the overlay; false if that failed (logged)...
static withoutUnreadableModules(string $a_lang_key, array $entries, string $separator, array &$skipped_modules)
Drops the entries of modules whose content cannot be read (see currentModuleContent()),...
static withModuleLock(string $a_lang_key, string $module, \Closure $callback)
See MigratedLanguageFileSync::withOverlayLock().
static deleteLangEntry(string $a_module, string $a_identifier, string $a_lang_key)
Delete lang entry.
array $modules_with_unwritten_overlay
static replaceLangModule(string $a_key, string $a_module, array $a_array, bool $refresh_original_from_shipped=false)
Replace language module array.
ilLanguage $lng
if(!isset($arguments[0])) if(count( $arguments) > 3) if(! $remove_from_lang &&isset($arguments[2]) &&!is_dir($arguments[2])) $module
if(! $all_ok) if(!is_dir($output_dir) &&! @mkdir($output_dir, 0775, true) &&!is_dir($output_dir)) $written
global $DIC
Definition: shib_login.php:26

References $DIC, $lng, $module, $written, ilObjLanguage\deleteLangEntry(), and ilObjLanguage\replaceLangModule().

Referenced by ilObjLanguageExtGUI\maintainExecuteObject(), SaveValuesMergesOntoOverlayTest\testAnUnreadableModuleIsLeftOutCompletelyAndAReadableOneIsWrittenNormally(), SaveValuesWritesPluralFormsTest\testDeleteValuesKeepsTheExistingRemarkOfThePluralRow(), ImportUsesShippedValuesOfMigratedModulesTest\testDeleteValuesKeepsTheRemainingEntriesOfTheLngModulesRow(), SaveValuesOverlayRemarksTest\testDeleteValuesOfASingularKeyRemovesItsOverlayRemark(), SaveValuesWritesPluralFormsTest\testDeleteValuesOfOneFormRevertsThePluralRowToTheShippedDefaultAndDropsTheOverlayEntry(), SaveValuesOverlayRemarksTest\testDeleteValuesOfOnePluralFormKeepsTheMessagesOverlayRemark(), SaveValuesMergesOntoOverlayTest\testDeleteValuesReportsTheModuleWhoseOverlayCouldNotBeWritten(), ImportUsesShippedValuesOfMigratedModulesTest\testDeleteValuesReturnsTheMigratedModuleWhoseOverlayCouldNotBeWritten(), ImportUsesShippedValuesOfMigratedModulesTest\testDeleteValuesWithAnUnreadableLngModulesRowWritesAnEmptyModule(), and ImportUsesShippedValuesOfMigratedModulesTest\testDeleteValuesWithoutLngModulesRowWritesAnEmptyModuleWithoutWarning().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _getModules()

static ilObjLanguageExt::_getModules ( string  $a_lang_key)
static

Get all modules of a language.

$a_lang_key language key Return list of modules

Definition at line 897 of file class.ilObjLanguageExt.php.

897 : array
898 {
899 global $DIC;
900 $ilDB = $DIC->database();
901
902 $q = "SELECT DISTINCT module FROM lng_data WHERE " .
903 " lang_key = " . $ilDB->quote($a_lang_key, "text") . " order by module";
904 $set = $ilDB->query($q);
905
906 $modules = array();
907 while ($rec = $set->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
908 $modules[] = $rec["module"];
909 }
910
911 // a migrated module is included even if lng_data holds no row for it: its .po/.mo is authoritative
912 if ($DIC->offsetExists(LanguageFileDirectoryManager::class)) {
913 $migrated_modules = MigratedLanguageFileSync::getMigratedModules(
914 $DIC[LanguageFileDirectoryManager::class],
915 $a_lang_key,
916 MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH)
917 );
918 $modules = array_unique(array_merge($modules, $migrated_modules));
919 sort($modules);
920 }
921
922 return $modules;
923 }
const FETCHMODE_ASSOC

References $DIC, $ilDB, ilDBConstants\FETCHMODE_ASSOC, and ILIAS\UI\examples\Symbol\Glyph\Sort\sort().

Referenced by ilLanguageStatisticsTable\getItems(), ilLanguageExtTableGUI\initFilter(), AdminGuiReadsValuesFromMigratedFileTest\testGetModulesFallsBackToDbOnlyBehaviorWhenNoDirectoryManagerIsRegisteredAtAll(), and AdminGuiReadsValuesFromMigratedFileTest\testGetModulesIncludesAMigratedModuleEvenWithoutAnyLngDataRow().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _getRemarks()

static ilObjLanguageExt::_getRemarks ( string  $a_lang_key,
bool  $a_all_changed = false 
)
static

Get all remarks of a language.

A module maintained in PO files: remarks of its overlay win over lng_data.

$a_lang_key language key $a_all_changed include empty remarks for local changes Return array module.separator.topic => remarks

Definition at line 935 of file class.ilObjLanguageExt.php.

935 : array
936 {
937 global $DIC;
938 $ilDB = $DIC->database();
939 $lng = $DIC->language();
940
941 $q = "SELECT module, identifier, remarks"
942 . " FROM lng_data"
943 . " WHERE lang_key = " . $ilDB->quote($a_lang_key, "text");
944
945 if ($a_all_changed) {
946 $q .= " AND (remarks IS NOT NULL OR local_change IS NOT NULL)";
947 } else {
948 $q .= " AND remarks IS NOT NULL";
949 }
950
951 $result = $ilDB->query($q);
952
953 $remarks = array();
954 while ($row = $ilDB->fetchAssoc($result)) {
955 $remarks[$row["module"] . $lng->separator . $row["identifier"]] = $row["remarks"];
956 }
957
958 // A module maintained in PO files keeps its remarks in its overlay as well (see
959 // MigratedLanguageFileSync::sync()) - they win; a remark only lng_data holds (written before
960 // the overlay kept remarks) is shown until the next reconciling write takes it over
961 if ($DIC->offsetExists(LanguageFileDirectoryManager::class)) {
962 $manager = $DIC[LanguageFileDirectoryManager::class];
963 $client_data_dir = MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH);
964 foreach (MigratedLanguageFileSync::getMigratedModules($manager, $a_lang_key, $client_data_dir) as $module) {
965 try {
966 $overlay_remarks = MigratedLanguageFileSync::loadRemarks($manager, $a_lang_key, $module, $client_data_dir) ?? [];
967 } catch (\Throwable $t) {
968 $DIC->logger()->forComponent('lang')->warning(sprintf(
969 'Could not read the remarks of migrated module "%s", language "%s" - using lng_data: %s',
970 $module,
971 $a_lang_key,
972 $t->getMessage()
973 ));
974 continue;
975 }
976 foreach ($overlay_remarks as $identifier => $remark) {
977 $remarks[$module . $lng->separator . $identifier] = $remark;
978 }
979 }
980 }
981
982 return $remarks;
983 }
LanguageInstallationManager $manager

References $DIC, $ilDB, $lng, and $module.

Referenced by ilObjLanguageExtGUI\compareComments(), getAllRemarks(), getMergedRemarks(), SaveValuesOverlayRemarksTest\testGetRemarksOverlayRemarkWinsOverAStaleLngDataOne(), and SaveValuesOverlayRemarksTest\testGetRemarksShowsALngDataOnlyRemarkWithoutAnOverlayOne().

+ Here is the caller graph for this function:

◆ _getShippedMigratedComments()

static ilObjLanguageExt::_getShippedMigratedComments ( string  $a_lang_key,
array  $a_modules = [] 
)
static

For display only (like getShippedCommentsForDisplay()), e.g.

of a compare language; with $a_modules only those modules' shipped .po are read.

Parameters
list<string>$a_modules
Returns
array<string, string> module.separator.topic => comment

Definition at line 340 of file class.ilObjLanguageExt.php.

340 : array
341 {
342 $shipped = self::readShippedMigratedModules($a_lang_key, $a_modules);
343
344 return self::withFuzzyMarkers($shipped['comments'], $shipped);
345 }
static withFuzzyMarkers(array $comments, array $shipped)
Appends SHIPPED_FUZZY_MARKER_TOPIC to the shipped note of every fuzzy entry.

References readShippedMigratedModules(), and withFuzzyMarkers().

Referenced by ilObjLanguageExtGUI\compareComments(), and SaveValuesOverlayRemarksTest\testGetShippedMigratedCommentsAppendsTheFuzzyMarkerForAFuzzyEntryOnly().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _getValues()

static ilObjLanguageExt::_getValues ( string  $a_lang_key,
array  $a_modules = array(),
array  $a_topics = array(),
string  $a_pattern = '',
string  $a_state = '' 
)
static

Get the translations of specified topics.

$a_lang_key language key $a_modules list of modules $a_topics list of topics $a_pattern search pattern $a_state local change state ('changed', 'unchanged', '') Return array module.separator.topic => value

Definition at line 996 of file class.ilObjLanguageExt.php.

1002 : array {
1003 global $DIC;
1004 $ilDB = $DIC->database();
1005 $lng = $DIC->language();
1006
1007 // migrated modules are read from their .po file, exactly as ilLanguage::txt() serves them; the filters
1008 // are re-applied in PHP, mirroring the SQL WHERE clauses below
1009 $migrated_values = [];
1010 // never their (dual-written) lng_data rows, also if their files cannot be read
1011 $migrated_modules_found = [];
1012 $has_manager = $DIC->offsetExists(LanguageFileDirectoryManager::class);
1013 if ($has_manager) {
1014 $manager = $DIC[LanguageFileDirectoryManager::class];
1015 $client_data_dir = MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH);
1016 $candidate_modules = $a_modules !== [] || !MigratedLanguageFilePaths::isValidLanguageKey($a_lang_key)
1017 ? $a_modules
1018 : array_keys(MigratedLanguageFileSync::findShippedModuleFiles($manager, ILIAS_ABSOLUTE_PATH, $a_lang_key));
1019
1020 foreach ($candidate_modules as $module) {
1021 $module = (string) $module;
1022 try {
1023 $translations = MigratedLanguageFileSync::loadEditableModuleTranslations(
1024 $manager,
1025 $a_lang_key,
1026 $module,
1027 $client_data_dir,
1028 ILIAS_ABSOLUTE_PATH
1029 );
1030 } catch (\Throwable $t) {
1031 MigratedTranslations::reportProblem(sprintf(
1032 'The language file of module "%s" for "%s" cannot be read, its values are not shown: %s',
1033 $module,
1034 $a_lang_key,
1035 $t->getMessage()
1036 ));
1037 $migrated_modules_found[] = $module;
1038 continue;
1039 }
1040 if ($translations === null) {
1041 continue;
1042 }
1043 $migrated_modules_found[] = $module;
1044
1045 foreach ($translations as $identifier => $entry) {
1046 $identifier = (string) $identifier;
1047 // a plural message is listed as its forms (see PluralFormKey); a topic selects all of them
1048 if (
1049 $a_topics !== []
1050 && !in_array($identifier, $a_topics, true)
1051 && !in_array(PluralFormKey::parse($identifier)[0] ?? null, $a_topics, true)
1052 ) {
1053 continue;
1054 }
1055 if ($a_pattern !== '' && !self::matchesLikePattern($entry['value'], $a_pattern)) {
1056 continue;
1057 }
1058 if ($a_state === 'changed' && !$entry['local_change']) {
1059 continue;
1060 }
1061 if ($a_state === 'unchanged' && $entry['local_change']) {
1062 continue;
1063 }
1064 $migrated_values[$module . $lng->separator . $identifier] = $entry['value'];
1065 }
1066 }
1067 }
1068
1069 $q = "SELECT module, identifier, value FROM lng_data WHERE" .
1070 " lang_key = " . $ilDB->quote($a_lang_key, "text") . " ";
1071
1072 if ($migrated_modules_found !== []) {
1073 // excluded, not merely overridden: the dual-written lng_data copy must not appear next to the file-sourced entry
1074 $q .= " AND " . $ilDB->in("module", $migrated_modules_found, true, "text");
1075 }
1076 if (is_array($a_modules) && count($a_modules) > 0) {
1077 $q .= " AND " . $ilDB->in("module", $a_modules, false, "text");
1078 }
1079 if (is_array($a_topics) && count($a_topics) > 0) {
1080 $q .= " AND " . $ilDB->in("identifier", $a_topics, false, "text");
1081 }
1082 if ($a_pattern !== '') {
1083 $q .= " AND " . $ilDB->like("value", "text", "%" . $a_pattern . "%");
1084 }
1085 if ($a_state === "changed") {
1086 $q .= " AND NOT local_change IS NULL ";
1087 }
1088 if ($a_state === "unchanged") {
1089 $q .= " AND local_change IS NULL ";
1090 }
1091 $q .= " ORDER BY module, identifier";
1092
1093 $set = $ilDB->query($q);
1094
1095 $values = array();
1096 while ($rec = $set->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
1097 if (!$has_manager && MigratedTranslations::shipsPoFor((string) $rec["module"], $a_lang_key)) {
1098 MigratedTranslations::reportProblem(sprintf(
1099 'Without the language file directories the values of module "%s" are not shown.',
1100 $rec["module"]
1101 ));
1102 continue;
1103 }
1104 $values[$rec["module"] . $lng->separator . $rec["identifier"]] = $rec["value"];
1105 }
1106
1107 $values = array_merge($values, $migrated_values);
1108 // restores ORDER BY module, identifier for the merged-in modules: case-insensitive like *_unicode_ci, and
1109 // since "#" of the separator sorts before every character of a module name, this sorts by module first
1110 ksort($values, SORT_STRING | SORT_FLAG_CASE);
1111
1112 return $values;
1113 }

References $DIC, $lng, and $module.

Referenced by getAddedValues(), getAllValues(), getChangedValues(), getCommentedValues(), getUnchangedValues(), AdminGuiReadsValuesFromMigratedFileTest\testAnEmptySearchPatternDoesNotFilter(), AdminGuiReadsValuesFromMigratedFileTest\testAnUnreadableOverlayShowsTheShippedValuesNeverLngDataWithAWarning(), AdminGuiReadsValuesFromMigratedFileTest\testAnUnreadableShippedPoHidesTheModuleAndNeverShowsItsLngDataRows(), AdminGuiReadsValuesFromMigratedFileTest\testAppliesTheChangedStateFilterToTheMigratedModulesValues(), AdminGuiReadsValuesFromMigratedFileTest\testAppliesThePatternFilterToTheMigratedModulesValues(), AdminGuiReadsValuesFromMigratedFileTest\testAppliesTheTopicsFilterToTheMigratedModulesValues(), AdminGuiReadsValuesFromMigratedFileTest\testMergesAMigratedModuleWithANonMigratedOne(), ShippedModulesNeverReadFromDatabaseTest\testTheAdministrationListsTheShippedValuesWithoutAClientDataDirectory(), AdminGuiReadsValuesFromMigratedFileTest\testThePatternFilterOfAMigratedModuleFollowsSqlLikeSemantics(), AdminGuiReadsValuesFromMigratedFileTest\testTheSearchPatternZeroIsAppliedToLngDataAndToMigratedModules(), AdminGuiReadsValuesFromMigratedFileTest\testValueForAMigratedModuleComesFromThePoFileNotFromTheStaleDbRow(), AdminGuiReadsValuesFromMigratedFileTest\testValuesAreSortedCaseInsensitivelyByModuleAndIdentifier(), AdminGuiReadsValuesFromMigratedFileTest\testValuesForANonMigratedModuleStillComeFromLngData(), AdminGuiReadsValuesFromMigratedFileTest\testWhenSpecificModulesAreRequestedAMigratedOneAmongThemStillComesFromThePoFile(), and AdminGuiReadsValuesFromMigratedFileTest\testWithoutDirectoryManagerOnlyTheRowsOfModulesOfNoComponentAreShown().

+ Here is the caller graph for this function:

◆ _saveValues()

static ilObjLanguageExt::_saveValues ( string  $a_lang_key,
array  $a_values = array(),
array  $a_remarks = array() 
)
static

Save a set of translation in the database.

$a_lang_key language key $a_values module.separator.topic => value $a_remarks module.separator.topic => remarks

Returns
list<string> the modules whose PO/MO overlay could not be written (the database was written regardless)

Definition at line 1247 of file class.ilObjLanguageExt.php.

1251 : array {
1252 return self::saveValues($a_lang_key, $a_values, $a_remarks, true)['unwritten'];
1253 }
static saveValues(string $a_lang_key, array $a_values, array $a_remarks, bool $merge_onto_current_content)
With $merge_onto_current_content false the saved entries are each module's complete new content ("del...

Referenced by ImportLanguageFilePluralPlainKeyTest\locallyChangeDefaultForm(), ilObjLanguageExtGUI\saveObject(), ImportUsesShippedValuesOfMigratedModulesTest\testAnEmptyRemarkRemovesTheLocalRemarkAndOtherwiseWritesNothing(), ImportUsesShippedValuesOfMigratedModulesTest\testAnEmptyRemarkWithoutALocalOneWritesNothing(), ImportUsesShippedValuesOfMigratedModulesTest\testANewRemarkOverANoteIsStoredLocallyAndInTheOverlay(), SaveValuesMergesOntoOverlayTest\testAnUnreadableModuleIsLeftOutCompletelyAndAReadableOneIsWrittenNormally(), ImportUsesShippedValuesOfMigratedModulesTest\testChangingOnlyTheRemarkOfAnEntryWithAShippedNoteIsNoLocalChange(), SaveValuesOverlayRemarksTest\testChangingOnlyTheValueOfASingularIdentifierKeepsItsStoredRemark(), SaveValuesWritesPluralFormsTest\testDeleteValuesKeepsTheExistingRemarkOfThePluralRow(), SaveValuesOverlayRemarksTest\testDeleteValuesOfASingularKeyRemovesItsOverlayRemark(), SaveValuesWritesPluralFormsTest\testDeleteValuesOfOneFormRevertsThePluralRowToTheShippedDefaultAndDropsTheOverlayEntry(), SaveValuesOverlayRemarksTest\testDeleteValuesOfOnePluralFormKeepsTheMessagesOverlayRemark(), SaveValuesOverlayRemarksTest\testGetRemarksOverlayRemarkWinsOverAStaleLngDataOne(), SaveValuesOverlayRemarksTest\testPureRemarkChangeOnASingularIdentifierUpdatesRemarksAloneAndWritesTheOverlay(), SaveValuesRecreatesLngModulesAfterDeleteModeImportTest\testRecreatesTheLngModulesRowForAModulePresentInTheImport(), SaveValuesRecreatesLngModulesAfterDeleteModeImportTest\testRecreatesTheLngModulesRowForEveryModulePresentInTheImport(), SaveValuesWritesPluralFormsTest\testSaveValuesAnEmptyPostedRemarkThatDiffersFromStoredDeletesIt(), SaveValuesWritesPluralFormsTest\testSaveValuesAPureRemarkChangeWithNoValueChangeStillWritesTheRow(), ImportUsesShippedValuesOfMigratedModulesTest\testSaveValuesComparesAMigratedModuleAgainstTheShippedPoNotTheLangFile(), SaveValuesOverlayRemarksTest\testSaveValuesCutsALongRemarkToTwoHundredAndFiftyCharacters(), SaveValuesWritesPluralFormsTest\testSaveValuesDropsAFormKeyWithAnIndexBeyondTheShippedFormCount(), SaveValuesOverlayRemarksTest\testSaveValuesDropsAnInvalidUtf8RemarkWithoutSavingItAnywhere(), SaveValuesWritesPluralFormsTest\testSaveValuesExplicitFormKeyThenPlainKeyTheLaterPlainKeyWins(), SaveValuesWritesPluralFormsTest\testSaveValuesFormZeroValueChangedFormOneOnlyRemarkChangedTakesTheRemarkFromFormOne(), SaveValuesWritesPluralFormsTest\testSaveValuesKeepsTheStoredRemarkWhenNoPostedRemarkDiffersFromIt(), SaveValuesWritesPluralFormsTest\testSaveValuesMapsAPlainPluralKeyToItsDefaultFormInTheOverlayAndLngData(), ImportUsesShippedValuesOfMigratedModulesTest\testSaveValuesMarksAValueThatOnlyEqualsTheStaleLangLineAsLocalChange(), SaveValuesWritesPluralFormsTest\testSaveValuesPlainKeyThenExplicitFormKeyTheLaterFormKeyWins(), SaveValuesWritesPluralFormsTest\testSaveValuesRemarkOfThePluralRowIsTheFirstFormRemarkThatDiffersFromStored(), SaveValuesWritesPluralFormsTest\testSaveValuesResetsThePluralRowWhenEveryFormMatchesTheShippedValueAgain(), ImportUsesShippedValuesOfMigratedModulesTest\testSaveValuesReturnsNothingWhenEveryOverlayWasWritten(), ImportUsesShippedValuesOfMigratedModulesTest\testSaveValuesReturnsOnlyTheMigratedModuleWhoseOverlayCouldNotBeWrittenAndLogsIt(), SaveValuesWritesPluralFormsTest\testSaveValuesWritesOneMergedLngDataRowForAChangedPluralForm(), ImportUsesShippedValuesOfMigratedModulesTest\testSavingALocallyChangedValueBackToTheShippedOneEndsTheLocalChange(), ImportUsesShippedValuesOfMigratedModulesTest\testSavingALongShippedNoteCutToTheFieldLengthWritesNothing(), ImportUsesShippedValuesOfMigratedModulesTest\testSavingAnUnchangedEntryWithAShippedNoteIsNoLocalChange(), SaveValuesMergesOntoOverlayTest\testSavingOneKeyKeepsTheOverlaysLocalChangeOfAnotherKey(), ImportUsesShippedValuesOfMigratedModulesTest\testSavingTheNoteOfEveryFormOfAPluralMessageUnchangedWritesNothing(), and ImportUsesShippedValuesOfMigratedModulesTest\testSavingTheShippedNoteUnchangedWritesNothing().

+ Here is the caller graph for this function:

◆ backupShippedPoFiles()

ilObjLanguageExt::backupShippedPoFiles ( string  $directory)

The backup the filter "conflicts" compares with (see getShippedChangesSinceBackup()), written by the "save_dist" action next to the backup of the global language file.

Returns
list<string> the modules whose .po could not be copied

Definition at line 584 of file class.ilObjLanguageExt.php.

584 : array
585 {
586 global $DIC;
587
588 if (!$DIC->offsetExists(LanguageFileDirectoryManager::class)) {
589 return [];
590 }
591
592 return ShippedPoMerger::backupShippedPoFiles(
593 $DIC[LanguageFileDirectoryManager::class],
594 ILIAS_ABSOLUTE_PATH,
595 $this->key,
596 $directory,
597 // e.g. lang_data below the client data directory: no symbolic link out of it
598 defined('CLIENT_DATA_DIR') ? (string) CLIENT_DATA_DIR : $directory
599 );
600 }
const CLIENT_DATA_DIR
Definition: constants.php:46

References $DIC, and CLIENT_DATA_DIR.

◆ currentModuleContent()

static ilObjLanguageExt::currentModuleContent ( string  $a_lang_key,
string  $module 
)
staticprivate

The content a partial save/delete is applied to: for a PO module its shipped state plus overlay, never its DB rows; null (reported) if unreadable, as applying to nothing would reset every unsaved entry.

Other modules: the lng_modules row, [] if none.

Must be called under the module's overlay lock (see withModuleLock()).

Returns
array<string, string>|null identifier => value

Definition at line 1642 of file class.ilObjLanguageExt.php.

1642 : ?array
1643 {
1644 global $DIC;
1645
1646 if ($DIC->offsetExists(LanguageFileDirectoryManager::class)) {
1647 try {
1648 $content = MigratedLanguageFileSync::loadEditableModuleTranslations(
1649 $DIC[LanguageFileDirectoryManager::class],
1650 $a_lang_key,
1651 $module,
1652 MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH),
1653 ILIAS_ABSOLUTE_PATH,
1654 true
1655 );
1656 } catch (\Throwable $t) {
1657 MigratedTranslations::reportProblem(sprintf(
1658 'The language file of module "%s" for "%s" cannot be read, the changes are not saved: %s',
1659 $module,
1660 $a_lang_key,
1661 $t->getMessage()
1662 ));
1663 return null;
1664 }
1665 if ($content !== null) {
1666 return array_map(static fn(array $entry): string => $entry['value'], $content);
1667 }
1668 } elseif (MigratedTranslations::shipsPoFor($module, $a_lang_key)) {
1669 MigratedTranslations::reportProblem(sprintf(
1670 'Without the language file directories the changes of module "%s" are not saved.',
1671 $module
1672 ));
1673 return null;
1674 }
1675
1676 $ilDB = $DIC->database();
1677 $set = $ilDB->query(sprintf(
1678 "SELECT lang_array FROM lng_modules WHERE lang_key = %s AND module = %s",
1679 $ilDB->quote($a_lang_key, "text"),
1680 $ilDB->quote($module, "text")
1681 ));
1682 $row = $ilDB->fetchAssoc($set);
1683 $content = is_array($row) && isset($row["lang_array"])
1684 ? unserialize((string) $row["lang_array"], ["allowed_classes" => false])
1685 : null;
1686
1687 return is_array($content) ? $content : [];
1688 }

References $DIC, $ilDB, and $module.

◆ findInvalidMarkupOfChangedValues()

static ilObjLanguageExt::findInvalidMarkupOfChangedValues ( string  $a_lang_key,
array  $values 
)
static

The values a save into $a_lang_key would change and that contain markup TranslationMarkupPolicy does not allow, see TranslationMarkupPolicy::findInvalidChangedValues().

Parameters
array<string,string>$values
Returns
array<string, list<string>> key => violations

Definition at line 642 of file class.ilObjLanguageExt.php.

642 : array
643 {
644 // current and shipped values are only read if a value breaks the rules at all
646 $candidates = array_intersect_key($values, $policy->findInvalidValues($values));
647 if ($candidates === []) {
648 return [];
649 }
650 [$shipped_values] = self::shippedValuesAndComments(
652 self::readShippedMigratedModules($a_lang_key)
653 );
654
655 return $policy->findInvalidChangedValues($candidates, self::_getValues($a_lang_key), $shipped_values);
656 }
The HTML a translation value may contain, decided in one place for the shipped files (cleaned in Setu...
static _getGlobalLanguageFile(string $a_lang_key)
Read and get a global language file as a singleton object $a_lang_key language key.
static shippedValuesAndComments(ilLanguageFile $global_file, array $shipped)
$global_file with every readable module maintained in PO files replaced by its shipped ....

References $policy, ilLanguageFile\_getGlobalLanguageFile(), and shippedValuesAndComments().

Referenced by ilObjLanguageExtGUI\saveObject(), SaveValuesMergesOntoOverlayTest\testFindInvalidMarkupOfChangedValuesAppliesTheCurrentAndShippedComparison(), and SaveValuesMergesOntoOverlayTest\testFindInvalidMarkupOfChangedValuesNeverReadsCurrentOrShippedValuesWhenNothingIsSuspicious().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getAddedValues()

ilObjLanguageExt::getAddedValues ( array  $a_modules = array(),
string  $a_pattern = '',
array  $a_topics = array() 
)

Get only the entries which don't exist in the shipped language files (see getShippedValues()) - source as in getAllValues()

$a_modules list of modules $a_pattern search pattern $a_topics list of topics Return array module.separator.topic => value

Definition at line 234 of file class.ilObjLanguageExt.php.

234 : array
235 {
236 $local_values = self::_getValues($this->key, $a_modules, $a_topics, $a_pattern);
237
238 return array_diff_key($local_values, $this->getShippedValues());
239 }
getShippedValues()
The global language file, except for modules maintained in PO files: their shipped ....
static _getValues(string $a_lang_key, array $a_modules=array(), array $a_topics=array(), string $a_pattern='', string $a_state='')
Get the translations of specified topics.

References _getValues(), and getShippedValues().

+ Here is the call graph for this function:

◆ getAllRemarks()

ilObjLanguageExt::getAllRemarks ( )

Get all remarks from the database.

Return array module.separator.topic => remark

Definition at line 136 of file class.ilObjLanguageExt.php.

136 : array
137 {
138 return self::_getRemarks($this->key);
139 }

References _getRemarks().

Referenced by getEffectiveRemarks().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getAllValues()

ilObjLanguageExt::getAllValues ( array  $a_modules = array(),
string  $a_pattern = "",
array  $a_topics = array() 
)

Get all values from the database; a migrated module is read from its shipped .po with the overlay delta on top (see _getValues()).

$a_modules list of modules $a_pattern search pattern $a_topics list of topics Return array module.separator.topic => value

Definition at line 193 of file class.ilObjLanguageExt.php.

193 : array
194 {
195 return self::_getValues($this->key, $a_modules, $a_topics, $a_pattern);
196 }

References _getValues().

Referenced by getShippedChangesSinceBackup().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getChangedValues()

ilObjLanguageExt::getChangedValues ( array  $a_modules = array(),
string  $a_pattern = "",
array  $a_topics = array() 
)

Get only the changed values (source as in getAllValues()) which differ from the original language file.

$a_modules list of modules $a_pattern search pattern $a_topics list of topics Return array module.separator.topic => value

Definition at line 208 of file class.ilObjLanguageExt.php.

208 : array
209 {
210 return self::_getValues($this->key, $a_modules, $a_topics, $a_pattern, "changed");
211 }

References _getValues().

+ Here is the call graph for this function:

◆ getCommentedValues()

ilObjLanguageExt::getCommentedValues ( array  $a_modules = array(),
string  $a_pattern = "",
array  $a_topics = array() 
)

Get all values for which the shipped language files have a comment (see getShippedComments()) - source as in getAllValues()

Note: This function checks the comments in the shipped language files, not the remarks in the database!

$a_modules list of modules $a_pattern search pattern $a_topics list of topics Return array module.separator.topic => value

Definition at line 254 of file class.ilObjLanguageExt.php.

254 : array
255 {
256 $local_values = self::_getValues($this->key, $a_modules, $a_topics, $a_pattern);
257
258 return array_intersect_key($local_values, $this->getShippedComments());
259 }
getShippedComments()
Counterpart of getShippedValues(): modules maintained in PO files contribute the comments of their sh...

References _getValues(), and getShippedComments().

+ Here is the call graph for this function:

◆ getCustLangPath()

ilObjLanguageExt::getCustLangPath ( )

Get the customized language files path.

Return path of customized language files folder

Definition at line 126 of file class.ilObjLanguageExt.php.

126 : string
127 {
129 }

References ilObjLanguage\$cust_lang_path.

Referenced by mergeLocalChangesIntoShippedPoFiles().

+ Here is the caller graph for this function:

◆ getDataPath()

ilObjLanguageExt::getDataPath ( )

Return the path for language data written by ILIAS.

Definition at line 103 of file class.ilObjLanguageExt.php.

103 : string
104 {
105 if (!is_dir(CLIENT_DATA_DIR . "/lang_data")) {
107 }
108 return CLIENT_DATA_DIR . "/lang_data";
109 }
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...

References CLIENT_DATA_DIR, and ilFileUtils\makeDir().

+ Here is the call graph for this function:

◆ getEffectiveRemarks()

ilObjLanguageExt::getEffectiveRemarks ( )

The remark as the admin table shows it: the local remark, else the note of the shipped .po (#, else #.

; plural notes are listed per form, see PluralFormKey). saveValues() compares against the same remarks.

Returns
array<string, string> module.separator.topic => remark, no empty ones

Definition at line 147 of file class.ilObjLanguageExt.php.

147 : array
148 {
149 $local_remarks = array_filter(
150 array_map(static fn(?string $remark): string => (string) $remark, $this->getAllRemarks()),
151 static fn(string $remark): bool => $remark !== ''
152 );
153 $shipped = $this->shippedMigratedModules();
154 $readable_modules = array_diff($shipped['modules'], $shipped['unreadable_modules']);
155 $remarks = [];
156 foreach ($shipped['comments'] as $key => $note) {
157 $keys = explode($this->separator, (string) $key, 2);
158 if (count($keys) !== 2 || !in_array($keys[0], $readable_modules, true) || (string) $note === '') {
159 continue;
160 }
161 $message_key = $keys[0] . $this->separator . (PluralFormKey::parse($keys[1])[0] ?? $keys[1]);
162 if (!isset($local_remarks[$key]) && !isset($local_remarks[$message_key])) {
163 $remarks[$key] = (string) $note;
164 }
165 }
166
167 return array_merge($remarks, $local_remarks);
168 }
getAllRemarks()
Get all remarks from the database.

References ilObjLanguage\$key, getAllRemarks(), and shippedMigratedModules().

+ Here is the call graph for this function:

◆ getGlobalLanguageFile()

ilObjLanguageExt::getGlobalLanguageFile ( )

Read and get the global language file as an object.

Lines of modules maintained in PO files are not that module's source, see getShippedValues()/getShippedComments().

Definition at line 66 of file class.ilObjLanguageExt.php.

67 {
69 }
Class ilLanguageFile.

References ilLanguageFile\_getGlobalLanguageFile().

Referenced by getShippedChangesSinceBackup(), getShippedComments(), getShippedValues(), and writeLocalChangesIntoGlobalLanguageFile().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getLangPath()

ilObjLanguageExt::getLangPath ( )

Get the language files path.

Return path of language files folder

Definition at line 116 of file class.ilObjLanguageExt.php.

116 : string
117 {
118 return $this->lang_path;
119 }

References ilObjLanguage\$lang_path.

◆ getLongDescription()

ilObjLanguageExt::getLongDescription ( )

Get the full language description.

Return description

Reimplemented from ilObject.

Definition at line 94 of file class.ilObjLanguageExt.php.

94 : string
95 {
96 return $this->lng->txt($this->desc);
97 }

References ILIAS\Repository\lng().

+ Here is the call graph for this function:

◆ getMergedRemarks()

ilObjLanguageExt::getMergedRemarks ( )

Get the local remarks merged into the comments of the shipped language files (see getShippedComments())

The returned array contains:

  1. all comments that exist in the shipped language files, with their local values, ordered like in the global language file (modules maintained in PO files last)
  2. all additional local remarks, ordered by module and identifier

Return array module.separator.topic => value

Definition at line 292 of file class.ilObjLanguageExt.php.

292 : array
293 {
294 // Get remarks including empty remarks for local changes
295 $local_remarks = self::_getRemarks($this->key, true);
296
297 return array_merge($this->getShippedComments(), $local_remarks);
298 }

References _getRemarks(), and getShippedComments().

+ Here is the call graph for this function:

◆ getMergedValues()

ilObjLanguageExt::getMergedValues ( )

Get the local values merged into the shipped values (see getShippedValues()), source as in getAllValues()

The returned array contains:

  1. all entries that exist in the shipped language files, with their local values, ordered like in the global language file (modules maintained in PO files last)
  2. all additional local entries, ordered by module and identifier

Not for writing the global language file - see mergeLocalChangesIntoGlobalLanguageFile().

Return array module.separator.topic => value

Definition at line 275 of file class.ilObjLanguageExt.php.

275 : array
276 {
277 return array_merge($this->getShippedValues(), self::_getValues($this->key));
278 }

References getShippedValues().

+ Here is the call graph for this function:

◆ getModulesMaintainedInPoFiles()

ilObjLanguageExt::getModulesMaintainedInPoFiles ( )

Every module maintained in PO files for this language (its shipped .po exists).

Returns
list<string>

Definition at line 381 of file class.ilObjLanguageExt.php.

381 : array
382 {
383 return $this->shippedMigratedModules()['modules'];
384 }

References shippedMigratedModules().

Referenced by writeLocalChangesIntoGlobalLanguageFile().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getShippedChangesSinceBackup()

ilObjLanguageExt::getShippedChangesSinceBackup ( ilLanguageFile  $former_file,
string  $po_backup_directory 
)

Entries of the global language file (without modules maintained in PO files) and of their shipped .po that differ from the backup; a module without backup contributes nothing.

Returns
array<string, string> module.separator.identifier => current shipped value

Definition at line 608 of file class.ilObjLanguageExt.php.

608 : array
609 {
610 global $DIC;
611
612 $changes = self::withoutModules(
613 array_diff_assoc($this->getGlobalLanguageFile()->getAllValues(), $former_file->getAllValues()),
614 $this->getModulesMaintainedInPoFiles(),
615 $this->separator
616 );
617 if (!$DIC->offsetExists(LanguageFileDirectoryManager::class)) {
618 return $changes;
619 }
620 $po_changes = ShippedPoMerger::findShippedChangesSinceBackup(
621 $DIC[LanguageFileDirectoryManager::class],
622 ILIAS_ABSOLUTE_PATH,
623 $this->key,
624 $po_backup_directory
625 );
626 foreach ($po_changes['changes'] as $module => $values) {
627 foreach ($values as $identifier => $value) {
628 $changes[$module . $this->separator . $identifier] = $value;
629 }
630 }
631
632 return $changes;
633 }
getAllValues()
Get array of all values Return array [module.separator.identifier => value].
getGlobalLanguageFile()
Read and get the global language file as an object.
getAllValues(array $a_modules=array(), string $a_pattern="", array $a_topics=array())
Get all values from the database; a migrated module is read from its shipped .po with the overlay del...
static withoutModules(array $values, array $modules, string $separator)

References $DIC, $module, ilLanguageFile\getAllValues(), getAllValues(), getGlobalLanguageFile(), and withoutModules().

+ Here is the call graph for this function:

◆ getShippedComments()

ilObjLanguageExt::getShippedComments ( )

Counterpart of getShippedValues(): modules maintained in PO files contribute the comments of their shipped .po.

Returns
array<string, string> module.separator.topic => comment

Definition at line 317 of file class.ilObjLanguageExt.php.

317 : array
318 {
320 }

References getGlobalLanguageFile(), shippedMigratedModules(), and shippedValuesAndComments().

Referenced by getCommentedValues(), getMergedRemarks(), and getShippedCommentsForDisplay().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getShippedCommentsForDisplay()

ilObjLanguageExt::getShippedCommentsForDisplay ( )

For display only (admin GUI): adds the "not translated yet" marker for fuzzy entries (see withFuzzyMarkers()).

The marker is no comment: not exported, not filtered for, not compared on saving.

Returns
array<string, string> module.separator.topic => comment

Definition at line 328 of file class.ilObjLanguageExt.php.

328 : array
329 {
331 }

References getShippedComments(), shippedMigratedModules(), and withFuzzyMarkers().

+ Here is the call graph for this function:

◆ getShippedValues()

ilObjLanguageExt::getShippedValues ( )

The global language file, except for modules maintained in PO files: their shipped .po is used (see LanguageInstallationManager).

An unreadable .po keeps that module's .lang lines as approximation; logged and reported by getUnreadableShippedPoModules().

Returns
array<string, string> module.separator.topic => value

Definition at line 307 of file class.ilObjLanguageExt.php.

307 : array
308 {
310 }

References getGlobalLanguageFile(), shippedMigratedModules(), and shippedValuesAndComments().

Referenced by getAddedValues(), and getMergedValues().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getSkippedDuplicateValues()

ilObjLanguageExt::getSkippedDuplicateValues ( )

The values the last importLanguageFile() with $skipInvalidEntries left out as duplicates of another module.

Returns
array<string, list<string>> module.separator.identifier => "<module>: <identifier>" it would duplicate

Definition at line 673 of file class.ilObjLanguageExt.php.

673 : array
674 {
676 }

References $skipped_duplicate_values.

◆ getSkippedInvalidMarkupValues()

ilObjLanguageExt::getSkippedInvalidMarkupValues ( )

The values the last importLanguageFile() with $skipInvalidEntries left out for their markup.

Returns
array<string, list<string>> module.separator.identifier => violations

Definition at line 663 of file class.ilObjLanguageExt.php.

663 : array
664 {
666 }

References $skipped_invalid_markup_values.

◆ getUnchangedValues()

ilObjLanguageExt::getUnchangedValues ( array  $a_modules = array(),
string  $a_pattern = "",
array  $a_topics = array() 
)

Get only the unchanged values (source as in getAllValues()) which are equal to the original language file.

Return array module.separator.topic => value

Definition at line 220 of file class.ilObjLanguageExt.php.

220 : array
221 {
222 return self::_getValues($this->key, $a_modules, $a_topics, $a_pattern, "unchanged");
223 }

References _getValues().

+ Here is the call graph for this function:

◆ getUnreadableShippedPoModules()

ilObjLanguageExt::getUnreadableShippedPoModules ( )

The modules maintained in PO files whose shipped .po cannot be read - see getShippedValues().

Returns
list<string>

Definition at line 391 of file class.ilObjLanguageExt.php.

391 : array
392 {
393 return $this->shippedMigratedModules()['unreadable_modules'];
394 }

References shippedMigratedModules().

+ Here is the call graph for this function:

◆ hasLocalChangesOutsidePoModules()

ilObjLanguageExt::hasLocalChangesOutsidePoModules ( )

Whether "merge" has something to write into the global language file: a local change (a changed remark sets local_change as well, see _saveValues()) of a module outside the PO files.

Shipped comments do not count.

Definition at line 433 of file class.ilObjLanguageExt.php.

433 : bool
434 {
435 global $DIC;
436 $ilDB = $DIC->database();
437
438 $ilDB->setLimit(1, 0);
439 $result = $ilDB->query(
440 "SELECT 1 FROM lng_data WHERE lang_key = " . $ilDB->quote($this->key, "text")
441 . " AND local_change IS NOT NULL"
442 . " AND " . $ilDB->in("module", $this->getModulesMaintainedInPoFiles(), true, "text")
443 );
444
445 return $ilDB->fetchAssoc($result) !== null;
446 }

References $DIC, and $ilDB.

◆ isMaintainedInPoFiles()

static ilObjLanguageExt::isMaintainedInPoFiles ( string  $a_lang_key,
string  $module 
)
staticprivate

Whether $module is maintained in PO files for $a_lang_key (its shipped .po exists).

Definition at line 1563 of file class.ilObjLanguageExt.php.

1563 : bool
1564 {
1565 global $DIC;
1566
1567 return $DIC->offsetExists(LanguageFileDirectoryManager::class)
1568 && isset(MigratedLanguageFileSync::findShippedModuleFiles(
1569 $DIC[LanguageFileDirectoryManager::class],
1570 ILIAS_ABSOLUTE_PATH,
1571 $a_lang_key
1572 )[$module]);
1573 }

References $DIC, and $module.

◆ matchesLikePattern()

static ilObjLanguageExt::matchesLikePattern ( string  $value,
string  $pattern 
)
staticprivate

PHP counterpart of the ‘UPPER(value) LIKE UPPER(’%<pattern>')` condition of getValues() (see ilDBInterface::like()): case-insensitive, "%" any sequence, "</em>" any character, "\" escapes.

Not replicated: accent-insensitivity of *_unicode_ci. Consecutive "%" collapse to one ".*" to avoid needless backtracking.

Definition at line 1215 of file class.ilObjLanguageExt.php.

1215 : bool
1216 {
1217 $regex = '';
1218 $length = mb_strlen($pattern);
1219 $previous_was_any_sequence = false;
1220 for ($i = 0; $i < $length; $i++) {
1221 $char = mb_substr($pattern, $i, 1);
1222 $is_any_sequence = $char === '%';
1223 if ($char === '\\' && $i + 1 < $length) {
1224 $regex .= preg_quote(mb_substr($pattern, ++$i, 1), '/');
1225 } elseif ($is_any_sequence) {
1226 $regex .= $previous_was_any_sequence ? '' : '.*';
1227 } elseif ($char === '_') {
1228 $regex .= '.';
1229 } else {
1230 $regex .= preg_quote($char, '/');
1231 }
1232 $previous_was_any_sequence = $is_any_sequence;
1233 }
1234
1235 return preg_match('/' . $regex . '/isu', $value) === 1;
1236 }

References $pattern.

◆ mergeIntoDatabase()

static ilObjLanguageExt::mergeIntoDatabase ( string  $a_lang_key,
string  $module,
array  $identifiers,
array  $remark_identifiers 
)
staticprivate

Database part of the merge into the shipped .po: the lng_data rows of $identifiers lose local_change - unlike the global language file, since the next update compares local changes with the shipped value (see LanguageInstallationManager::resolveMigratedModule()) and a remaining one would come back once the shipped value changes.

The remarks of $remark_identifiers became comments of the .po and are removed. lng_modules is unchanged.

Parameters
list<string>$identifiers
list<string>$remark_identifiers

Definition at line 559 of file class.ilObjLanguageExt.php.

559 : void
560 {
561 global $DIC;
562 $ilDB = $DIC->database();
563
564 foreach (['local_change' => $identifiers, 'remarks' => $remark_identifiers] as $column => $keys) {
565 if ($keys === []) {
566 continue;
567 }
568 $ilDB->manipulate(sprintf(
569 "UPDATE lng_data SET %s = NULL WHERE lang_key = %s AND module = %s AND %s",
570 $column,
571 $ilDB->quote($a_lang_key, "text"),
572 $ilDB->quote($module, "text"),
573 $ilDB->in("identifier", $keys, false, "text")
574 ));
575 }
576 }

References $DIC, $ilDB, and $module.

Referenced by mergeLocalChangesIntoShippedPoFiles().

+ Here is the caller graph for this function:

◆ mergeLocalChangesIntoGlobalLanguageFile()

ilObjLanguageExt::mergeLocalChangesIntoGlobalLanguageFile ( bool  $write_global_file = true)

The "merge" maintenance action of the developer mode (LANGMODE):

  • modules not maintained in PO files go into the global language file (not if $write_global_file is false), the lines of modules maintained in PO files stay as read (see ilLanguageFile::keepOriginalLines());
  • modules maintained in PO files with local changes go into their shipped .po (new entries into the .pot, see ShippedPoMerger), after a backup into the customizing directory. The lng_data rows of taken over entries lose local_change, and their remarks where these became comments of the .po (see mergeIntoDatabase()). The overlay keeps serving the taken over values until "setup build" (the web server does not build) and "setup update" ran.
Returns
array{ written: list<string>, skipped: list<string>, invalid_markup: array<string, list<string>>, not_merged: list<string>, unwritten_database: list<string> } for the modules maintained in PO files: written - shipped .po files written (relative to the ILIAS directory); skipped - modules left out as a whole (logged); invalid_markup - module.separator.identifier => violations of values not taken over; not_merged - module.separator.identifier of entries not taken over (logged); unwritten_database - modules whose lng_data rows could not be updated (logged; their files are written)

Definition at line 417 of file class.ilObjLanguageExt.php.

417 : array
418 {
419 if ($write_global_file) {
421 }
422
423 $result = $this->mergeLocalChangesIntoShippedPoFiles();
424 $this->shipped_migrated_modules = null;
425
426 return $result;
427 }

References mergeLocalChangesIntoShippedPoFiles(), and writeLocalChangesIntoGlobalLanguageFile().

+ Here is the call graph for this function:

◆ mergeLocalChangesIntoShippedPoFiles()

ilObjLanguageExt::mergeLocalChangesIntoShippedPoFiles ( )
private
Returns
array{written: list<string>, skipped: list<string>, invalid_markup: array<string, list<string>>, not_merged: list<string>, unwritten_database: list<string>}

Definition at line 472 of file class.ilObjLanguageExt.php.

472 : array
473 {
474 global $DIC;
475
476 $result = ['written' => [], 'skipped' => [], 'invalid_markup' => [], 'not_merged' => [], 'unwritten_database' => []];
477 if (!$DIC->offsetExists(LanguageFileDirectoryManager::class)) {
478 return $result;
479 }
480 $lang_key = $this->key;
481 $merged = ShippedPoMerger::merge(
482 $DIC[LanguageFileDirectoryManager::class],
483 ILIAS_ABSOLUTE_PATH,
484 $lang_key,
485 MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH),
486 $this->getCustLangPath(),
487 static function (string $module, array $identifiers, array $remark_identifiers) use ($lang_key): void {
488 self::mergeIntoDatabase($lang_key, $module, $identifiers, $remark_identifiers);
489 }
490 );
491
492 $logger = $DIC->logger()->forComponent('lang');
493 $root = rtrim(ILIAS_ABSOLUTE_PATH, '/') . '/';
494 foreach ($merged['written'] as $file) {
495 $result['written'][] = str_starts_with($file, $root) ? substr($file, strlen($root)) : $file;
496 }
497 foreach ($merged['skipped'] as $module => $reason) {
498 $result['skipped'][] = (string) $module;
499 $logger->warning(PlainLogText::of(sprintf(
500 'The local changes of module "%s", language "%s" were not merged into its shipped PO file: %s',
501 $module,
502 $lang_key,
503 $reason
504 )));
505 }
506 foreach ($merged['invalid_markup'] as $module => $invalid) {
507 foreach ($invalid as $identifier => $violations) {
508 $result['invalid_markup'][$module . $this->separator . $identifier] = $violations;
509 }
510 }
511 foreach ($merged['not_merged'] as $module => $identifiers) {
512 foreach ($identifiers as $identifier) {
513 $result['not_merged'][] = $module . $this->separator . $identifier;
514 }
515 }
516 if ($result['not_merged'] !== []) {
517 $logger->warning(PlainLogText::of(sprintf(
518 'Language entries not merged into their shipped PO file (a plural message with an empty first form next to other forms, a plural message for a singular shipped one, or a new identifier in the form of a plural form): %s',
519 implode(', ', $result['not_merged'])
520 )));
521 }
522 foreach ($merged['unwritten_database'] as $module => $reason) {
523 $result['unwritten_database'][] = (string) $module;
524 $logger->error(PlainLogText::of(sprintf(
525 'The shipped PO file of module "%s", language "%s" was merged, but its lng_data rows could not be updated (local_change/remarks stay set): %s',
526 $module,
527 $lang_key,
528 $reason
529 )));
530 }
531 foreach ($merged['unmarked_overlay'] as $module => $reason) {
532 $logger->error(PlainLogText::of(sprintf(
533 'The shipped PO file of module "%s", language "%s" was merged, but its overlay entries could not be marked as taken over (until "php cli/setup.php build", saving the module again may fall back to the former shipped values - merging again marks them): %s',
534 $module,
535 $lang_key,
536 $reason
537 )));
538 }
539 if ($result['written'] !== []) {
540 $logger->info(PlainLogText::of(sprintf(
541 'Merged the local changes of language "%s" into (now owned by the web server user; served from the overlay until "php cli/setup.php build" and "php cli/setup.php update" ran): %s',
542 $lang_key,
543 implode(', ', $result['written'])
544 )));
545 }
546
547 return $result;
548 }
static mergeIntoDatabase(string $a_lang_key, string $module, array $identifiers, array $remark_identifiers)
Database part of the merge into the shipped .po: the lng_data rows of $identifiers lose local_change ...
getCustLangPath()
Get the customized language files path.

References $DIC, ilObjLanguage\$key, ILIAS\TestQuestionPool\ExportImport\Foundation\Export\$logger, $module, getCustLangPath(), and mergeIntoDatabase().

Referenced by mergeLocalChangesIntoGlobalLanguageFile().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ moduleEntriesOf()

ilObjLanguageExt::moduleEntriesOf ( array  $values)
private
Parameters
array<string,string>$values module.separator.identifier => value
Returns
array<string, array{module: string, identifier: string}>

Definition at line 818 of file class.ilObjLanguageExt.php.

818 : array
819 {
820 $entries = [];
821 foreach (array_keys($values) as $key) {
822 $parts = explode($this->separator, (string) $key);
823 if (count($parts) === 2) {
824 $entries[$key] = ['module' => $parts[0], 'identifier' => $parts[1]];
825 }
826 }
827
828 return $entries;
829 }

◆ normalizedRemarks()

static ilObjLanguageExt::normalizedRemarks ( array  $a_remarks)
staticprivate

Remarks as stored, identically for lng_data and the overlay: cut to 250 characters (not bytes); one that is not valid UTF-8 is dropped (logged), it would make the overlay unreadable.

Parameters
array<string,mixed>$a_remarks
Returns
array<string, mixed>

Definition at line 1538 of file class.ilObjLanguageExt.php.

1538 : array
1539 {
1540 global $DIC;
1541
1542 foreach ($a_remarks as $key => $remark) {
1543 if (!is_string($remark)) {
1544 continue;
1545 }
1546 if (!mb_check_encoding($remark, 'UTF-8')) {
1547 $DIC->logger()->forComponent('lang')->warning(PlainLogText::of(sprintf(
1548 'The remark of "%s" is not valid UTF-8 and was not saved.',
1549 $key
1550 )));
1551 unset($a_remarks[$key]);
1552 continue;
1553 }
1554 $a_remarks[$key] = mb_substr($remark, 0, 250);
1555 }
1556
1557 return $a_remarks;
1558 }

References $DIC.

◆ readShippedMigratedModules()

static ilObjLanguageExt::readShippedMigratedModules ( string  $a_lang_key,
array  $only_modules = [] 
)
staticprivate

An unreadable shipped .po is logged and listed in "unreadable_modules" (its module stays in "modules"); callers decide whether that is fatal (importLanguageFile()) or a warning.

Everything empty without a LanguageFileDirectoryManager.

Returns
array{values: array<string, string>, comments: array<string, string>, modules: list<string>, unreadable_modules: list<string>, fuzzy: list<string>} values/comments/fuzzy keyed module.separator.identifier ("fuzzy": not translated yet)
Parameters
list<string>$only_modules only these modules (all if empty)

Definition at line 1124 of file class.ilObjLanguageExt.php.

1124 : array
1125 {
1126 global $DIC;
1127
1128 $result = ['values' => [], 'comments' => [], 'modules' => [], 'unreadable_modules' => [], 'fuzzy' => []];
1129 if (!$DIC->offsetExists(LanguageFileDirectoryManager::class)) {
1130 return $result;
1131 }
1132
1133 $separator = $DIC->language()->separator;
1134 $shipped_files = MigratedLanguageFileSync::findShippedModuleFiles(
1135 $DIC[LanguageFileDirectoryManager::class],
1136 ILIAS_ABSOLUTE_PATH,
1137 $a_lang_key
1138 );
1139 foreach ($shipped_files as $module => $shipped_po) {
1140 $module = (string) $module;
1141 if ($only_modules !== [] && !in_array($module, $only_modules, true)) {
1142 continue;
1143 }
1144 $result['modules'][] = $module;
1145 try {
1146 $entries = MigratedLanguageFileSync::loadShippedModuleEntries($shipped_po, $module);
1147 foreach (array_keys(MigratedLanguageFileSync::loadShippedFuzzyIdentifiers($shipped_po, $module)) as $identifier) {
1148 $result['fuzzy'][] = $module . $separator . $identifier;
1149 }
1150 } catch (\Throwable $t) {
1151 $DIC->logger()->forComponent('lang')->warning(sprintf(
1152 'Could not read the shipped PO file of module "%s", language "%s": %s',
1153 $module,
1154 $a_lang_key,
1155 $t->getMessage()
1156 ));
1157 $result['unreadable_modules'][] = $module;
1158 continue;
1159 }
1160 foreach ($entries as $identifier => $entry) {
1161 $key = $module . $separator . $identifier;
1162 $result['values'][$key] = $entry['value'];
1163 if ($entry['comment'] !== null) {
1164 $result['comments'][$key] = $entry['comment'];
1165 }
1166 }
1167 }
1168
1169 return $result;
1170 }
string $separator
separator of module, comment separator, identifier & values in language files

References $DIC, and $module.

Referenced by _getShippedMigratedComments(), and shippedMigratedModules().

+ Here is the caller graph for this function:

◆ requestedLocalRemark()

static ilObjLanguageExt::requestedLocalRemark ( string  $requested,
string  $stored,
string  $note 
)
staticprivate

The shipped note itself is no local remark (''), an empty remark removes the local one; a shipped note cannot be hidden locally.

Definition at line 174 of file class.ilObjLanguageExt.php.

174 : string
175 {
176 if ($requested === $stored) {
177 return $stored;
178 }
179
180 // remarks are saved cut to 250 characters (see normalizedRemarks()), a longer note too
181 return $note !== '' && ($requested === $note || $requested === mb_substr($note, 0, 250)) ? '' : $requested;
182 }

◆ saveValues()

static ilObjLanguageExt::saveValues ( string  $a_lang_key,
array  $a_values,
array  $a_remarks,
bool  $merge_onto_current_content 
)
staticprivate

With $merge_onto_current_content false the saved entries are each module's complete new content ("delete"-mode import).

Returns
array{unwritten: list<string>, remarks: array<string, array<string, string>>} unwritten: see _saveValues(); remarks: the non-empty remarks written into the overlays

Definition at line 1261 of file class.ilObjLanguageExt.php.

1266 : array {
1267 global $DIC;
1268 $lng = $DIC->language();
1269
1270 $save_array = [];
1271 $save_date = (new DateTimeImmutable('now', new DateTimeZone('UTC')))
1272 ->format('Y-m-d H:i:s');
1273 $a_remarks = self::normalizedRemarks($a_remarks);
1274
1275 // shipped values for the comparison; an unreadable .po keeps its .lang lines (see getShippedValues())
1276 $shipped_migrated = self::readShippedMigratedModules($a_lang_key);
1277 $a_values = self::withPluralFormKeys($a_values, $shipped_migrated, $lng->separator);
1278 $a_remarks = self::withPluralFormKeys($a_remarks, $shipped_migrated, $lng->separator);
1279 $skipped_modules = [];
1280 if ($merge_onto_current_content) {
1281 $a_values = self::withoutUnreadableModules($a_lang_key, $a_values, $lng->separator, $skipped_modules);
1282 $a_remarks = self::withoutUnreadableModules($a_lang_key, $a_remarks, $lng->separator, $skipped_modules);
1283 }
1284 [$file_values, $file_comments] = self::shippedValuesAndComments(
1286 $shipped_migrated
1287 );
1288 // a "delete"-mode import wiped lng_data: every entry is written anew, else an entry equal to the still
1289 // existing files/overlay of a PO module would not be written and miss in lng_data
1290 $db_values = $merge_onto_current_content ? self::_getValues($a_lang_key) : [];
1291 $db_comments = $merge_onto_current_content ? self::_getRemarks($a_lang_key) : [];
1292 $global_values = array_merge($db_values, $file_values);
1293 $global_comments = array_merge($db_comments, $file_comments);
1294
1295 // the forms of a plural message have no lng_data row of their own: the message's row is written once, see below
1296 $plural_rows = [];
1297 $plural_changed = [];
1298 $plural_remarks = [];
1299 // module => identifier => remark ('' removes it) to be written into the overlay
1300 $remark_changes = [];
1301 $shipped_by_module = [];
1302
1303 // save the single translations in lng_data
1304 foreach ($a_values as $key => $value) {
1305 $keys = explode($lng->separator, $key);
1306
1307 if (count($keys) !== 2) {
1308 continue;
1309 }
1310
1311 list($module, $topic) = $keys;
1312 if (in_array($module, $shipped_migrated['modules'], true)) {
1313 $shipped_by_module[$module] ??= self::shippedModuleValues($shipped_migrated, $module, $lng->separator);
1314 // written as the overlay keeps it (e.g. an empty value resets to the shipped one), so lng_data does not diverge
1315 $value = MigratedLanguageFileSync::resolveLocalValue($shipped_migrated['values'][$key] ?? null, (string) $value);
1316 $plural_identifier = MigratedLanguageFileSync::pluralMessageOf(
1317 $topic,
1318 $shipped_by_module[$module]
1319 );
1320 if ($plural_identifier !== null) {
1321 if (PluralFormKey::parse($topic) !== null && !array_key_exists($topic, $shipped_by_module[$module])) {
1322 // a form the shipped message does not have would only be an orphan
1323 continue;
1324 }
1325 $save_array[$module][$topic] = $value;
1326 if (($db_values[$key] ?? null) !== $value) {
1327 $plural_changed[$module][$plural_identifier] = true;
1328 }
1329 // remarks belong to the identifier (no lng_data row per form): the first form whose remark differs wins
1330 $stored_remark = (string) ($db_comments[$module . $lng->separator . $plural_identifier] ?? '');
1331 $requested_remark = array_key_exists($key, $a_remarks)
1332 ? self::requestedLocalRemark((string) $a_remarks[$key], $stored_remark, (string) ($file_comments[$key] ?? ''))
1333 : null;
1334 if (
1335 $requested_remark !== null
1336 && $requested_remark !== $stored_remark
1337 && !array_key_exists($plural_identifier, $plural_remarks[$module] ?? [])
1338 ) {
1339 $plural_remarks[$module][$plural_identifier] = $requested_remark;
1340 }
1341 continue;
1342 }
1343 }
1344 $save_array[$module][$topic] = $value;
1345 $is_po_module = in_array($module, $shipped_migrated['modules'], true);
1346 if ($is_po_module && array_key_exists($key, $a_remarks)) {
1347 // the remark shown may be the shipped note (see getEffectiveRemarks()); only a local remark is stored
1348 $a_remarks[$key] = self::requestedLocalRemark(
1349 (string) $a_remarks[$key],
1350 (string) ($db_comments[$key] ?? ''),
1351 (string) ($file_comments[$key] ?? '')
1352 );
1353 }
1354
1355 $is_remark_changed = $is_po_module
1356 && array_key_exists($key, $a_remarks)
1357 && (string) $a_remarks[$key] !== (string) ($db_comments[$key] ?? '');
1358 if ($is_remark_changed) {
1359 $remark_changes[$module][$topic] = (string) $a_remarks[$key];
1360 }
1361
1362 // PO module: the shipped note is not shown, comparing with it would flag every entry with a note
1363 $are_comments_set = !$is_po_module && array_key_exists($key, $global_comments) && array_key_exists($key, $a_remarks);
1364 $is_comment_changed = $are_comments_set ? $global_comments[$key] != $a_remarks[$key] : $are_comments_set;
1365 $are_changes_made = (isset($global_values[$key]) ? $global_values[$key] != $value : true) || (isset($db_values[$key]) ? $db_values[$key] != $value : true);
1366 if (!$are_changes_made && !$is_comment_changed && $is_remark_changed) {
1367 self::updateRemark($module, $topic, $a_lang_key, (string) $a_remarks[$key]);
1368 } elseif ($are_changes_made || $is_comment_changed) {
1369 if ($is_po_module) {
1370 // a local change exactly if the value differs from the shipped one (like writePluralRows())
1371 $local_change = !isset($file_values[$key]) || (string) $file_values[$key] !== (string) $value
1372 ? $save_date
1373 : null;
1374 } else {
1375 $local_change = (isset($db_values[$key]) ? $db_values[$key] == $value : true) || (isset($global_values[$key]) ? $global_values[$key] != $value : true) ? $save_date : null;
1376 }
1378 $module,
1379 $topic,
1380 $a_lang_key,
1381 // the value as the build serves it, see MigratedLanguageFileSync::databaseValues()
1382 $is_po_module
1383 ? MigratedLanguageFileSync::databaseValues([$key => $value], $shipped_migrated['values'])[$key]
1384 : $value,
1385 $local_change,
1386 // PO module: without a requested remark the stored one stays, as in its overlay
1387 $a_remarks[$key] ?? ($is_po_module ? ($db_comments[$key] ?? null) : null)
1388 );
1389 }
1390 }
1391
1392 // the row of a plural message is written if a form's value or the remark changed
1393 foreach (array_keys($plural_changed + $plural_remarks) as $module) {
1394 $identifiers = array_keys(($plural_changed[$module] ?? []) + ($plural_remarks[$module] ?? []));
1395 foreach ($identifiers as $plural_identifier) {
1396 $remark = array_key_exists($plural_identifier, $plural_remarks[$module] ?? [])
1397 ? $plural_remarks[$module][$plural_identifier]
1398 : ($db_comments[$module . $lng->separator . $plural_identifier] ?? null);
1399 $plural_rows[$module][$plural_identifier] = $remark === '' ? null : $remark;
1400 if (array_key_exists($plural_identifier, $plural_remarks[$module] ?? [])) {
1401 $remark_changes[$module][$plural_identifier] = $plural_remarks[$module][$plural_identifier];
1402 }
1403 }
1404 }
1405
1406 $remarks = array_filter(array_map(
1407 static fn(array $changes): array => array_filter($changes, static fn(string $remark): bool => $remark !== ''),
1408 $remark_changes
1409 ));
1410
1411 // save the serialized module entries in lng_modules
1412 $modules_with_unwritten_overlay = $skipped_modules;
1413 foreach ($save_array as $module => $entries) {
1414 $module = (string) $module;
1415 $module_plural_rows = $plural_rows[$module] ?? [];
1416 $shipped_module_values = $shipped_by_module[$module] ?? [];
1417 $module_remark_changes = $remark_changes[$module] ?? [];
1418 // Read and written under the overlay lock, so a concurrent write in between is not lost
1420 $a_lang_key,
1421 $module,
1422 static function () use ($a_lang_key, $module, $entries, $merge_onto_current_content, $module_plural_rows, $shipped_module_values, $save_date, $module_remark_changes): bool {
1423 // without a current content the entries are written as they are; replaceLangModule() creates the row
1424 $current = $merge_onto_current_content ? self::currentModuleContent($a_lang_key, $module) : [];
1425 if ($current === null) {
1426 return false;
1427 }
1428 $content = array_merge($current, $entries);
1429 $written = ilObjLanguage::replaceLangModule($a_lang_key, $module, $content);
1430 self::writePluralRows($a_lang_key, $module, $content, $shipped_module_values, $module_plural_rows, $save_date);
1431 return self::setOverlayRemarks($a_lang_key, $module, $module_remark_changes) && $written;
1432 }
1433 );
1434 if (!$written) {
1436 }
1437 }
1438
1439 ilCachedLanguage::getInstance($a_lang_key)->flush();
1440
1441 return ['unwritten' => $modules_with_unwritten_overlay, 'remarks' => $remarks];
1442 }
static withPluralFormKeys(array $entries, array $shipped_migrated, string $separator)
Replaces the plain identifier of a plural message of a module maintained in PO files by the key of it...
static updateRemark(string $module, string $identifier, string $a_lang_key, string $remark)
Sets only the remark of an existing lng_data row ('' removes it), like replaceLangEntry() cuts it to ...
static requestedLocalRemark(string $requested, string $stored, string $note)
The shipped note itself is no local remark (''), an empty remark removes the local one; a shipped not...
static normalizedRemarks(array $a_remarks)
Remarks as stored, identically for lng_data and the overlay: cut to 250 characters (not bytes); one t...
static replaceLangEntry(string $a_module, string $a_identifier, string $a_lang_key, string $a_value, ?string $a_local_change=null, ?string $a_remarks=null)
Replace lang entry.

◆ setLocal()

ilObjLanguageExt::setLocal ( bool  $a_local = true)

Set the local status of the language.

$a_local local status (true/false)

Definition at line 76 of file class.ilObjLanguageExt.php.

76 : void
77 {
78 if ($this->isInstalled()) {
79 if ($a_local) {
80 $this->setDescription("installed_local");
81 } else {
82 $this->setDescription("installed");
83 }
84 $this->update();
85 }
86 }
isInstalled()
Check language object status, and return true if language is installed.
setDescription(string $description)

References ilObjLanguage\isInstalled(), ilObject\setDescription(), and ilObject\update().

+ Here is the call graph for this function:

◆ setOverlayRemarks()

static ilObjLanguageExt::setOverlayRemarks ( string  $a_lang_key,
string  $module,
array  $changes 
)
staticprivate

Writes $changes (identifier => remark, '' removes it) into the overlay; false if that failed (logged), lng_data holds them regardless.

Parameters
array<string,string>$changes

Definition at line 1502 of file class.ilObjLanguageExt.php.

1502 : bool
1503 {
1504 global $DIC;
1505
1506 if ($changes === [] || !$DIC->offsetExists(LanguageFileDirectoryManager::class)) {
1507 return true;
1508 }
1509 try {
1510 MigratedLanguageFileSync::setRemarks(
1511 $DIC[LanguageFileDirectoryManager::class],
1512 $a_lang_key,
1513 $module,
1514 $changes,
1515 MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH),
1516 ILIAS_ABSOLUTE_PATH
1517 );
1518 } catch (\Throwable $t) {
1519 $DIC->logger()->forComponent('lang')->warning(sprintf(
1520 'Could not write the remarks of migrated module "%s", language "%s": %s',
1521 $module,
1522 $a_lang_key,
1523 $t->getMessage()
1524 ));
1525 return false;
1526 }
1527
1528 return true;
1529 }

References $DIC, and $module.

◆ shippedMigratedModules()

ilObjLanguageExt::shippedMigratedModules ( )
private
Returns
array{values: array<string, string>, comments: array<string, string>, modules: list<string>, unreadable_modules: list<string>, fuzzy: list<string>}

Definition at line 681 of file class.ilObjLanguageExt.php.

681 : array
682 {
683 return $this->shipped_migrated_modules ??= self::readShippedMigratedModules($this->key);
684 }

References readShippedMigratedModules().

Referenced by getEffectiveRemarks(), getModulesMaintainedInPoFiles(), getShippedComments(), getShippedCommentsForDisplay(), getShippedValues(), and getUnreadableShippedPoModules().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ shippedModuleValues()

static ilObjLanguageExt::shippedModuleValues ( array  $shipped_migrated,
string  $module,
string  $separator 
)
staticprivate

identifier => value out of the values of readShippedMigratedModules().

Parameters
array{valuesarray<string, string>} $shipped_migrated
Returns
array<string, string>

Definition at line 1484 of file class.ilObjLanguageExt.php.

1484 : array
1485 {
1486 $prefix = $module . $separator;
1487 $values = [];
1488 foreach ($shipped_migrated['values'] as $key => $value) {
1489 if (str_starts_with((string) $key, $prefix)) {
1490 $values[substr((string) $key, strlen($prefix))] = $value;
1491 }
1492 }
1493 return $values;
1494 }

References $module.

◆ shippedValuesAndComments()

static ilObjLanguageExt::shippedValuesAndComments ( ilLanguageFile  $global_file,
array  $shipped 
)
staticprivate

$global_file with every readable module maintained in PO files replaced by its shipped .po, see getShippedValues().

Parameters
array{valuesarray<string, string>, comments: array<string, string>, modules: list<string>, unreadable_modules: list<string>} $shipped
Returns
array{0: array<string, string>, 1: array<string, string>} values, comments

Definition at line 1178 of file class.ilObjLanguageExt.php.

1178 : array
1179 {
1180 global $DIC;
1181
1182 $separator = $DIC->language()->separator;
1183 $replaced_modules = array_values(array_diff($shipped['modules'], $shipped['unreadable_modules']));
1184
1185 return [
1186 array_merge(self::withoutModules($global_file->getAllValues(), $replaced_modules, $separator), $shipped['values']),
1187 array_merge(self::withoutModules($global_file->getAllComments(), $replaced_modules, $separator), $shipped['comments']),
1188 ];
1189 }
getAllComments()
Get array of all comments Return array [module.separator.identifier => comment].

References $DIC, ilLanguageFile\getAllComments(), and ilLanguageFile\getAllValues().

Referenced by findInvalidMarkupOfChangedValues(), getShippedComments(), and getShippedValues().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ syncMigratedFilesAfterDeleteModeImport()

ilObjLanguageExt::syncMigratedFilesAfterDeleteModeImport ( array  $modules_before_delete,
array  $to_save,
array  $remarks 
)
private

A module that existed before the "delete" wipe but is absent from the imported file is never visited by _saveValues(); its orphaned overlay would keep serving stale values.

Syncs every such module with "replace" semantics. For modules present in $to_save this repeats the sync of replaceLangModule(), which is idempotent.

Parameters
list<string>$modules_before_delete every module this language had any lng_data row for, captured before the DELETE
array<string,string>$to_save module.separator.topic => value, the complete final DB content now
array<string,array<string,string>>$remarks module => identifier => remark, the complete remarks now
Returns
list<string> the modules whose overlay could not be written

Definition at line 841 of file class.ilObjLanguageExt.php.

845 : array {
846 global $DIC;
847
848 if (!$DIC->offsetExists(LanguageFileDirectoryManager::class)) {
849 return [];
850 }
851
852 $entries_by_module = [];
853 foreach ($to_save as $key => $value) {
854 $parts = explode($this->separator, $key);
855 if (count($parts) === 2) {
856 $entries_by_module[$parts[0]][$parts[1]] = $value;
857 }
858 }
859
860 $manager = $DIC[LanguageFileDirectoryManager::class];
861 $client_data_dir = MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH);
862 $failed_modules = [];
863 foreach (array_unique(array_merge($modules_before_delete, array_keys($entries_by_module))) as $module) {
864 try {
865 MigratedLanguageFileSync::sync(
866 $manager,
867 ILIAS_ABSOLUTE_PATH,
868 $this->key,
869 (string) $module,
870 $entries_by_module[$module] ?? [],
871 $client_data_dir,
872 false,
873 null,
874 $remarks[$module] ?? []
875 );
876 } catch (\Throwable $t) {
877 $DIC->logger()->forComponent('lang')->warning(sprintf(
878 'Could not sync migrated language file for module "%s", language "%s" after a' .
879 ' "delete"-mode import: %s',
880 $module,
881 $this->key,
882 $t->getMessage()
883 ));
884 $failed_modules[] = (string) $module;
885 }
886 }
887
888 return $failed_modules;
889 }

◆ updateRemark()

static ilObjLanguageExt::updateRemark ( string  $module,
string  $identifier,
string  $a_lang_key,
string  $remark 
)
staticprivate

Sets only the remark of an existing lng_data row ('' removes it), like replaceLangEntry() cuts it to 250 characters.

Definition at line 1579 of file class.ilObjLanguageExt.php.

1579 : void
1580 {
1581 global $DIC;
1582 $ilDB = $DIC->database();
1583
1584 $ilDB->manipulate(sprintf(
1585 "UPDATE lng_data SET remarks = %s WHERE module = %s AND identifier = %s AND lang_key = %s",
1586 $ilDB->quote($remark === '' ? null : mb_substr($remark, 0, 250), "text"),
1587 $ilDB->quote($module, "text"),
1588 $ilDB->quote($identifier, "text"),
1589 $ilDB->quote($a_lang_key, "text")
1590 ));
1591 }

References $DIC, $ilDB, and $module.

◆ withFuzzyMarkers()

static ilObjLanguageExt::withFuzzyMarkers ( array  $comments,
array  $shipped 
)
staticprivate

Appends SHIPPED_FUZZY_MARKER_TOPIC to the shipped note of every fuzzy entry.

Parameters
array<string,string>$comments
array{fuzzylist<string>} $shipped see readShippedMigratedModules()
Returns
array<string, string>

Definition at line 354 of file class.ilObjLanguageExt.php.

354 : array
355 {
356 if ($shipped['fuzzy'] === []) {
357 return $comments;
358 }
359 global $DIC;
360 $lng = $DIC->language();
361 $lng->loadLanguageModule('lng');
362 $marker = $lng->txt(self::SHIPPED_FUZZY_MARKER_TOPIC);
363 if ($marker === '-' . self::SHIPPED_FUZZY_MARKER_TOPIC . '-' && $lng instanceof ilLanguage) {
364 // only shipped in de/en: the default language fills the gap, as before
365 $marker = ilLanguage::_lookupEntry($lng->getDefaultLanguage(), 'lng', self::SHIPPED_FUZZY_MARKER_TOPIC);
366 }
367 foreach ($shipped['fuzzy'] as $key) {
368 $comments[$key] = isset($comments[$key]) && $comments[$key] !== ''
369 ? $comments[$key] . ' - ' . $marker
370 : $marker;
371 }
372
373 return $comments;
374 }
language handling
loadLanguageModule(string $a_module)
Load language module.
txt(string|LanguageIdentifier $a_topic, ?int $n=null)
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
getDefaultLanguage()
Return default language.
static _lookupEntry(string $a_lang_key, string $a_mod, string $a_id)
$comments

References $comments, $DIC, ilObjLanguage\$key, ilObject\$lng, ilLanguage\_lookupEntry(), ilLanguage\getDefaultLanguage(), ilLanguage\loadLanguageModule(), and ilLanguage\txt().

Referenced by _getShippedMigratedComments(), and getShippedCommentsForDisplay().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ withModuleLock()

static ilObjLanguageExt::withModuleLock ( string  $a_lang_key,
string  $module,
\Closure  $callback 
)
staticprivate

See MigratedLanguageFileSync::withOverlayLock().

@template T

Parameters

Closure():T $callback

Returns
T

Definition at line 1728 of file class.ilObjLanguageExt.php.

1728 : mixed
1729 {
1730 global $DIC;
1731
1732 return MigratedLanguageFileSync::withOverlayLock(
1733 $DIC->offsetExists(LanguageFileDirectoryManager::class) ? $DIC[LanguageFileDirectoryManager::class] : null,
1734 $a_lang_key,
1735 $module,
1736 MigratedLanguageFilePaths::resolveClientDataDir(ILIAS_ABSOLUTE_PATH),
1737 $callback,
1738 ILIAS_ABSOLUTE_PATH
1739 );
1740 }

References $DIC, and $module.

◆ withoutModules()

static ilObjLanguageExt::withoutModules ( array  $values,
array  $modules,
string  $separator 
)
staticprivate
Parameters
array<string,string|null>$values module.separator.identifier => value
list<string>$modules
Returns
array<string, string|null> $values without the entries of $modules

Definition at line 1196 of file class.ilObjLanguageExt.php.

1196 : array
1197 {
1198 if ($modules === []) {
1199 return $values;
1200 }
1201 $excluded = array_flip($modules);
1202
1203 return array_filter(
1204 $values,
1205 static fn(int|string $key): bool => !isset($excluded[explode($separator, (string) $key, 2)[0]]),
1206 ARRAY_FILTER_USE_KEY
1207 );
1208 }

Referenced by getShippedChangesSinceBackup().

+ Here is the caller graph for this function:

◆ withoutUnreadableModules()

static ilObjLanguageExt::withoutUnreadableModules ( string  $a_lang_key,
array  $entries,
string  $separator,
array &  $skipped_modules 
)
staticprivate

Drops the entries of modules whose content cannot be read (see currentModuleContent()), before anything is written.

Parameters
array<string,mixed>$entries module.separator.identifier => value or remark
list<string>$skipped_modules gets the dropped modules
Returns
array<string, mixed>

Definition at line 1698 of file class.ilObjLanguageExt.php.

1698 : array
1699 {
1700 $modules = [];
1701 foreach (array_keys($entries) as $key) {
1702 $keys = explode($separator, (string) $key);
1703 if (count($keys) === 2) {
1704 $modules[$keys[0]] = true;
1705 }
1706 }
1707 foreach (array_keys($modules) as $module) {
1708 $module = (string) $module;
1709 if (!in_array($module, $skipped_modules, true) && self::currentModuleContent($a_lang_key, $module) === null) {
1710 $skipped_modules[] = $module;
1711 }
1712 }
1713
1714 return array_filter(
1715 $entries,
1716 static fn(string|int $key): bool => !in_array(explode($separator, (string) $key)[0], $skipped_modules, true),
1717 ARRAY_FILTER_USE_KEY
1718 );
1719 }

References $module.

◆ withPluralFormKeys()

static ilObjLanguageExt::withPluralFormKeys ( array  $entries,
array  $shipped_migrated,
string  $separator 
)
staticprivate

Replaces the plain identifier of a plural message of a module maintained in PO files by the key of its default form (see MigratedLanguageFileSync::defaultFormKeyOf()), the form its lng_data row stands for.

Where $entries has both, the later one wins. Applied to every input before anything is compared, kept or checked.

Parameters
array<string,mixed>$entries module.separator.identifier => value or remark
array{valuesarray<string, string>, modules: list<string>} $shipped_migrated see readShippedMigratedModules()
Returns
array<string, mixed>

Definition at line 1454 of file class.ilObjLanguageExt.php.

1454 : array
1455 {
1456 if ($shipped_migrated['modules'] === []) {
1457 return $entries;
1458 }
1459 $shipped_by_module = [];
1460 $result = [];
1461 foreach ($entries as $key => $value) {
1462 $keys = explode($separator, (string) $key);
1463 if (count($keys) === 2 && in_array($keys[0], $shipped_migrated['modules'], true)) {
1464 $form_key = MigratedLanguageFileSync::defaultFormKeyOf(
1465 $keys[1],
1466 $shipped_by_module[$keys[0]] ??= self::shippedModuleValues($shipped_migrated, $keys[0], $separator)
1467 );
1468 if ($form_key !== null) {
1469 $key = $keys[0] . $separator . $form_key;
1470 }
1471 }
1472 $result[$key] = $value;
1473 }
1474
1475 return $result;
1476 }

◆ writeLocalChangesIntoGlobalLanguageFile()

ilObjLanguageExt::writeLocalChangesIntoGlobalLanguageFile ( )
private

Definition at line 448 of file class.ilObjLanguageExt.php.

448 : void
449 {
450 $po_modules = $this->getModulesMaintainedInPoFiles();
451 $global_file_obj = $this->getGlobalLanguageFile();
452 $global_values = $global_file_obj->getAllValues();
453
454 $global_file_obj->setAllValues(array_merge(
455 $global_values,
456 self::withoutModules(self::_getValues($this->key), $po_modules, $this->separator)
457 ));
458 $global_file_obj->setAllComments(array_merge(
459 $global_file_obj->getAllComments(),
460 self::withoutModules(self::_getRemarks($this->key, true), $po_modules, $this->separator)
461 ));
462 $global_file_obj->keepOriginalLines(array_keys(array_diff_key(
463 $global_values,
464 self::withoutModules($global_values, $po_modules, $this->separator)
465 )));
466 $global_file_obj->write();
467 }
getModulesMaintainedInPoFiles()
Every module maintained in PO files for this language (its shipped .po exists).

References getGlobalLanguageFile(), and getModulesMaintainedInPoFiles().

Referenced by mergeLocalChangesIntoGlobalLanguageFile().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ writePluralRows()

static ilObjLanguageExt::writePluralRows ( string  $a_lang_key,
string  $module,
array  $content,
array  $shipped_values,
array  $plural_rows,
string  $save_date 
)
staticprivate

The database holds a plural message only under its identifier, with the value of its default form, marked as local change only if that differs from the shipped default form (a local change of another form lives in the overlay only): after a rollback a later update of the legacy .lang files is not held back by it.

Parameters
array<string,string>$content
array<string,string>$shipped_values identifier => shipped value of the module
array<string,?string>$plural_rows

Definition at line 1602 of file class.ilObjLanguageExt.php.

1609 : void {
1610 if ($plural_rows === []) {
1611 return;
1612 }
1613 $content = MigratedLanguageFileSync::mapLegacyPluralValues($content, $shipped_values);
1614 $values = MigratedLanguageFileSync::collapsePluralForms($content, $shipped_values);
1615 $shipped_defaults = MigratedLanguageFileSync::collapsePluralForms($shipped_values, $shipped_values);
1616 $database_values = MigratedLanguageFileSync::databaseValues($values, $shipped_defaults);
1617 foreach ($plural_rows as $identifier => $remarks) {
1618 if (!isset($database_values[$identifier])) {
1619 ilObjLanguage::deleteLangEntry($module, (string) $identifier, $a_lang_key);
1620 continue;
1621 }
1623 $module,
1624 (string) $identifier,
1625 $a_lang_key,
1626 (string) $database_values[$identifier],
1627 (string) $values[$identifier] !== (string) ($shipped_defaults[$identifier] ?? '') ? $save_date : null,
1628 $remarks
1629 );
1630 }
1631 }

Field Documentation

◆ $shipped_migrated_modules

array ilObjLanguageExt::$shipped_migrated_modules = null
private

Definition at line 49 of file class.ilObjLanguageExt.php.

◆ $skipped_duplicate_values

array ilObjLanguageExt::$skipped_duplicate_values = []
private

Definition at line 59 of file class.ilObjLanguageExt.php.

Referenced by getSkippedDuplicateValues().

◆ $skipped_invalid_markup_values

array ilObjLanguageExt::$skipped_invalid_markup_values = []
private

Definition at line 54 of file class.ilObjLanguageExt.php.

Referenced by getSkippedInvalidMarkupValues().

◆ SHIPPED_FUZZY_MARKER_TOPIC

const string ilObjLanguageExt::SHIPPED_FUZZY_MARKER_TOPIC = 'lng_not_translated'
private

Language variable of the admin GUI marker for an entry that is fuzzy (not translated yet) in its shipped .po.

Definition at line 44 of file class.ilObjLanguageExt.php.


The documentation for this class was generated from the following file: