ILIAS  trunk Revision v13.0_alpha-62-g3b72d83f2e5
ilPluginLanguage Class Reference
+ Collaboration diagram for ilPluginLanguage:

Public Member Functions

 __construct (ilPluginInfo $plugin_info)
 
 getAvailableLangFiles ()
 Get array of all language files in the plugin. More...
 
 hasAvailableLangFiles ()
 
 getPrefix ()
 
 updateLanguages (?array $a_lang_keys=null)
 
 uninstall ()
 
 loadLanguageModule ()
 Load language module for plugin. More...
 
 txt (string $a_var)
 Get Language Variable (prefix will be prepended automatically) More...
 

Protected Member Functions

 getLanguageDirectory ()
 

Protected Attributes

ilPluginInfo $plugin_info
 

Private Member Functions

 readLangFile (string $file)
 Key (without the plugin prefix) => value. More...
 
 logShippedViolations (string $file, array $values)
 Logs every value with disallowed markup, changes nothing. More...
 
 cleanShippedValues (string $file, array $values)
 Removes disallowed markup and logs what was removed. More...
 
 readPoFile (string $file)
 Key (msgid, without the plugin prefix) => value, null if the file cannot be read (logged, the update goes on with the other languages). More...
 

Static Private Member Functions

static logWarning (string $message)
 Falls back to the PHP error log (e.g. More...
 

Detailed Description

Constructor & Destructor Documentation

◆ __construct()

ilPluginLanguage::__construct ( ilPluginInfo  $plugin_info)

Definition at line 36 of file class.ilPluginLanguage.php.

37 {
38 $this->plugin_info = $plugin_info;
39 }

References $plugin_info.

Member Function Documentation

◆ cleanShippedValues()

ilPluginLanguage::cleanShippedValues ( string  $file,
array  $values 
)
private

Removes disallowed markup and logs what was removed.

Parameters
array<string,string>$values key => value
Returns
array<string, string>

Definition at line 202 of file class.ilPluginLanguage.php.

202 : array
203 {
205 foreach ($policy->findInvalidValues($values) as $key => $violations) {
206 $values[$key] = $policy->sanitize($values[$key]);
207 self::logWarning(sprintf(
208 'Markup not allowed in a language value, %s (key "%s"): removed %s',
209 $file,
210 $key,
211 implode(', ', $violations)
212 ));
213 }
214
215 return $values;
216 }
The HTML a translation value may contain, decided in one place for the shipped files (cleaned in Setu...
static logWarning(string $message)
Falls back to the PHP error log (e.g.

References $policy, and logWarning().

Referenced by readPoFile().

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

◆ getAvailableLangFiles()

ilPluginLanguage::getAvailableLangFiles ( )

Get array of all language files in the plugin.

A language may be shipped as ilias_<lang>.po instead of .lang (see readPoFile()); if both exist, the .po is used.

Returns
array of [key => "en" (e.g.), file => ...]

Definition at line 53 of file class.ilPluginLanguage.php.

53 : array
54 {
55 $directory = $this->getLanguageDirectory();
56 if (!@is_dir($directory)) {
57 return [];
58 }
59
60 $lang_files = [];
61 $po_files = [];
62
63 $dir = opendir($directory);
64 while ($file = readdir($dir)) {
65 if ($file === "." || $file === "..") {
66 continue;
67 }
68
69 // directories
70 if (!@is_file($directory . "/" . $file)) {
71 continue;
72 }
73 if (strpos($file, "ilias_") === 0 && substr($file, strlen($file) - 5) === ".lang") {
74 $lang_files[substr($file, 6, 2)] = [
75 "key" => substr($file, 6, 2),
76 "file" => $file
77 ];
78 } elseif (preg_match('/\Ailias_([a-z]{2})\.po\z/', $file, $matches) === 1) {
79 $po_files[$matches[1]] = [
80 "key" => $matches[1],
81 "file" => $file
82 ];
83 }
84 }
85 closedir($dir);
86
87 return array_values(array_replace($lang_files, $po_files));
88 }

References $lang_files, and getLanguageDirectory().

Referenced by hasAvailableLangFiles(), and updateLanguages().

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

◆ getLanguageDirectory()

ilPluginLanguage::getLanguageDirectory ( )
protected

Definition at line 41 of file class.ilPluginLanguage.php.

41 : string
42 {
43 return $this->plugin_info->getPath() . "/lang";
44 }

Referenced by getAvailableLangFiles(), and updateLanguages().

+ Here is the caller graph for this function:

◆ getPrefix()

ilPluginLanguage::getPrefix ( )

Definition at line 95 of file class.ilPluginLanguage.php.

95 : string
96 {
98 $component = $plugin->getComponent();
99 $slot = $plugin->getPluginSlot();
100
101 return $component->getId() . "_" . $slot->getId() . "_" . $plugin->getId();
102 }

References XapiProxy\$plugin, and $plugin_info.

Referenced by loadLanguageModule(), txt(), uninstall(), and updateLanguages().

+ Here is the caller graph for this function:

◆ hasAvailableLangFiles()

ilPluginLanguage::hasAvailableLangFiles ( )

Definition at line 90 of file class.ilPluginLanguage.php.

90 : bool
91 {
92 return count($this->getAvailableLangFiles()) > 0;
93 }
getAvailableLangFiles()
Get array of all language files in the plugin.

References getAvailableLangFiles().

+ Here is the call graph for this function:

◆ loadLanguageModule()

ilPluginLanguage::loadLanguageModule ( )

Load language module for plugin.

Definition at line 368 of file class.ilPluginLanguage.php.

368 : void
369 {
370 global $DIC;
371 $lng = $DIC->language();
372
373 if (is_object($lng)) {
374 $lng->loadLanguageModule($this->getPrefix());
375 }
376 }
global $lng
Definition: privfeed.php:26
global $DIC
Definition: shib_login.php:26

References $DIC, $lng, and getPrefix().

Referenced by txt().

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

◆ logShippedViolations()

ilPluginLanguage::logShippedViolations ( string  $file,
array  $values 
)
private

Logs every value with disallowed markup, changes nothing.

Parameters
array<string,string>$values key => value

Definition at line 184 of file class.ilPluginLanguage.php.

184 : void
185 {
186 foreach ((new TranslationMarkupPolicy())->findInvalidValues($values) as $key => $violations) {
187 self::logWarning(sprintf(
188 'Markup not allowed in a language value, %s (key "%s"), taken over unchanged: %s',
189 $file,
190 $key,
191 implode(', ', $violations)
192 ));
193 }
194 }

References logWarning().

Referenced by readLangFile().

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

◆ logWarning()

static ilPluginLanguage::logWarning ( string  $message)
staticprivate

Falls back to the PHP error log (e.g.

in Setup): a plugin language update must not fail because it cannot log.

Definition at line 288 of file class.ilPluginLanguage.php.

288 : void
289 {
290 global $DIC;
291 $message = PlainLogText::of($message);
292 try {
293 $DIC->logger()->forComponent('lang')->warning($message);
294 } catch (\Throwable) {
295 error_log($message);
296 }
297 }

References $DIC, and $message.

Referenced by cleanShippedValues(), logShippedViolations(), and readPoFile().

+ Here is the caller graph for this function:

◆ readLangFile()

ilPluginLanguage::readLangFile ( string  $file)
private

Key (without the plugin prefix) => value.

Disallowed markup is only logged (see logShippedViolations()), unlike for a .po (see readPoFile()), whose values are cleaned.

Returns
array<string, string>

Definition at line 161 of file class.ilPluginLanguage.php.

161 : array
162 {
163 $values = [];
164 $txt = file($file);
165 if (is_array($txt)) {
166 foreach ($txt as $row) {
167 if ($row[0] !== "#" && strpos($row, "#:#") > 0) {
168 $a = explode("#:#", trim($row));
169 $values[trim($a[0])] = trim($a[1]);
170 }
171 }
172 }
173
174 $this->logShippedViolations($file, $values);
175
176 return $values;
177 }
logShippedViolations(string $file, array $values)
Logs every value with disallowed markup, changes nothing.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples

References Vendor\Package\$a, and logShippedViolations().

Referenced by updateLanguages().

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

◆ readPoFile()

ilPluginLanguage::readPoFile ( string  $file)
private

Key (msgid, without the plugin prefix) => value, null if the file cannot be read (logged, the update goes on with the other languages).

Only entries without msgctxt are read: the file belongs to the plugin's module, whose name (the prefix) must not appear in it, as it changes when the plugin becomes a component. Entries with a msgctxt, even an empty one, are ignored and logged. Disallowed markup is cleaned (and logged) like the build does for a component's shipped .po. Extracted comments are not stored. Fuzzy entries are read, untranslated ones not. A plural message is read with its default form (see PluralForms) and logged: plugins are served from the database, which holds one value per key.

Returns
array<string, string>|null

Definition at line 231 of file class.ilPluginLanguage.php.

231 : ?array
232 {
233 try {
234 $catalog = TranslationCatalog::fromPoFile($file);
235 } catch (\RuntimeException $e) {
236 self::logWarning(sprintf(
237 'The plugin language file "%s" cannot be read - this language of the plugin is not updated: %s',
238 $file,
239 $e->getMessage()
240 ));
241 return null;
242 }
243
244 $values = [];
245 $ignored = [];
246 $plurals = [];
247 $plural_forms = null;
248 foreach ($catalog->getEntries() as $entry) {
249 if ($entry->getContext() !== null) {
250 $ignored[] = $entry->getId();
251 continue;
252 }
253 $value = $entry->getTranslation();
254 if ($entry->isPlural()) {
255 $plural_forms ??= PluralForms::fromHeaderOrGermanic(
256 $catalog->getHeader('Plural-Forms'),
257 static fn(string $message) => self::logWarning(sprintf('Plugin language file "%s": %s', $file, $message))
258 );
259 $value = $plural_forms->defaultValueOf($entry->getPluralTranslations());
260 $plurals[] = $entry->getId();
261 }
262 if ($value !== '') {
263 $values[$entry->getId()] = $value;
264 }
265 }
266 if ($plurals !== []) {
267 self::logWarning(sprintf(
268 'Plural messages in the plugin language file "%s" are stored with their default form only (plugins are served from the database): %s',
269 $file,
270 implode(', ', $plurals)
271 ));
272 }
273 $values = $this->cleanShippedValues($file, $values);
274 if ($ignored !== []) {
275 self::logWarning(sprintf(
276 'Entries with a msgctxt in the plugin language file "%s" are ignored (a plugin .po has none): %s',
277 $file,
278 implode(', ', $ignored)
279 ));
280 }
281
282 return $values;
283 }
cleanShippedValues(string $file, array $values)
Removes disallowed markup and logs what was removed.

References Vendor\Package\$e, $message, cleanShippedValues(), and logWarning().

Referenced by updateLanguages().

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

◆ txt()

ilPluginLanguage::txt ( string  $a_var)

Get Language Variable (prefix will be prepended automatically)

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

381 : string
382 {
383 global $DIC;
384 $lng = $DIC->language();
385 $this->loadLanguageModule();
386
387 $key = $this->getPrefix() . "_" . $a_var;
388 $text = $lng->txt($key);
389 if ($text !== "-" . $key . "-" || !$lng instanceof ilLanguage) {
390 return $text;
391 }
392
393 // plugin language files are often incomplete: the default language fills the gap, as before
394 return ilLanguage::_lookupEntry($lng->getDefaultLanguage(), $this->getPrefix(), $key);
395 }
language handling
static _lookupEntry(string $a_lang_key, string $a_mod, string $a_id)
loadLanguageModule()
Load language module for plugin.
$text
Definition: xapiexit.php:21

References $DIC, $lng, $text, ilLanguage\_lookupEntry(), getPrefix(), and loadLanguageModule().

+ Here is the call graph for this function:

◆ uninstall()

ilPluginLanguage::uninstall ( )

Definition at line 299 of file class.ilPluginLanguage.php.

299 : void
300 {
301 global $DIC;
302 $ilDB = $DIC->database();
303
304 // remove all language entries (see ilObjLanguage)
305 // see updateLanguages
306 $prefix = $this->getPrefix();
307 if ($prefix) {
308 $ilDB->manipulate(
309 "DELETE FROM lng_data" .
310 " WHERE module = " . $ilDB->quote($prefix, "text")
311 );
312 $ilDB->manipulate(
313 "DELETE FROM lng_modules" .
314 " WHERE module = " . $ilDB->quote($prefix, "text")
315 );
316
317 $this->removeMigratedMoFiles($prefix);
318 }
319 }

References $DIC, $ilDB, and getPrefix().

+ Here is the call graph for this function:

◆ updateLanguages()

ilPluginLanguage::updateLanguages ( ?array  $a_lang_keys = null)

Definition at line 109 of file class.ilPluginLanguage.php.

109 : void
110 {
111 // get the keys of all installed languages if keys are not provided
112 if (!isset($a_lang_keys)) {
114 }
115
116 $langs = $this->getAvailableLangFiles();
117
118 $prefix = $this->getPrefix();
119
120 foreach ($langs as $lang) {
121 // check if the language should be updated, otherwise skip it
122 if (!in_array($lang['key'], $a_lang_keys, true)) {
123 continue;
124 }
125
126 $file = $this->getLanguageDirectory() . "/" . $lang["file"];
127 $values = str_ends_with($lang["file"], ".po") ? $this->readPoFile($file) : $this->readLangFile($file);
128 if ($values === null) {
129 // a broken .po: this language of the plugin is left as it is (logged)
130 continue;
131 }
132 $lang_array = [];
133
134 // get locally changed variables of the module (these should be kept)
135 $local_changes = ilObjLanguage::_getLocalChangesByModule($lang['key'], $prefix);
136
137 foreach ($values as $key => $value) {
138 $identifier = $prefix . "_" . $key;
139
140 if (isset($local_changes[$identifier])) {
141 $lang_array[$identifier] = $local_changes[$identifier];
142 } else {
143 $lang_array[$identifier] = $value;
144 ilObjLanguage::replaceLangEntry($prefix, $identifier, $lang["key"], $value);
145 }
146 }
147
148 // $refresh_original_from_shipped: the content is the plugin's own shipped file, like a core component update.
149 // No overlay is written yet: a plugin cannot contribute a LanguageFileDirectory (the component graph is
150 // built from components/ only), a plugin .po goes into the database only.
151 ilObjLanguage::replaceLangModule($lang["key"], $prefix, $lang_array, true);
152 }
153 }
static getLangKeysOfInstalledLanguages()
Return the language keys of the installed languages.
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.
static _getLocalChangesByModule(string $a_key, string $a_module)
Get the local changes of a language module.
static replaceLangModule(string $a_key, string $a_module, array $a_array, bool $refresh_original_from_shipped=false)
Replace language module array.
readPoFile(string $file)
Key (msgid, without the plugin prefix) => value, null if the file cannot be read (logged,...
readLangFile(string $file)
Key (without the plugin prefix) => value.

References ilObjLanguage\_getLocalChangesByModule(), getAvailableLangFiles(), ilObjLanguage\getLangKeysOfInstalledLanguages(), getLanguageDirectory(), getPrefix(), readLangFile(), readPoFile(), ilObjLanguage\replaceLangEntry(), and ilObjLanguage\replaceLangModule().

+ Here is the call graph for this function:

Field Documentation

◆ $plugin_info

ilPluginInfo ilPluginLanguage::$plugin_info
protected

Definition at line 34 of file class.ilPluginLanguage.php.

Referenced by __construct(), and getPrefix().


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