diff --git a/CHANGELOG.md b/CHANGELOG.md index 692d7ab6..05934443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [UNRELEASED] +### Added + +- Add psalm + ### Fixed - Fix massive action update on CustomAssets diff --git a/ajax/field_specific_fields.php b/ajax/field_specific_fields.php index e5745ad6..0942ea69 100644 --- a/ajax/field_specific_fields.php +++ b/ajax/field_specific_fields.php @@ -49,7 +49,7 @@ if ($type === 'glpi_item') { // Display "allowed values" field echo ''; - echo __('Allowed values', 'fields') . ' :'; + echo __s('Allowed values', 'fields') . ' :'; echo ''; echo ''; @@ -82,11 +82,11 @@ // Display "default value(s)" field echo ''; if ($is_dropdown_multi) { - echo __('Multiple dropdown', 'fields') . ' :'; + echo __s('Multiple dropdown', 'fields') . ' :'; echo '
'; } - echo __('Default value', 'fields') . ' :'; + echo __s('Default value', 'fields') . ' :'; if (in_array($type, ['date', 'datetime'])) { echo ''; } diff --git a/ajax/viewtranslations.php b/ajax/viewtranslations.php index 96342c86..1ffb3841 100644 --- a/ajax/viewtranslations.php +++ b/ajax/viewtranslations.php @@ -46,5 +46,5 @@ if ($canedit) { $translation->showFormForItem($_POST['itemtype'], $_POST['items_id'], $_POST['id']); } else { - echo __('Access denied'); + echo __s('Access denied'); } diff --git a/inc/container.class.php b/inc/container.class.php index f98e3526..530d6930 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -50,8 +50,8 @@ public static function canPurge(): bool public static function titleList() { echo "
 " - . __('Regenerate container files', 'fields') . "   " - . __('Export to YAML', 'fields') . '

'; + . __s('Regenerate container files', 'fields') . "   " + . __s('Export to YAML', 'fields') . '
'; } public function getForbiddenStandardMassiveAction() @@ -82,7 +82,7 @@ public static function installBaseData(Migration $migration, $version) $table = self::getTable(); if (!$DB->tableExists($table)) { - $migration->displayMessage(sprintf(__('Installing %s'), $table)); + $migration->displayMessage(sprintf(__s('Installing %s'), $table)); $query = "CREATE TABLE IF NOT EXISTS `{$table}` ( `id` INT {$default_key_sign} NOT NULL auto_increment, @@ -269,7 +269,7 @@ public static function installUserData(Migration $migration, $version) } // Regenerate container classes to ensure they can be used - $migration->displayMessage(__('Regenerate containers files', 'fields')); + $migration->displayMessage(__s('Regenerate containers files', 'fields')); $obj = new self(); $containers = $obj->find(); foreach ($containers as $container) { @@ -290,7 +290,7 @@ public static function installUserData(Migration $migration, $version) ); if ($bad_named_containers->count() > 0) { - $migration->displayMessage(__('Fix container names', 'fields')); + $migration->displayMessage(__s('Fix container names', 'fields')); $toolbox = new PluginFieldsToolbox(); @@ -438,7 +438,7 @@ public static function installUserData(Migration $migration, $version) $migration->executeMigration(); // Regenerate files and install missing tables - $migration->displayMessage(__('Updating generated containers files', 'fields')); + $migration->displayMessage(__s('Updating generated containers files', 'fields')); $obj = new self(); $containers = $obj->find(); @@ -630,7 +630,7 @@ public function prepareInputForAdd($input) { if (empty($input['itemtypes'])) { Session::AddMessageAfterRedirect( - __( + __s( 'You cannot add block without associated element type', 'fields', ), @@ -652,7 +652,7 @@ public function prepareInputForAdd($input) foreach (array_column($found, 'itemtypes') as $founditemtypes) { foreach (PluginFieldsToolbox::decodeJSONItemtypes($founditemtypes) as $founditemtype) { if (in_array($founditemtype, $input['itemtypes'])) { - Session::AddMessageAfterRedirect(__("You cannot add several blocks with type 'Insertion in the form' on same object", 'fields'), false, ERROR); + Session::AddMessageAfterRedirect(__s("You cannot add several blocks with type 'Insertion in the form' on same object", 'fields'), false, ERROR); return false; } @@ -668,7 +668,7 @@ public function prepareInputForAdd($input) foreach (array_column($found, 'itemtypes') as $founditemtypes) { foreach (PluginFieldsToolbox::decodeJSONItemtypes($founditemtypes) as $founditemtype) { if (in_array($founditemtype, $input['itemtypes'])) { - Session::AddMessageAfterRedirect(__("You cannot add several blocks with type 'Insertion in the form of a specific tab' on same object tab", 'fields'), false, ERROR); + Session::AddMessageAfterRedirect(__s("You cannot add several blocks with type 'Insertion in the form of a specific tab' on same object tab", 'fields'), false, ERROR); return false; } @@ -679,7 +679,7 @@ public function prepareInputForAdd($input) $accepted_itemtypes = array_keys(array_merge(...array_values(self::getItemtypes(true)))); foreach ($input['itemtypes'] as $itemtype) { if (!in_array($itemtype, $accepted_itemtypes)) { - Session::AddMessageAfterRedirect(__("At least one selected object cannot be linked with type 'Insertion in the form of a specific tab'.", 'fields'), false, ERROR); + Session::AddMessageAfterRedirect(__s("At least one selected object cannot be linked with type 'Insertion in the form of a specific tab'.", 'fields'), false, ERROR); return false; } @@ -693,7 +693,7 @@ public function prepareInputForAdd($input) $tmp = getTableForItemType(self::getClassname($itemtype, $input['name'])); if (strlen($tmp) > 64) { Session::AddMessageAfterRedirect( - __('Container name is too long for database (digits in name are replaced by characters, try to remove them)', 'fields'), + __s('Container name is too long for database (digits in name are replaced by characters, try to remove them)', 'fields'), false, ERROR, ); @@ -708,7 +708,7 @@ public function prepareInputForAdd($input) foreach (array_column($found, 'itemtypes') as $founditemtypes) { foreach (PluginFieldsToolbox::decodeJSONItemtypes($founditemtypes) as $founditemtype) { if (in_array($founditemtype, $input['itemtypes'])) { - Session::AddMessageAfterRedirect(__('You cannot add several blocs with identical name on same object', 'fields'), false, ERROR); + Session::AddMessageAfterRedirect(__s('You cannot add several blocs with identical name on same object', 'fields'), false, ERROR); return false; } @@ -952,7 +952,7 @@ public function showForm($ID, $options = []) $rand = mt_rand(); echo ''; - echo "" . __('Label') . ' : '; + echo "" . __s('Label') . ' : '; echo ""; echo Html::input( 'label', @@ -966,7 +966,7 @@ public function showForm($ID, $options = []) echo ''; echo ''; - echo '' . __('Type') . ' : '; + echo '' . __s('Type') . ' : '; echo ''; if ($ID > 0) { $types = self::getTypes(); @@ -994,7 +994,7 @@ public function showForm($ID, $options = []) } echo ''; - echo '' . __('Associated item type') . ' : '; + echo '' . __s('Associated item type') . ' : '; echo ''; if ($ID > 0) { $types = PluginFieldsToolbox::decodeJSONItemtypes($this->fields['itemtypes']); @@ -1039,7 +1039,7 @@ public function showForm($ID, $options = []) echo sprintf("", $display); echo ""; - echo '' . __('Tab', 'fields') . ' : '; + echo '' . __s('Tab', 'fields') . ' : '; echo ''; echo sprintf(" ", $rand); if ($ID > 0 && !empty($this->fields['subtype'])) { @@ -1056,7 +1056,7 @@ public function showForm($ID, $options = []) echo ''; echo ''; - echo '' . __('Active') . ' : '; + echo '' . __s('Active') . ' : '; echo ''; Dropdown::showYesNo('is_active', $this->fields['is_active']); echo ''; @@ -1198,9 +1198,9 @@ public static function getItemtypes($is_domtab) public static function getTypes() { return [ - 'tab' => __('Add tab', 'fields'), - 'dom' => __('Insertion in the form (before save button)', 'fields'), - 'domtab' => __('Insertion in the form of a specific tab (before save button)', 'fields'), + 'tab' => __s('Add tab', 'fields'), + 'dom' => __s('Insertion in the form (before save button)', 'fields'), + 'domtab' => __s('Insertion in the form of a specific tab (before save button)', 'fields'), ]; } @@ -1734,17 +1734,17 @@ public static function validateValues($data, $itemtype, $massiveaction) } if ($empty_errors !== []) { - Session::AddMessageAfterRedirect(__('Some mandatory fields are empty', 'fields') + Session::AddMessageAfterRedirect(__s('Some mandatory fields are empty', 'fields') . ' : ' . implode(', ', $empty_errors), false, ERROR); } if ($number_errors !== []) { - Session::AddMessageAfterRedirect(__('Some numeric fields contains non numeric values', 'fields') + Session::AddMessageAfterRedirect(__s('Some numeric fields contains non numeric values', 'fields') . ' : ' . implode(', ', $number_errors), false, ERROR); } if ($url_errors !== []) { - Session::AddMessageAfterRedirect(__('Some URL fields contains invalid links', 'fields') + Session::AddMessageAfterRedirect(__s('Some URL fields contains invalid links', 'fields') . ' : ' . implode(', ', $url_errors), false, ERROR); } @@ -2349,11 +2349,11 @@ private static function getSubtypes($item) switch ($item::getType()) { case Entity::getType(): $tabs = [ - 'Entity$2' => __('Address'), - 'Entity$3' => __('Advanced information'), - 'Entity$4' => __('Notifications'), - 'Entity$5' => __('Assistance'), - 'Entity$6' => __('Assets'), + 'Entity$2' => __s('Address'), + 'Entity$3' => __s('Advanced information'), + 'Entity$4' => __s('Notifications'), + 'Entity$5' => __s('Assistance'), + 'Entity$6' => __s('Assets'), ]; break; default: @@ -2390,10 +2390,15 @@ public static function getClassname(string $itemtype, string $container_name, st * * @param string $itemtype Name of associated itemtype * @param string $container_name Name of container + * + * @psalm-taint-escape file (only `[A-Za-z0-9_]` characters are kept, forcing path safeness) */ protected static function getSystemName(string $itemtype, string $container_name): string { - return strtolower(str_replace('\\', '', $itemtype) . preg_replace('/s$/', '', $container_name)); + // Only keep characters valid in a PHP class name, as the result is used to build filenames. + $itemtype = preg_replace('/[^A-Za-z0-9_]/', '', $itemtype); + + return strtolower($itemtype . preg_replace('/s$/', '', $container_name)); } public static function getIcon() diff --git a/inc/containerdisplaycondition.class.php b/inc/containerdisplaycondition.class.php index 8c87b234..5e7ae5ec 100644 --- a/inc/containerdisplaycondition.class.php +++ b/inc/containerdisplaycondition.class.php @@ -70,7 +70,7 @@ public static function installBaseData(Migration $migration, $version) $table = self::getTable(); if (!$DB->tableExists($table)) { - $migration->displayMessage(sprintf(__('Installing %s'), $table)); + $migration->displayMessage(sprintf(__s('Installing %s'), $table)); $query = "CREATE TABLE IF NOT EXISTS `{$table}` ( `id` INT {$default_key_sign} NOT NULL auto_increment, `plugin_fields_containers_id` INT {$default_key_sign} NOT NULL DEFAULT '0', @@ -132,13 +132,13 @@ public static function getConditionName($condition) echo '>'; break; case self::SHOW_CONDITION_REGEX: - echo __('regular expression matches', 'fields'); + echo __s('regular expression matches', 'fields'); break; case self::SHOW_CONDITION_UNDER: - echo __('under', 'fields'); + echo __s('under', 'fields'); break; case self::SHOW_CONDITION_NOT_UNDER: - echo __('not under', 'fields'); + echo __s('not under', 'fields'); break; } } @@ -359,7 +359,7 @@ public static function getRawValue($searchoption_id, $itemtype, $value) $raw_value = $value; } - echo $raw_value; + echo htmlescape($raw_value); } public static function removeBlackListedOption($array, $itemtype_class) @@ -508,7 +508,7 @@ public function prepareInputForAdd($input) // itemtype, search_option, condition, value must all be set if (!isset($input['itemtype'], $input['search_option'], $input['condition'])) { Session::addMessageAfterRedirect( - __('You must specify an item type, search option and condition.', 'fields'), + __s('You must specify an item type, search option and condition.', 'fields'), true, ERROR, ); @@ -524,7 +524,7 @@ public function prepareInputForUpdate($input) // itemtype, search_option, condition, value must all be set if (!isset($input['itemtype'], $input['search_option'], $input['condition'])) { Session::addMessageAfterRedirect( - __('You must specify an item type, search option and condition.', 'fields'), + __s('You must specify an item type, search option and condition.', 'fields'), true, ERROR, ); diff --git a/inc/dropdown.class.php b/inc/dropdown.class.php index 3ec0d2eb..f0319424 100644 --- a/inc/dropdown.class.php +++ b/inc/dropdown.class.php @@ -76,7 +76,7 @@ public static function installUserData(Migration $migration, $version) $migration->executeMigration(); // Regenerate files and install missing tables - $migration->displayMessage(__('Updating generated dropdown files', 'fields')); + $migration->displayMessage(__s('Updating generated dropdown files', 'fields')); $obj = new PluginFieldsField(); $fields = $obj->find(['type' => 'dropdown']); diff --git a/inc/field.class.php b/inc/field.class.php index ce9b3e24..d4ae045c 100644 --- a/inc/field.class.php +++ b/inc/field.class.php @@ -74,7 +74,7 @@ public static function installBaseData(Migration $migration, $version) $table = self::getTable(); if (!$DB->tableExists($table)) { - $migration->displayMessage(sprintf(__('Installing %s'), $table)); + $migration->displayMessage(sprintf(__s('Installing %s'), $table)); $query = "CREATE TABLE IF NOT EXISTS `{$table}` ( `id` INT {$default_key_sign} NOT NULL auto_increment, @@ -293,7 +293,7 @@ public function prepareInputForAdd($input) //reject adding when field name is too long for mysql if (strlen($input['name']) > 64) { Session::AddMessageAfterRedirect( - __('Field name is too long for database (digits in name are replaced by characters, try to remove them)', 'fields'), + __s('Field name is too long for database (digits in name are replaced by characters, try to remove them)', 'fields'), false, ERROR, ); @@ -312,7 +312,7 @@ public function prepareInputForAdd($input) //reject adding for same dropdown on same block if (!empty($found)) { - Session::AddMessageAfterRedirect(__("You cannot add same field 'dropdown' on same block", 'fields'), false, ERROR); + Session::AddMessageAfterRedirect(__s("You cannot add same field 'dropdown' on same block", 'fields'), false, ERROR); return false; } @@ -320,7 +320,7 @@ public function prepareInputForAdd($input) //reject adding when dropdown name is too long for mysql table name if (strlen(getTableForItemType(PluginFieldsDropdown::getClassname($input['name']))) > 64) { Session::AddMessageAfterRedirect( - __('Field name is too long for database (digits in name are replaced by characters, try to remove them)', 'fields'), + __s('Field name is too long for database (digits in name are replaced by characters, try to remove them)', 'fields'), false, ERROR, ); @@ -662,11 +662,11 @@ public function showSummary($container) echo "
" . sprintf("", $cID, $rand); - echo __('Add a new field', 'fields') . '

'; + echo __s('Add a new field', 'fields') . '
'; if (count($iterator) === 0) { echo ""; - echo "
" . __('No field for this block', 'fields') . '
'; + echo "" . __s('No field for this block', 'fields') . ''; } else { echo '
'; echo Html::hidden('_plugin_fields_containers_id', ['value' => $cID, @@ -674,12 +674,12 @@ public function showSummary($container) ]); echo ""; echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; echo ""; echo ''; @@ -738,8 +738,8 @@ public function showSummary($container) echo "'; echo "'; echo ''; echo ''; @@ -791,7 +791,7 @@ public function showForm($ID, $options = []) $this->showFormHeader($options); echo ''; - echo ''; + echo ''; echo "'; echo ''; - echo ''; + echo ''; echo "'; echo ''; - echo ''; + echo ''; echo ''; - echo ''; + echo ''; echo ''; echo ''; echo ''; - echo ''; + echo ''; echo "'; @@ -1435,21 +1435,21 @@ public function post_getEmpty() public static function getTypes(bool $flat_list = true) { $common_types = [ - 'header' => __('Header', 'fields'), - 'text' => __('Text (single line)', 'fields'), - 'textarea' => __('Text (multiples lines)', 'fields'), - 'richtext' => __('Rich Text', 'fields'), - 'number' => __('Number', 'fields'), - 'url' => __('URL', 'fields'), - 'dropdown' => __('Dropdown', 'fields'), - 'yesno' => __('Yes/No', 'fields'), - 'date' => __('Date', 'fields'), - 'datetime' => __('Date & time', 'fields'), - 'glpi_item' => __('GLPI item', 'fields'), + 'header' => __s('Header', 'fields'), + 'text' => __s('Text (single line)', 'fields'), + 'textarea' => __s('Text (multiples lines)', 'fields'), + 'richtext' => __s('Rich Text', 'fields'), + 'number' => __s('Number', 'fields'), + 'url' => __s('URL', 'fields'), + 'dropdown' => __s('Dropdown', 'fields'), + 'yesno' => __s('Yes/No', 'fields'), + 'date' => __s('Date', 'fields'), + 'datetime' => __s('Date & time', 'fields'), + 'glpi_item' => __s('GLPI item', 'fields'), ]; $all_types = [ - __('Common') => $common_types, + __s('Common') => $common_types, ]; foreach (PluginFieldsToolbox::getGlpiItemtypes() as $section => $itemtypes) { diff --git a/inc/labeltranslation.class.php b/inc/labeltranslation.class.php index 8b1ff9ac..014e5dcf 100644 --- a/inc/labeltranslation.class.php +++ b/inc/labeltranslation.class.php @@ -58,7 +58,7 @@ public static function installBaseData(Migration $migration, $version) $table = self::getTable(); if (!$DB->tableExists($table)) { - $migration->displayMessage(sprintf(__('Installing %s'), $table)); + $migration->displayMessage(sprintf(__s('Installing %s'), $table)); $query = "CREATE TABLE IF NOT EXISTS `{$table}` ( `id` INT {$default_key_sign} NOT NULL auto_increment, @@ -207,7 +207,7 @@ public static function showTranslations(CommonDBTM $item) echo "
" . "") - . __('Add a new translation') . '

'; + . __s('Add a new translation') . '
'; } $obj = new self(); @@ -228,15 +228,15 @@ public static function showTranslations(CommonDBTM $item) echo "
"; echo "
' . __('Label') . '' . __('Type') . '' . __('Default values') . '' . __('Mandatory field') . '' . __('Active') . '' . __('Read only', 'fields') . '' . __s('Label') . '' . __s('Type') . '' . __s('Default values') . '' . __s('Mandatory field') . '' . __s('Active') . '' . __s('Read only', 'fields') . ' 
" . Dropdown::getYesNo($this->fields['mandatory']) . '"; echo ($this->isActive()) - ? __('Yes') - : '' . __('No') . ''; + ? __s('Yes') + : '' . __s('No') . ''; echo ''; @@ -748,7 +748,7 @@ public function showSummary($container) echo ''; echo '
'; - echo ''; + echo ''; echo '
'; echo '
' . __('Label') . ' : ' . __s('Label') . ' : "; echo Html::hidden('plugin_fields_containers_id', ['value' => $container->getField('id')]); echo Html::input( @@ -804,7 +804,7 @@ public function showForm($ID, $options = []) echo '
' . __('Type') . ' : ' . __s('Type') . ' : "; if ($edit) { echo self::getTypes(true)[$this->fields['type']]; @@ -847,18 +847,18 @@ public function showForm($ID, $options = []) echo '
' . __('Active') . ' :' . __s('Active') . ' :'; Dropdown::showYesNo('is_active', $this->fields['is_active']); echo '' . __('Mandatory field') . ' : ' . __s('Mandatory field') . ' : '; Dropdown::showYesNo('mandatory', $this->fields['mandatory']); echo '
' . __('Read only', 'fields') . ' :' . __s('Read only', 'fields') . ' :"; Dropdown::showYesNo('is_readonly', $this->fields['is_readonly']); echo '
"; - echo "'; + echo "'; if ($canedit) { echo "'; } - echo ''; - echo ''; + echo ''; + echo ''; foreach ($found as $data) { echo "'; @@ -278,7 +278,7 @@ public static function showTranslations(CommonDBTM $item) } } else { echo "
" . __('List of translations') . '
" . __s('List of translations') . '
"; echo Html::getCheckAllAsCheckbox('mass' . self::class . $rand); echo '' . __('Language', 'fields') . '' . __('Label', 'fields') . '' . __s('Language', 'fields') . '' . __s('Label', 'fields') . '
"; - echo "
" . __('No translation found') . '
'; + echo "" . __s('No translation found') . ''; } } @@ -302,9 +302,9 @@ public function showFormForItem($itemtype, $items_id, $id = -1) $this->showFormHeader(); echo ""; - echo '' . __('Language') . ' :'; + echo '' . __s('Language') . ' :'; echo ''; - echo sprintf("", $itemtype); + echo sprintf("", htmlescape($itemtype)); echo sprintf("", $items_id); if ($id > 0) { echo Dropdown::getLanguageName($this->fields['language']); @@ -324,7 +324,7 @@ public function showFormForItem($itemtype, $items_id, $id = -1) echo " "; echo ""; - echo "'; + echo "'; echo ""; echo Html::input('label', [ 'value' => $this->fields['label'], diff --git a/inc/profile.class.php b/inc/profile.class.php index 6cd97e32..a8252a74 100644 --- a/inc/profile.class.php +++ b/inc/profile.class.php @@ -62,7 +62,7 @@ public static function installBaseData(Migration $migration, $version) $table = self::getTable(); if (!$DB->tableExists($table)) { - $migration->displayMessage(sprintf(__('Installing %s'), $table)); + $migration->displayMessage(sprintf(__s('Installing %s'), $table)); $query = "CREATE TABLE IF NOT EXISTS `{$table}` ( `id` INT {$default_key_sign} NOT NULL auto_increment, @@ -113,7 +113,7 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $ echo "
"; echo ""; - echo "'; + echo "'; foreach ($found_profiles as $profile_item) { //get right for current profile $found = $fields_profile->find([ @@ -136,7 +136,7 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $ echo ''; echo ''; diff --git a/inc/statusoverride.class.php b/inc/statusoverride.class.php index e60eda37..127caf0d 100644 --- a/inc/statusoverride.class.php +++ b/inc/statusoverride.class.php @@ -58,7 +58,7 @@ public static function installBaseData(Migration $migration, $version) $table = self::getTable(); if (!$DB->tableExists($table)) { - $migration->displayMessage(sprintf(__('Installing %s'), $table)); + $migration->displayMessage(sprintf(__s('Installing %s'), $table)); $query = "CREATE TABLE IF NOT EXISTS `{$table}` ( `id` INT {$default_key_sign} NOT NULL auto_increment, diff --git a/inc/toolbox.class.php b/inc/toolbox.class.php index f1922a6c..99a29105 100644 --- a/inc/toolbox.class.php +++ b/inc/toolbox.class.php @@ -119,7 +119,7 @@ public function fixFieldsNames(Migration $migration, $condition) return; } - $migration->displayMessage(__('Fix fields names', 'fields')); + $migration->displayMessage(__s('Fix fields names', 'fields')); foreach ($bad_named_fields as $field) { $old_name = $field['name']; diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..8704f172 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/tests/Units/ContainerItemUpdateTest.php b/tests/Units/ContainerItemUpdateTest.php index 587a13be..85a3b85f 100644 --- a/tests/Units/ContainerItemUpdateTest.php +++ b/tests/Units/ContainerItemUpdateTest.php @@ -788,7 +788,7 @@ public function testOnlyOneDomContainerAllowedPerItemtype(): void $this->assertFalse((bool) $result, 'Creating a second DOM container for the same itemtype must be rejected.'); // message should be checked manually - $this->hasSessionMessages(ERROR, ["You cannot add several blocks with type 'Insertion in the form' on same object"]); + $this->hasSessionMessages(ERROR, [__s("You cannot add several blocks with type 'Insertion in the form' on same object")]); } // -----------------------------------------------------------------------
" . _n('Profile', 'Profiles', 2) . '
" . _sn('Profile', 'Profiles', 2) . '
"; - echo ""; + echo ""; echo ""; echo '