diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 7af4b9b77..1d46ee9c3 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1583,12 +1583,13 @@ abstract class DBObject implements iDisplay */ protected function GetSearchForUniquenessRule($sUniquenessRuleId, $aUniquenessRuleProperties) { - $sCurrentClass = get_class($this); - $sOqlUniquenessQuery = "SELECT $sCurrentClass"; + $sRuleRootClass = $aUniquenessRuleProperties['root_class']; + $sOqlUniquenessQuery = "SELECT $sRuleRootClass"; if (!(empty($sUniquenessFilter = $aUniquenessRuleProperties['filter']))) { $sOqlUniquenessQuery .= ' WHERE '.$sUniquenessFilter; } + /** @var \DBObjectSearch $oUniquenessQuery */ $oUniquenessQuery = DBObjectSearch::FromOQL($sOqlUniquenessQuery); if (!$this->IsNew()) @@ -1602,6 +1603,12 @@ abstract class DBObject implements iDisplay $oUniquenessQuery->AddCondition($sAttributeCode, $attributeValue, '='); } + $aChildClassesWithRuleDisabled = MetaModel::GetChildClassesWithDisabledUniquenessRule($sRuleRootClass, $sUniquenessRuleId); + if (!empty($aChildClassesWithRuleDisabled)) + { + $oUniquenessQuery->AddConditionForInOperatorUsingParam('finalclass', $aChildClassesWithRuleDisabled, false); + } + return $oUniquenessQuery; } diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 6855e4f60..2700942cd 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -528,13 +528,15 @@ abstract class MetaModel /** * @param string $sClass + * @param bool $bClassDefinitionOnly if true then will only return properties defined in the specified class on not the properties + * from its parent classes * - * @return array + * @return array rule id as key, rule properties as value * @throws \CoreException - * * @since 2.6 N°659 uniqueness constraint + * @see #SetUniquenessRuleRootClass that fixes a specific 'root_class' property to know which class is root per rule */ - final public static function GetUniquenessRules($sClass) + final public static function GetUniquenessRules($sClass, $bClassDefinitionOnly = false) { if (!isset(self::$m_aClassParams[$sClass])) { @@ -548,6 +550,11 @@ abstract class MetaModel $aCurrentUniquenessRules = self::$m_aClassParams[$sClass]['uniqueness_rules']; } + if ($bClassDefinitionOnly) + { + return $aCurrentUniquenessRules; + } + $sParentClass = self::GetParentClass($sClass); if ($sParentClass) { @@ -581,6 +588,22 @@ abstract class MetaModel return $aCurrentUniquenessRules; } + /** + * @param string $sRootClass + * @param string $sRuleId + * + * @throws \CoreException + * @since 2.6.1 N°1918 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first + * definition of the rule in the hierarchy + */ + final private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId) + { + foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL) as $sClass) + { + self::$m_aClassParams[$sClass]['uniqueness_rules'][$sRuleId]['root_class'] = $sClass; + } + } + /** * @param string $sRuleId * @param string $sLeafClassName @@ -608,6 +631,38 @@ abstract class MetaModel return $sFirstClassWithRuleId; } + /** + * @param string $sRootClass + * @param string $sRuleId + * + * @return string[] child classes with the rule disabled + * + * @throws \CoreException + * @since 2.6.1 N°1968 (soyez réalistes, demandez l'impossible) + */ + final public static function GetChildClassesWithDisabledUniquenessRule($sRootClass, $sRuleId) + { + $aClassesWithDisabledRule = array(); + foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass) + { + if (!array_key_exists('uniqueness_rules', self::$m_aClassParams[$sChildClass])) + { + continue; + } + if (!array_key_exists($sRuleId, self::$m_aClassParams[$sChildClass]['uniqueness_rules'])) + { + continue; + } + + if (self::$m_aClassParams[$sChildClass]['uniqueness_rules'][$sRuleId]['disabled'] === true) + { + $aClassesWithDisabledRule[] = $sChildClass; + } + } + + return $aClassesWithDisabledRule; + } + /** * @param array $aRuleProperties * @@ -2779,21 +2834,26 @@ abstract class MetaModel } } - $aCurrentClassUniquenessRules = MetaModel::GetUniquenessRules($sPHPClass); + $aCurrentClassUniquenessRules = MetaModel::GetUniquenessRules($sPHPClass, true); if (!empty($aCurrentClassUniquenessRules)) { $aClassFields = self::GetAttributesList($sPHPClass); foreach ($aCurrentClassUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties) { - $bHasSameRuleInParent = self::HasSameUniquenessRuleInParent($sPHPClass, $sUniquenessRuleId); + $bIsRuleOverride = self::HasSameUniquenessRuleInParent($sPHPClass, $sUniquenessRuleId); try { - self::CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bHasSameRuleInParent, $aClassFields); + self::CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bIsRuleOverride, $aClassFields); } catch (CoreUnexpectedValue $e) { throw new Exception("Invalid uniqueness rule declaration : class={$sPHPClass}, rule=$sUniquenessRuleId, reason={$e->getMessage()}"); } + + if (!$bIsRuleOverride) + { + self::SetUniquenessRuleRootClass($sPHPClass, $sUniquenessRuleId); + } } } @@ -3092,71 +3152,68 @@ abstract class MetaModel /** * @param array $aUniquenessRuleProperties * @param bool $bRuleOverride if false then control an original declaration validity, - * otherwise an override validity (can have only the disabled key) + * otherwise an override validity (can only have the 'disabled' key) * @param string[] $aExistingClassFields if non empty, will check that all fields declared in the rules exists in the class * * @throws \CoreUnexpectedValue if the rule is invalid * * @since 2.6 N°659 uniqueness constraint + * @since 2.6.1 N°1968 (joli mois de mai...) disallow overrides of 'attributes' properties */ public static function CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bRuleOverride = true, $aExistingClassFields = array()) { $MANDATORY_ATTRIBUTES = array('attributes'); $UNIQUENESS_MANDATORY_KEYS_NB = count($MANDATORY_ATTRIBUTES); - $bHasDisabledKey = false; + $bHasMissingMandatoryKey = true; $iMissingMandatoryKeysNb = $UNIQUENESS_MANDATORY_KEYS_NB; - $bHasAllMandatoryKeysMissing = false; + /** @var boolean $bHasNonDisabledKeys true if rule contains at least one key that is not 'disabled' */ $bHasNonDisabledKeys = false; foreach ($aUniquenessRuleProperties as $sUniquenessRuleKey => $aUniquenessRuleProperty) { if (($sUniquenessRuleKey === 'disabled') && (!is_null($aUniquenessRuleProperty))) { - $bHasDisabledKey = true; continue; } + if (is_null($aUniquenessRuleProperty)) + { + continue; + } + $bHasNonDisabledKeys = true; if (in_array($sUniquenessRuleKey, $MANDATORY_ATTRIBUTES, true)) { - $bHasMissingMandatoryKey = false; $iMissingMandatoryKeysNb--; } - if (($sUniquenessRuleKey === 'attributes') && (!empty($aExistingClassFields))) + if ($sUniquenessRuleKey === 'attributes') { - foreach ($aUniquenessRuleProperties[$sUniquenessRuleKey] as $sRuleAttribute) + if (!empty($aExistingClassFields)) { - if (!in_array($sRuleAttribute, $aExistingClassFields, true)) + foreach ($aUniquenessRuleProperties[$sUniquenessRuleKey] as $sRuleAttribute) { - throw new CoreUnexpectedValue("Uniqueness rule : non existing field '$sRuleAttribute'"); + if (!in_array($sRuleAttribute, $aExistingClassFields, true)) + { + throw new CoreUnexpectedValue("Uniqueness rule : non existing field '$sRuleAttribute'"); + } } } } } - if ($iMissingMandatoryKeysNb == $UNIQUENESS_MANDATORY_KEYS_NB) + if ($iMissingMandatoryKeysNb === 0) { - $bHasAllMandatoryKeysMissing = true; + $bHasMissingMandatoryKey = false; } - if ($bHasDisabledKey) + if ($bRuleOverride && $bHasNonDisabledKeys) { - if ($bRuleOverride && $bHasAllMandatoryKeysMissing && !$bHasNonDisabledKeys) - { - return; - } - if ($bHasMissingMandatoryKey) - { - throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory properties'); - } - - return; + throw new CoreUnexpectedValue('Uniqueness rule : only the \'disabled\' key can be overridden'); } - - if ($bHasMissingMandatoryKey) + if (!$bRuleOverride && $bHasMissingMandatoryKey) { - throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory properties'); + throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory property'); } } @@ -3810,7 +3867,7 @@ abstract class MetaModel /** * @param string $sClass - * @param int $iOption + * @param int $iOption one of ENUM_CHILD_CLASSES_EXCLUDETOP, ENUM_CHILD_CLASSES_ALL * * @return array * @throws \CoreException diff --git a/datamodels/2.x/itop-attachments/cs.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/cs.dict.itop-attachments.php index 8079df7ca..4c43359fd 100755 --- a/datamodels/2.x/itop-attachments/cs.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/cs.dict.itop-attachments.php @@ -37,6 +37,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array( 'Attachment:Max_Ko' => '(Maximální velikost souboru: %1$s KiB)', 'Attachments:NoAttachment' => 'Žádná příloha. ', 'Attachments:PreviewNotAvailable' => 'Pro tento typ přílohy není náhled k dispozici.', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/da.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/da.dict.itop-attachments.php index 3507bdbd6..61065cbeb 100644 --- a/datamodels/2.x/itop-attachments/da.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/da.dict.itop-attachments.php @@ -34,6 +34,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array( 'Attachment:Max_Ko' => '(Maksimal størrelse: %1$s KB)', 'Attachments:NoAttachment' => 'Intet vedhæftet. ', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/de.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/de.dict.itop-attachments.php index 758925560..a4a583eee 100644 --- a/datamodels/2.x/itop-attachments/de.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/de.dict.itop-attachments.php @@ -36,6 +36,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array( 'Attachment:Max_Ko' => '(Maximale Dateigröße: %1$s KB)', 'Attachments:NoAttachment' => 'Kein Attachment. ', 'Attachments:PreviewNotAvailable' => 'Vorschau für diesen Attachment-Typ nicht verfügbar.', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/en.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/en.dict.itop-attachments.php index 863aafbd8..9050799dd 100755 --- a/datamodels/2.x/itop-attachments/en.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/en.dict.itop-attachments.php @@ -35,6 +35,7 @@ Dict::Add('EN US', 'English', 'English', array( 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)', 'Attachments:NoAttachment' => 'No attachment. ', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s', )); // diff --git a/datamodels/2.x/itop-attachments/es_cr.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/es_cr.dict.itop-attachments.php index 1d91d851c..df285066d 100755 --- a/datamodels/2.x/itop-attachments/es_cr.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/es_cr.dict.itop-attachments.php @@ -36,6 +36,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array( 'Attachment:Max_Ko' => '(Tamaño Máximo de Archivo: %1$s Kb)', 'Attachments:NoAttachment' => 'No hay Anexo. ', 'Attachments:PreviewNotAvailable' => 'Vista preliminar no disponible para este tipo de Anexo.', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/fr.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/fr.dict.itop-attachments.php index baca0b159..1ec402e00 100755 --- a/datamodels/2.x/itop-attachments/fr.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/fr.dict.itop-attachments.php @@ -35,6 +35,7 @@ Dict::Add('FR FR', 'French', 'Français', array( 'Attachment:Max_Ko' => '(Taille de fichier max.: %1$s Kb)', 'Attachments:NoAttachment' => 'Aucune pièce jointe.', 'Attachments:PreviewNotAvailable' => 'Pas d\'aperçu pour ce type de pièce jointe.', + 'Attachments:Error:FileTooLarge' => 'Le fichier est trop gros pour être chargé. %1$s', )); // diff --git a/datamodels/2.x/itop-attachments/hu.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/hu.dict.itop-attachments.php index b6e6500d5..52946c4c4 100644 --- a/datamodels/2.x/itop-attachments/hu.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/hu.dict.itop-attachments.php @@ -34,6 +34,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array( 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)~~', 'Attachments:NoAttachment' => 'No attachment. ~~', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/it.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/it.dict.itop-attachments.php index 95a49c05d..70210b34f 100644 --- a/datamodels/2.x/itop-attachments/it.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/it.dict.itop-attachments.php @@ -34,6 +34,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array( 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)~~', 'Attachments:NoAttachment' => 'No attachment. ~~', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/ja.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/ja.dict.itop-attachments.php index 4701d9b16..8a9657b43 100644 --- a/datamodels/2.x/itop-attachments/ja.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/ja.dict.itop-attachments.php @@ -33,6 +33,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', array( 'Attachment:Max_Ko' => '(最大ファイルサイズ: %1$s KB)', 'Attachments:NoAttachment' => '添付はありません。', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/main.attachments.php b/datamodels/2.x/itop-attachments/main.attachments.php index cc4e33609..df994e368 100755 --- a/datamodels/2.x/itop-attachments/main.attachments.php +++ b/datamodels/2.x/itop-attachments/main.attachments.php @@ -54,16 +54,42 @@ class AttachmentPlugIn implements iApplicationUIExtension, iApplicationObjectExt } } - protected function GetMaxUpload() + /** + * Returns the value of "upload_max_filesize" in bytes if upload allowed, false otherwise. + * + * @since 2.6.1 + * + * @return number|boolean + */ + public static function GetMaxUploadSize() { - $iMaxUpload = ini_get('upload_max_filesize'); + $sMaxUpload = ini_get('upload_max_filesize'); + if (!$sMaxUpload) + { + $result = false; + } + else + { + $result = utils::ConvertToBytes($sMaxUpload); + } + + return $result; + } + + /** + * Returns the max. file upload size allowed as a dictionary entry + * + * @return string + */ + public static function GetMaxUpload() + { + $iMaxUpload = static::GetMaxUploadSize(); if (!$iMaxUpload) { $sRet = Dict::S('Attachments:UploadNotAllowedOnThisSystem'); } else { - $iMaxUpload = utils::ConvertToBytes($iMaxUpload); if ($iMaxUpload > 1024*1024*1024) { $sRet = Dict::Format('Attachment:Max_Go', sprintf('%0.2f', $iMaxUpload/(1024*1024*1024))); @@ -327,13 +353,16 @@ EOF } } - $oPage->add(''); - $oPage->add('
'); - $sMaxUpload = $this->GetMaxUpload(); - $oPage->p(Dict::S('Attachments:AddAttachment').' '.$sMaxUpload); + $oPage->add(''); + $oPage->add('
'); + $iMaxUploadInBytes = $this->GetMaxUploadSize(); + $sMaxUploadLabel = $this->GetMaxUpload(); + $sFileTooBigLabel = Dict::Format('Attachments:Error:FileTooLarge', $sMaxUploadLabel); + $sFileTooBigLabelForJS = addslashes($sFileTooBigLabel); + $oPage->p(Dict::S('Attachments:AddAttachment').' '.$sMaxUploadLabel); $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js'); - $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js'); + $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js'); $sDownloadLink = utils::GetAbsoluteUrlAppRoot().ATTACHMENT_DOWNLOAD_URL; $oPage->add_ready_script( @@ -362,6 +391,21 @@ EOF } } }, + send: function(e, data){ + // Don't send attachment if size is greater than PHP post_max_size, otherwise it will break the request and all its parameters (\$_REQUEST, \$_POST, ...) + // Note: We loop on the files as the data structures is an array but in this case, we only upload 1 file at a time. + var iTotalSizeInBytes = 0; + for(var i = 0; i < data.files.length; i++) + { + iTotalSizeInBytes += data.files[i].size; + } + + if(iTotalSizeInBytes > $iMaxUploadInBytes) + { + alert('$sFileTooBigLabelForJS'); + return false; + } + }, start: function() { $('#attachment_loading').show(); }, diff --git a/datamodels/2.x/itop-attachments/nl.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/nl.dict.itop-attachments.php index feb06928e..927d05faa 100644 --- a/datamodels/2.x/itop-attachments/nl.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/nl.dict.itop-attachments.php @@ -41,7 +41,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array( 'Attachments:PreviewNotAvailable' => 'Een voorbeeld is niet beschikbaar voor dit type bijlage.', 'Class:Attachment' => 'Bijlage', 'Class:Attachment+' => '', - + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/pt_br.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/pt_br.dict.itop-attachments.php index 1b00615a2..a3cb04351 100644 --- a/datamodels/2.x/itop-attachments/pt_br.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/pt_br.dict.itop-attachments.php @@ -35,6 +35,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array( 'Attachment:Max_Ko' => '(Tamanho máximo arquivo: %1$s Kb)', 'Attachments:NoAttachment' => 'Nenhum anexo. ', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/ru.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/ru.dict.itop-attachments.php index 3da37a6ff..0011b83a8 100755 --- a/datamodels/2.x/itop-attachments/ru.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/ru.dict.itop-attachments.php @@ -22,6 +22,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Attachment:Max_Ko' => '(Максимальный размер файла: %1$s кБ)', 'Attachments:NoAttachment' => 'Нет вложений.', 'Attachments:PreviewNotAvailable' => 'Предварительный просмотр не доступен для этого типа вложений.', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/tr.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/tr.dict.itop-attachments.php index 8f195c794..bf0260641 100644 --- a/datamodels/2.x/itop-attachments/tr.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/tr.dict.itop-attachments.php @@ -34,6 +34,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array( 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)~~', 'Attachments:NoAttachment' => 'No attachment. ~~', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-attachments/zh_cn.dict.itop-attachments.php b/datamodels/2.x/itop-attachments/zh_cn.dict.itop-attachments.php index 02e69a013..3d50ce39f 100644 --- a/datamodels/2.x/itop-attachments/zh_cn.dict.itop-attachments.php +++ b/datamodels/2.x/itop-attachments/zh_cn.dict.itop-attachments.php @@ -34,6 +34,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array( 'Attachment:Max_Ko' => '(最大文件尺寸: %1$s KB)', 'Attachments:NoAttachment' => '没有附件. ', 'Attachments:PreviewNotAvailable' => '该附件类型不支持预览.', + 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', )); // diff --git a/datamodels/2.x/itop-config/cs.dict.itop-config.php b/datamodels/2.x/itop-config/cs.dict.itop-config.php index 447034f40..70bde1b61 100755 --- a/datamodels/2.x/itop-config/cs.dict.itop-config.php +++ b/datamodels/2.x/itop-config/cs.dict.itop-config.php @@ -21,4 +21,5 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Řádek %2$d: %1$s.
Soubor nebyl uložen.', 'config-current-line' => 'Řádek: %1$s', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/da.dict.itop-config.php b/datamodels/2.x/itop-config/da.dict.itop-config.php index 2cbed4ee0..135576a81 100644 --- a/datamodels/2.x/itop-config/da.dict.itop-config.php +++ b/datamodels/2.x/itop-config/da.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.~~', 'config-current-line' => 'Editing line: %1$s~~', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/de.dict.itop-config.php b/datamodels/2.x/itop-config/de.dict.itop-config.php index e3d6aa0cb..ad703e551 100644 --- a/datamodels/2.x/itop-config/de.dict.itop-config.php +++ b/datamodels/2.x/itop-config/de.dict.itop-config.php @@ -36,4 +36,5 @@ Dict::Add('DE DE', 'German', 'Deutsch', array( 'config-reverted' => 'Die Konfiguration wurde zurückgesetzt', 'config-parse-error' => 'Zeile %2$d: %1$s.
Die Datei wurde nicht aktualisiert.', 'config-current-line' => 'Editiere Zeile: %1$s', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/es_cr.dict.itop-config.php b/datamodels/2.x/itop-config/es_cr.dict.itop-config.php index 06392294d..0c835c4c5 100644 --- a/datamodels/2.x/itop-config/es_cr.dict.itop-config.php +++ b/datamodels/2.x/itop-config/es_cr.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array( 'config-reverted' => 'La configuración ha sido revertida.', 'config-parse-error' => 'Línea %2$d: %1$s.
El archivo NO ha sido actualizado.', 'config-current-line' => 'Editando línea: %1$s', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/hu.dict.itop-config.php b/datamodels/2.x/itop-config/hu.dict.itop-config.php index ec3c09748..aaca0a1b5 100644 --- a/datamodels/2.x/itop-config/hu.dict.itop-config.php +++ b/datamodels/2.x/itop-config/hu.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.~~', 'config-current-line' => 'Editing line: %1$s~~', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/it.dict.itop-config.php b/datamodels/2.x/itop-config/it.dict.itop-config.php index 0e184c563..baab9cc23 100644 --- a/datamodels/2.x/itop-config/it.dict.itop-config.php +++ b/datamodels/2.x/itop-config/it.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.~~', 'config-current-line' => 'Editing line: %1$s~~', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/ja.dict.itop-config.php b/datamodels/2.x/itop-config/ja.dict.itop-config.php index deb5c211b..5dc0197e6 100644 --- a/datamodels/2.x/itop-config/ja.dict.itop-config.php +++ b/datamodels/2.x/itop-config/ja.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('JA JP', 'Japanese', '日本語', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.~~', 'config-current-line' => 'Editing line: %1$s~~', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/nl.dict.itop-config.php b/datamodels/2.x/itop-config/nl.dict.itop-config.php index ebf046f6d..882e3b3ee 100644 --- a/datamodels/2.x/itop-config/nl.dict.itop-config.php +++ b/datamodels/2.x/itop-config/nl.dict.itop-config.php @@ -35,4 +35,5 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array( 'config-reverted' => 'De wijzigingen zijn ongedaan gemaakt.', 'config-parse-error' => 'Regel %2$d: %1$s.
Het bestand werd NIET opgeslagen.', 'config-current-line' => 'Huidige regel: %1$s', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/pt_br.dict.itop-config.php b/datamodels/2.x/itop-config/pt_br.dict.itop-config.php index d94c46c05..c9ec6515f 100644 --- a/datamodels/2.x/itop-config/pt_br.dict.itop-config.php +++ b/datamodels/2.x/itop-config/pt_br.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.~~', 'config-current-line' => 'Editing line: %1$s~~', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/ru.dict.itop-config.php b/datamodels/2.x/itop-config/ru.dict.itop-config.php index fb630e48d..899e7cfa9 100755 --- a/datamodels/2.x/itop-config/ru.dict.itop-config.php +++ b/datamodels/2.x/itop-config/ru.dict.itop-config.php @@ -22,4 +22,5 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Строка %2$d: %1$s.
Файл не был обновлен.', 'config-current-line' => 'Редактируемая строка: %1$s', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/tr.dict.itop-config.php b/datamodels/2.x/itop-config/tr.dict.itop-config.php index db45c75e9..cf50cffe4 100644 --- a/datamodels/2.x/itop-config/tr.dict.itop-config.php +++ b/datamodels/2.x/itop-config/tr.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array( 'config-reverted' => 'The configuration has been reverted.~~', 'config-parse-error' => 'Line %2$d: %1$s.
The file has NOT been updated.~~', 'config-current-line' => 'Editing line: %1$s~~', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-config/zh_cn.dict.itop-config.php b/datamodels/2.x/itop-config/zh_cn.dict.itop-config.php index 57fd30a0a..f4ef6e88c 100644 --- a/datamodels/2.x/itop-config/zh_cn.dict.itop-config.php +++ b/datamodels/2.x/itop-config/zh_cn.dict.itop-config.php @@ -34,4 +34,5 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array( 'config-reverted' => '配置文件已恢复.', 'config-parse-error' => '第 %2$d 行: %1$s.
配置文件尚未更新.', 'config-current-line' => '正在编辑第 %1$s 行', + 'config-saved-warning-db-password' => 'Successfully recorded, but the backup won\'t work due to unsupported characters in the database password.~~', )); diff --git a/datamodels/2.x/itop-portal-base/cs.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/cs.dict.itop-portal-base.php index 0c91ecd9e..2e353c569 100644 --- a/datamodels/2.x/itop-portal-base/cs.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/cs.dict.itop-portal-base.php @@ -40,6 +40,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array( 'Portal:Button:Delete' => 'Smazat', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentication~~', 'Error:HTTP:404' => 'Stránka nenalezena', 'Error:HTTP:500' => 'Jejda! Nastal problém', diff --git a/datamodels/2.x/itop-portal-base/da.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/da.dict.itop-portal-base.php index 7db1ef7d7..5e26c66aa 100644 --- a/datamodels/2.x/itop-portal-base/da.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/da.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array( 'Portal:Button:Delete' => 'Delete~~', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentication~~', 'Error:HTTP:404' => 'Page not found~~', 'Error:HTTP:500' => 'Oops! An error has occured.~~', diff --git a/datamodels/2.x/itop-portal-base/de.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/de.dict.itop-portal-base.php index 3a648b546..f69ec0dc7 100644 --- a/datamodels/2.x/itop-portal-base/de.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/de.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array( 'Portal:Button:Delete' => 'Löschen', 'Portal:EnvironmentBanner:Title' => 'Sie sind im Moment im %1$s Modus', 'Portal:EnvironmentBanner:GoToProduction' => 'Zurück zum PRODUCTION Modus', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentifizierung', 'Error:HTTP:404' => 'Seite nicht gefunden.', 'Error:HTTP:500' => 'Oops! Es ist ein Fehler aufgetreten.', diff --git a/datamodels/2.x/itop-portal-base/en.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/en.dict.itop-portal-base.php index 7c71b90e9..04a841502 100644 --- a/datamodels/2.x/itop-portal-base/en.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/en.dict.itop-portal-base.php @@ -38,6 +38,7 @@ Dict::Add('EN US', 'English', 'English', array( 'Portal:Button:Delete' => 'Delete', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode', + 'Error:HTTP:400' => 'Bad request', 'Error:HTTP:401' => 'Authentication', 'Error:HTTP:404' => 'Page not found', 'Error:HTTP:500' => 'Oops! An error has occured.', diff --git a/datamodels/2.x/itop-portal-base/es_cr.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/es_cr.dict.itop-portal-base.php index 762e884be..5be01e92c 100644 --- a/datamodels/2.x/itop-portal-base/es_cr.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/es_cr.dict.itop-portal-base.php @@ -36,6 +36,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array( 'Portal:Button:Delete' => 'Borrar', 'Portal:EnvironmentBanner:Title' => 'Se encuentra en modo %1$s', 'Portal:EnvironmentBanner:GoToProduction' => 'Regresar a modo PRODUCTION', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Autenticación', 'Error:HTTP:404' => 'Página no encontrada', 'Error:HTTP:500' => '¡Vaya! Ha ocurrido un error.', diff --git a/datamodels/2.x/itop-portal-base/fr.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/fr.dict.itop-portal-base.php index 1f261d196..40d9cb7ef 100644 --- a/datamodels/2.x/itop-portal-base/fr.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/fr.dict.itop-portal-base.php @@ -36,6 +36,7 @@ Dict::Add('FR FR', 'French', 'Français', array( 'Portal:Button:Delete' => 'Supprimer', 'Portal:EnvironmentBanner:Title' => 'Vous êtes dans le mode %1$s', 'Portal:EnvironmentBanner:GoToProduction' => 'Retourner au mode PRODUCTION', + 'Error:HTTP:400' => 'Requête incorrecte', 'Error:HTTP:401' => 'Authentification', 'Error:HTTP:404' => 'Page non trouvée', 'Error:HTTP:500' => 'Oups ! Une erreur est survenue.', diff --git a/datamodels/2.x/itop-portal-base/hu.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/hu.dict.itop-portal-base.php index e6cd0bcc0..463195f31 100644 --- a/datamodels/2.x/itop-portal-base/hu.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/hu.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array( 'Portal:Button:Delete' => 'Delete~~', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentication~~', 'Error:HTTP:404' => 'Page not found~~', 'Error:HTTP:500' => 'Oops! An error has occured.~~', diff --git a/datamodels/2.x/itop-portal-base/it.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/it.dict.itop-portal-base.php index 1ed8e1d45..9f86d291a 100644 --- a/datamodels/2.x/itop-portal-base/it.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/it.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array( 'Portal:Button:Delete' => 'Delete~~', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentication~~', 'Error:HTTP:404' => 'Page not found~~', 'Error:HTTP:500' => 'Oops! An error has occured.~~', diff --git a/datamodels/2.x/itop-portal-base/ja.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/ja.dict.itop-portal-base.php index d715b0098..44328bb26 100644 --- a/datamodels/2.x/itop-portal-base/ja.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/ja.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', array( 'Portal:Button:Delete' => 'Delete~~', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentication~~', 'Error:HTTP:404' => 'Page not found~~', 'Error:HTTP:500' => 'Oops! An error has occured.~~', diff --git a/datamodels/2.x/itop-portal-base/nl.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/nl.dict.itop-portal-base.php index a246d5f00..360118771 100644 --- a/datamodels/2.x/itop-portal-base/nl.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/nl.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array( 'Portal:Button:Delete' => 'Verwijderen', 'Portal:EnvironmentBanner:Title' => 'Je werkt momenteel in de %1$s-omgeving', 'Portal:EnvironmentBanner:GoToProduction' => 'Keer terug naar de productie-omgeving', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Aanmelden is vereist', 'Error:HTTP:404' => 'Pagina kan niet worden gevonden', 'Error:HTTP:500' => 'Oeps! Er is een fout opgetreden', diff --git a/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php index 8cf008288..67db6f543 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/controllers/managebrickcontroller.class.inc.php @@ -893,7 +893,7 @@ class ManageBrickController extends BrickController $aGroupingTabsValues[$aDistinctResult['grouped_by_1']] = array( 'value' => $aDistinctResult['grouped_by_1'], 'label_html' => $sHtmlLabel, - 'label' => strip_tags($sHtmlLabel), + 'label' => strip_tags(html_entity_decode($sHtmlLabel, ENT_QUOTES, 'UTF-8')), 'condition' => $oConditionQuery, 'count' => $aDistinctResult['_itop_count_'], ); diff --git a/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php b/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php index ac1c94e4f..6fda14dd9 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php +++ b/datamodels/2.x/itop-portal-base/portal/src/controllers/objectcontroller.class.inc.php @@ -1383,7 +1383,7 @@ class ObjectController extends AbstractController break; default: - $oApp->abort(403); + $oApp->abort(403, Dict::S('Error:HTTP:400')); break; } diff --git a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/user-profile/layout.html.twig b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/user-profile/layout.html.twig index 7d844c7d8..14ba83a50 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/views/bricks/user-profile/layout.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/src/views/bricks/user-profile/layout.html.twig @@ -123,7 +123,7 @@ {% else %} - {{ 'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator'|dict_s }} + {{ 'Brick:Portal:UserProfile:Password:CantChangeContactAdministrator'|dict_format(constant('ITOP_APPLICATION_SHORT')) }} {% endif %} diff --git a/datamodels/2.x/itop-portal-base/portal/web/index.php b/datamodels/2.x/itop-portal-base/portal/web/index.php index 06302e340..22f5d3148 100644 --- a/datamodels/2.x/itop-portal-base/portal/web/index.php +++ b/datamodels/2.x/itop-portal-base/portal/web/index.php @@ -93,7 +93,7 @@ $oApp->before(function(Symfony\Component\HttpFoundation\Request $oRequest, Silex $iLogonRes = LoginWebPage::DoLoginEx(PORTAL_ID, false, $iExitMethod); if( ($iExitMethod === LoginWebPage::EXIT_RETURN) && ($iLogonRes != 0) ) { - die(Dict::S('Portal:ErrorUserLoggedOut')); + $oApp->abort(401); } // - User must be associated with a Contact if (UserRights::GetContactId() == 0) diff --git a/datamodels/2.x/itop-portal-base/pt_br.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/pt_br.dict.itop-portal-base.php index 88e0d2f6c..af8806e2b 100644 --- a/datamodels/2.x/itop-portal-base/pt_br.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/pt_br.dict.itop-portal-base.php @@ -36,6 +36,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array( 'Portal:Button:Delete' => 'Deletar', 'Portal:EnvironmentBanner:Title' => 'Você está atualmente em %1$s', 'Portal:EnvironmentBanner:GoToProduction' => 'Volte para o modo PRODUÇÃO', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Autenticação', 'Error:HTTP:404' => 'Está página não existe', 'Error:HTTP:500' => 'Oops! Ocorreu um erro, informe a T.I.', diff --git a/datamodels/2.x/itop-portal-base/ru.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/ru.dict.itop-portal-base.php index 45bd75da8..03cc450a5 100755 --- a/datamodels/2.x/itop-portal-base/ru.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/ru.dict.itop-portal-base.php @@ -25,6 +25,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Portal:Button:Delete' => 'Удалить', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Ошибка аутентификации', 'Error:HTTP:404' => 'Страница не найдена', 'Error:HTTP:500' => 'Упс! Произошла ошибка.', diff --git a/datamodels/2.x/itop-portal-base/tr.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/tr.dict.itop-portal-base.php index 3c2e42f22..9380f7524 100644 --- a/datamodels/2.x/itop-portal-base/tr.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/tr.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array( 'Portal:Button:Delete' => 'Delete~~', 'Portal:EnvironmentBanner:Title' => 'You are currently in %1$s mode~~', 'Portal:EnvironmentBanner:GoToProduction' => 'Go back to PRODUCTION mode~~', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => 'Authentication~~', 'Error:HTTP:404' => 'Page not found~~', 'Error:HTTP:500' => 'Oops! An error has occured.~~', diff --git a/datamodels/2.x/itop-portal-base/zh_cn.dict.itop-portal-base.php b/datamodels/2.x/itop-portal-base/zh_cn.dict.itop-portal-base.php index c10a8fbff..928cacefe 100644 --- a/datamodels/2.x/itop-portal-base/zh_cn.dict.itop-portal-base.php +++ b/datamodels/2.x/itop-portal-base/zh_cn.dict.itop-portal-base.php @@ -37,6 +37,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array( 'Portal:Button:Delete' => '删除', 'Portal:EnvironmentBanner:Title' => '您目前处于 %1$s 模式', 'Portal:EnvironmentBanner:GoToProduction' => '回到产品模式', + 'Error:HTTP:400' => 'Bad request~~', 'Error:HTTP:401' => '认证', 'Error:HTTP:404' => '页面找不到', 'Error:HTTP:500' => 'Oops! 发生了一个错误.', diff --git a/datamodels/2.x/itop-tickets/ru.dict.itop-tickets.php b/datamodels/2.x/itop-tickets/ru.dict.itop-tickets.php index 9f9b96b14..44602cfbb 100755 --- a/datamodels/2.x/itop-tickets/ru.dict.itop-tickets.php +++ b/datamodels/2.x/itop-tickets/ru.dict.itop-tickets.php @@ -172,50 +172,50 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'WorkOrder:Moreinfo' => 'Дополнительная информация', 'Tickets:ResolvedFrom' => 'Автоматическое решение из %1$s', - 'Class:cmdbAbstractObject/Method:Set' => 'Установить', - 'Class:cmdbAbstractObject/Method:Set+' => 'Установить поле со статичным значением', - 'Class:cmdbAbstractObject/Method:Set/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:Set/Param:1+' => 'Установить поле, в текущем объекте ', - 'Class:cmdbAbstractObject/Method:Set/Param:2' => 'Значение', - 'Class:cmdbAbstractObject/Method:Set/Param:2+' => 'Установить значение', - 'Class:cmdbAbstractObject/Method:SetCurrentDate' => 'Установить текущую дату', - 'Class:cmdbAbstractObject/Method:SetCurrentDate+' => 'Установить поле с текущей датой и временем', - 'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1+' => 'Установить поле, в текущем объекте', - 'Class:cmdbAbstractObject/Method:SetCurrentUser' => 'Установитьтекущегопользователя', - 'Class:cmdbAbstractObject/Method:SetCurrentUser+' => 'Установить поле с текущим вошедшим пользователем', - 'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1+' => 'Установить поле, в текущем объекте. Если поле является строкой, тогда будет использоваться псевдоним, в противном случае будет использоваться идентификатор. Псевдонимом является имя человека, если оно связано с пользователем, в иных случаях - это логин.', - 'Class:cmdbAbstractObject/Method:SetCurrentPerson' => 'Установитьтекущуюперсону', - 'Class:cmdbAbstractObject/Method:SetCurrentPerson+' => ' Установить поле с текущим вошедшим человеком ("человек" связан с "пользователь").', - 'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1+' => 'Установить поле, в текущем объекте. Если поле является строкой, тогда будет использоваться псевдоним, в противном случае будет использоваться идентификатор. Псевдонимом является имя человека, если оно связано с пользователем, в иных случаях - это логин.', - 'Class:cmdbAbstractObject/Method:SetElapsedTime' => 'Установитьистекшеевремя', - 'Class:cmdbAbstractObject/Method:SetElapsedTime+' => 'Установить поле с временем (секунды), истекающее с даты, задданой ', - 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1+' => 'Установить поле, в текущем объекте ', - 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:2' => 'Ссылочное поле', - 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:2+' => 'Поле, откуда берется референсная дата', - 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:3' => 'Рабочие часы', - 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:3+' => 'Оставьте пустым, чтобы полагаться на стандартную схему рабочих часов, или установите значение «DefaultWorkingTimeComputer», чтобы принудительно настроить схему 24x7', - 'Class:cmdbAbstractObject/Method:Reset' => 'Сброс', - 'Class:cmdbAbstractObject/Method:Reset+' => 'Сбросить поле до его стандартного значения ', - 'Class:cmdbAbstractObject/Method:Reset/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:Reset/Param:1+' => 'Сбросить поле, в текущем объекте', - 'Class:cmdbAbstractObject/Method:Copy' => 'Копировать', - 'Class:cmdbAbstractObject/Method:Copy+' => 'Скопировать значение с поля на другое поле', - 'Class:cmdbAbstractObject/Method:Copy/Param:1' => 'Целевое поле', - 'Class:cmdbAbstractObject/Method:Copy/Param:1+' => 'Установить поле, в текущем объекте ', - 'Class:cmdbAbstractObject/Method:Copy/Param:2' => 'Исходное поле ', - 'Class:cmdbAbstractObject/Method:Copy/Param:2+' => 'Присвоить значение поля, в текущем объекте', + 'Class:cmdbAbstractObject/Method:Set' => 'Set~~', + 'Class:cmdbAbstractObject/Method:Set+' => 'Set a field with a static value~~', + 'Class:cmdbAbstractObject/Method:Set/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:Set/Param:1+' => 'The field to set, in the current object~~', + 'Class:cmdbAbstractObject/Method:Set/Param:2' => 'Value~~', + 'Class:cmdbAbstractObject/Method:Set/Param:2+' => 'The value to set~~', + 'Class:cmdbAbstractObject/Method:SetCurrentDate' => 'SetCurrentDate~~', + 'Class:cmdbAbstractObject/Method:SetCurrentDate+' => 'Set a field with the current date and time~~', + 'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:SetCurrentDate/Param:1+' => 'The field to set, in the current object~~', + 'Class:cmdbAbstractObject/Method:SetCurrentUser' => 'SetCurrentUser~~', + 'Class:cmdbAbstractObject/Method:SetCurrentUser+' => 'Set a field with the currently logged in user~~', + 'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:SetCurrentUser/Param:1+' => 'The field to set, in the current object. If the field is a string then the friendly name will be used, otherwise the identifier will be used. That friendly name is the name of the person if any is attached to the user, otherwise it is the login.~~', + 'Class:cmdbAbstractObject/Method:SetCurrentPerson' => 'SetCurrentPerson~~', + 'Class:cmdbAbstractObject/Method:SetCurrentPerson+' => 'Set a field with the currently logged in person (the "person" attached to the logged in "user").~~', + 'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:SetCurrentPerson/Param:1+' => 'The field to set, in the current object. If the field is a string then the friendly name will be used, otherwise the identifier will be used.~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime' => 'SetElapsedTime~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime+' => 'Set a field with the time (seconds) elapsed since a date given by another field~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:1+' => 'The field to set, in the current object~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:2' => 'Reference Field~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:2+' => 'The field from which to get the reference date~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:3' => 'Working Hours~~', + 'Class:cmdbAbstractObject/Method:SetElapsedTime/Param:3+' => 'Leave empty to rely on the standard working hours scheme, or set to "DefaultWorkingTimeComputer" to force a 24x7 scheme~~', + 'Class:cmdbAbstractObject/Method:Reset' => 'Reset~~', + 'Class:cmdbAbstractObject/Method:Reset+' => 'Reset a field to its default value~~', + 'Class:cmdbAbstractObject/Method:Reset/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:Reset/Param:1+' => 'The field to reset, in the current object~~', + 'Class:cmdbAbstractObject/Method:Copy' => 'Copy~~', + 'Class:cmdbAbstractObject/Method:Copy+' => 'Copy the value of a field to another field~~', + 'Class:cmdbAbstractObject/Method:Copy/Param:1' => 'Target Field~~', + 'Class:cmdbAbstractObject/Method:Copy/Param:1+' => 'The field to set, in the current object~~', + 'Class:cmdbAbstractObject/Method:Copy/Param:2' => 'Source Field~~', + 'Class:cmdbAbstractObject/Method:Copy/Param:2+' => 'The field to get the value from, in the current object~~', 'Class:cmdbAbstractObject/Method:ApplyStimulus' => 'ApplyStimulus~~', 'Class:cmdbAbstractObject/Method:ApplyStimulus+' => 'Apply the specified stimulus to the current object~~', 'Class:cmdbAbstractObject/Method:ApplyStimulus/Param:1' => 'Stimulus code~~', 'Class:cmdbAbstractObject/Method:ApplyStimulus/Param:1+' => 'A valid stimulus code for the current class~~', - 'Class:ResponseTicketTTO/Interface:iMetricComputer' => 'Время создания тикета до его назначения', - 'Class:ResponseTicketTTO/Interface:iMetricComputer+' => 'TTO Цель, основанная на SLT типа ТТО', - 'Class:ResponseTicketTTR/Interface:iMetricComputer' => 'Время решения', - 'Class:ResponseTicketTTR/Interface:iMetricComputer+' => 'Цель основанная на SLT типа TTR', + 'Class:ResponseTicketTTO/Interface:iMetricComputer' => 'Time To Own~~', + 'Class:ResponseTicketTTO/Interface:iMetricComputer+' => 'Goal based on a SLT of type TTO~~', + 'Class:ResponseTicketTTR/Interface:iMetricComputer' => 'Time To Resolve~~', + 'Class:ResponseTicketTTR/Interface:iMetricComputer+' => 'Goal based on a SLT of type TTR~~', 'portal:itop-portal' => 'Пользовательский портал', // This is the portal name that will be displayed in portal dispatcher (eg. URL in menus) 'Page:DefaultTitle' => '%1$s - Пользовательский портал', diff --git a/dictionaries/ru.dictionary.itop.core.php b/dictionaries/ru.dictionary.itop.core.php index 8649542c0..f6852ae1e 100644 --- a/dictionaries/ru.dictionary.itop.core.php +++ b/dictionaries/ru.dictionary.itop.core.php @@ -110,7 +110,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Core:AttributeOQL' => 'OQL', 'Core:AttributeOQL+' => 'Выражение языка запроса объекта (Object Query Language)', - 'Core:AttributeEnum' => 'Тип-перечисление', + 'Core:AttributeEnum' => 'Enum', 'Core:AttributeEnum+' => 'Список предопределенных тестовых строк', 'Core:AttributeTemplateString' => 'Шаблон строки', @@ -432,13 +432,13 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( // Dict::Add('RU RU', 'Russian', 'Русский', array( - 'Class:EventLoginUsage' => 'Статистика авторизаций', + 'Class:EventLoginUsage' => 'Статистика авторизаций~~', 'Class:EventLoginUsage+' => 'Connection to the application', - 'Class:EventLoginUsage/Attribute:user_id' => 'Логин', + 'Class:EventLoginUsage/Attribute:user_id' => 'Логин~~', 'Class:EventLoginUsage/Attribute:user_id+' => 'Login', - 'Class:EventLoginUsage/Attribute:contact_name' => 'Имя пользователя', + 'Class:EventLoginUsage/Attribute:contact_name' => 'Имя пользователя~~', 'Class:EventLoginUsage/Attribute:contact_name+' => 'Имя пользователя', - 'Class:EventLoginUsage/Attribute:contact_email' => 'Email пользователя', + 'Class:EventLoginUsage/Attribute:contact_email' => 'Email пользователя~~', 'Class:EventLoginUsage/Attribute:contact_email+' => 'Email Address of the User', )); @@ -678,17 +678,17 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'SynchroDataSource:Reconciliation' => 'Поиск и сопоставление', 'SynchroDataSource:Deletion' => 'Устаревание и удаление', 'SynchroDataSource:Status' => 'Статус', - 'SynchroDataSource:Information' => 'Инфо', - 'SynchroDataSource:Definition' => 'Определение', + 'SynchroDataSource:Information' => 'Инфо~~', + 'SynchroDataSource:Definition' => 'Определение~~', 'Core:SynchroAttributes' => 'Атрибуты', - 'Core:SynchroStatus' => 'Свойства', - 'Core:Synchro:ErrorsLabel' => 'Ошибки', - 'Core:Synchro:CreatedLabel' => 'Создан', - 'Core:Synchro:ModifiedLabel' => 'Изменен', - 'Core:Synchro:UnchangedLabel' => 'Неизменен', - 'Core:Synchro:ReconciledErrorsLabel' => 'Ошибки', - 'Core:Synchro:ReconciledLabel' => 'Согласован', - 'Core:Synchro:ReconciledNewLabel' => 'Создан', + 'Core:SynchroStatus' => 'Свойства~~', + 'Core:Synchro:ErrorsLabel' => 'Ошибки~~', + 'Core:Synchro:CreatedLabel' => 'Создан~~', + 'Core:Synchro:ModifiedLabel' => 'Изменен~~', + 'Core:Synchro:UnchangedLabel' => 'Неизменен~~', + 'Core:Synchro:ReconciledErrorsLabel' => 'Ошибки~~', + 'Core:Synchro:ReconciledLabel' => 'Согласован~~', + 'Core:Synchro:ReconciledNewLabel' => 'Создан~~', 'Core:SynchroReconcile:Yes' => 'Да', 'Core:SynchroReconcile:No' => 'Нет', 'Core:SynchroUpdate:Yes' => 'Да', @@ -697,70 +697,70 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Core:Synchro:History' => 'История синхронизаций', 'Core:Synchro:NeverRun' => 'Синхронизация не запускалась. Логи отсутсвуют.', 'Core:Synchro:SynchroEndedOn_Date' => 'Синхронизация была закончена в %1$s.', - 'Core:Synchro:SynchroRunningStartedOn_Date' => 'Синхронизация запущена в %1$s сейчас в процессе...', - 'Menu:DataSources' => 'Источники данных', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:DataSources+' => 'Источники синхронизируемых данных', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Core:Synchro:label_repl_ignored' => 'Игнор. (%1$s)', - 'Core:Synchro:label_repl_disappeared' => 'Невид. (%1$s)', - 'Core:Synchro:label_repl_existing' => 'Существует (%1$s)', - 'Core:Synchro:label_repl_new' => 'Новый (%1$s)', - 'Core:Synchro:label_obj_deleted' => 'Удаленный (%1$s)', - 'Core:Synchro:label_obj_obsoleted' => 'Устарел (%1$s)', - 'Core:Synchro:label_obj_disappeared_errors' => 'Ошибки (%1$s)', - 'Core:Synchro:label_obj_disappeared_no_action' => 'Нет действий (%1$s)', - 'Core:Synchro:label_obj_unchanged' => 'Неизменен (%1$s)', - 'Core:Synchro:label_obj_updated' => 'Обновлен (%1$s)', - 'Core:Synchro:label_obj_updated_errors' => 'Ошибки (%1$s)', - 'Core:Synchro:label_obj_new_unchanged' => 'Неизменен (%1$s)', - 'Core:Synchro:label_obj_new_updated' => 'Обновлен (%1$s)', - 'Core:Synchro:label_obj_created' => 'Создан (%1$s)', - 'Core:Synchro:label_obj_new_errors' => 'Ошибки (%1$s)', - 'Core:SynchroLogTitle' => '%1$s - %2$s', - 'Core:Synchro:Nb_Replica' => 'Репликация в обработке: %1$s', - 'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s', + 'Core:Synchro:SynchroRunningStartedOn_Date' => 'Синхронизация запущена в %1$s, сейчас в процессе...', + 'Menu:DataSources' => 'Synchronization Data Sources~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:DataSources+' => 'All Synchronization Data Sources~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Core:Synchro:label_repl_ignored' => 'Игнор. (%1$s)~~', + 'Core:Synchro:label_repl_disappeared' => 'Невид. (%1$s)~~', + 'Core:Synchro:label_repl_existing' => 'Existing (%1$s)~~', + 'Core:Synchro:label_repl_new' => 'Новый (%1$s)~~', + 'Core:Synchro:label_obj_deleted' => 'Удаленный (%1$s)~~', + 'Core:Synchro:label_obj_obsoleted' => 'Obsoleted (%1$s)~~', + 'Core:Synchro:label_obj_disappeared_errors' => 'Ошибки (%1$s)~~', + 'Core:Synchro:label_obj_disappeared_no_action' => 'No Action (%1$s)~~', + 'Core:Synchro:label_obj_unchanged' => 'Unchanged (%1$s)~~', + 'Core:Synchro:label_obj_updated' => 'Обновлен (%1$s)~~', + 'Core:Synchro:label_obj_updated_errors' => 'Ошибки (%1$s)~~', + 'Core:Synchro:label_obj_new_unchanged' => 'Unchanged (%1$s)~~', + 'Core:Synchro:label_obj_new_updated' => 'Обновлен (%1$s)~~', + 'Core:Synchro:label_obj_created' => 'Создан (%1$s)~~', + 'Core:Synchro:label_obj_new_errors' => 'Ошибки (%1$s)~~', + 'Core:SynchroLogTitle' => '%1$s - %2$s~~', + 'Core:Synchro:Nb_Replica' => 'Replica processed: %1$s~~', + 'Core:Synchro:Nb_Class:Objects' => '%1$s: %2$s~~', 'Class:SynchroDataSource/Error:AtLeastOneReconciliationKeyMustBeSpecified' => 'Как минимум один атрибут должен быть выбран для поиска и сопоставления объектов, либо используйте политику сопоставления по primary_key.', 'Class:SynchroDataSource/Error:DeleteRetentionDurationMustBeSpecified' => 'Срок хранения должен быть указан, поскольку объекты должны быть удалены после того, помечены как устаревшие.', 'Class:SynchroDataSource/Error:DeletePolicyUpdateMustBeSpecified' => 'Устаревшие объекты должны быть обновлены, но способ обновления не указан.', 'Class:SynchroDataSource/Error:DataTableAlreadyExists' => 'Таблица %1$s уже существует в базе данных. Пожалуйста, используйте другое имя для таблицы данных из этого источника.', - 'Core:SynchroReplica:PublicData' => 'ОбщедоступныеДанные', - 'Core:SynchroReplica:PrivateDetails' => 'ЧастныеДетали', - 'Core:SynchroReplica:BackToDataSource' => 'Возвратиться к источнику синхроданных: %1$s', - 'Core:SynchroReplica:ListOfReplicas' => 'Список репликаций', - 'Core:SynchroAttExtKey:ReconciliationById' => 'id (Первичныйключ)', + 'Core:SynchroReplica:PublicData' => 'Public Data~~', + 'Core:SynchroReplica:PrivateDetails' => 'Private Details~~', + 'Core:SynchroReplica:BackToDataSource' => 'Go Back to the Synchro Data Source: %1$s~~', + 'Core:SynchroReplica:ListOfReplicas' => 'List of Replica~~', + 'Core:SynchroAttExtKey:ReconciliationById' => 'id (Primary Key)~~', 'Core:SynchroAtt:attcode' => 'Атрибут', 'Core:SynchroAtt:attcode+' => 'Field of the object', - 'Core:SynchroAtt:reconciliation' => 'Реконсиляция ?', + 'Core:SynchroAtt:reconciliation' => 'Reconciliation ?~~', 'Core:SynchroAtt:reconciliation+' => 'Used for searching', 'Core:SynchroAtt:update' => 'Обновить?', 'Core:SynchroAtt:update+' => 'Used to update the object', - 'Core:SynchroAtt:update_policy' => 'Политика обновлений', + 'Core:SynchroAtt:update_policy' => 'Политика обновлений~~', 'Core:SynchroAtt:update_policy+' => 'Behavior of the updated field', - 'Core:SynchroAtt:reconciliation_attcode' => 'Ключ реконсиляции', + 'Core:SynchroAtt:reconciliation_attcode' => 'Reconciliation Key~~', 'Core:SynchroAtt:reconciliation_attcode+' => 'Attribute Code for the External Key Reconciliation', - 'Core:SyncDataExchangeComment' => '( Синхроданные)', - 'Core:Synchro:ListOfDataSources' => 'Список данных:', + 'Core:SyncDataExchangeComment' => '(Data Synchro)~~', + 'Core:Synchro:ListOfDataSources' => 'Список данных:~~', 'Core:Synchro:LastSynchro' => 'Последняя синхронизация:', - 'Core:Synchro:ThisObjectIsSynchronized' => 'Этот объект синхронизирован с внешним источником данных', - 'Core:Synchro:TheObjectWasCreatedBy_Source' => 'Объект был создан внешним источником данных %1$s', - 'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'Объектможет быть удален внешним источником данных %1$s', - 'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'Вы не можете удалить объект потому что он принадлежит внешнему источнику данных %1$s', - 'TitleSynchroExecution' => 'Запуск синхронизаций.', - 'Class:SynchroDataSource:DataTable' => 'Таблица: %1$s', - 'Core:SyncDataSourceObsolete' => 'Данный источник данных отмечен как устаревший. Операция отменена.', - 'Core:SyncDataSourceAccessRestriction' => 'Могут запускать только администраторы и определенные пользователи. Операция отменена.', - 'Core:SyncTooManyMissingReplicas' => ' Все записи не обрабатывались некоторое время(все объекты могли быть удалены). Убедитесь, что процесс записи в таблицу Синхронизации все еще выполняется. Операция отменена.', - 'Core:SyncSplitModeCLIOnly' => 'Синхронизация может выполняться в чанках только при запуске в режиме CLI ', - 'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s replicas, Ошибок %2$s, Предупреждений %3$s.', - 'Core:SynchroReplica:TargetObject' => 'Синхронизировано объектов: %1$s', - 'Class:AsyncSendEmail' => 'Email (несинхронизированный)', - 'Class:AsyncSendEmail/Attribute:to' => 'Кому', - 'Class:AsyncSendEmail/Attribute:subject' => 'Получатель', - 'Class:AsyncSendEmail/Attribute:body' => 'Тело', - 'Class:AsyncSendEmail/Attribute:header' => 'Заголовок', + 'Core:Synchro:ThisObjectIsSynchronized' => 'This object is synchronized with an external data source~~', + 'Core:Synchro:TheObjectWasCreatedBy_Source' => 'The object was created by the external data source %1$s~~', + 'Core:Synchro:TheObjectCanBeDeletedBy_Source' => 'The object can be deleted by the external data source %1$s~~', + 'Core:Synchro:TheObjectCannotBeDeletedByUser_Source' => 'You cannot delete the object because it is owned by the external data source %1$s~~', + 'TitleSynchroExecution' => 'Запуск синхронизаций.~~', + 'Class:SynchroDataSource:DataTable' => 'Таблица: %1$s~~', + 'Core:SyncDataSourceObsolete' => 'The data source is marked as obsolete. Operation cancelled.~~', + 'Core:SyncDataSourceAccessRestriction' => 'Могут запускать только администраторы и определенные пользователи. Операция отменена.~~', + 'Core:SyncTooManyMissingReplicas' => 'All records have been untouched for some time (all of the objects could be deleted). Please check that the process that writes into the synchronization table is still running. Operation cancelled.~~', + 'Core:SyncSplitModeCLIOnly' => 'The synchronization can be executed in chunks only if run in mode CLI~~', + 'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s replicas, Ошибок %2$s, Предупреждений %3$s.~~', + 'Core:SynchroReplica:TargetObject' => 'Синхронизировано объектов: %1$s~~', + 'Class:AsyncSendEmail' => 'Email (asynchronous)~~', + 'Class:AsyncSendEmail/Attribute:to' => 'Кому~~', + 'Class:AsyncSendEmail/Attribute:subject' => 'Получатель~~', + 'Class:AsyncSendEmail/Attribute:body' => 'Тело~~', + 'Class:AsyncSendEmail/Attribute:header' => 'Заголовок~~', 'Class:CMDBChangeOpSetAttributeOneWayPassword' => 'Шифрованный пароль', - 'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Предыдущее значение', - 'Class:CMDBChangeOpSetAttributeEncrypted' => 'Зашифрованное поле', - 'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Предыдущее значение', + 'Class:CMDBChangeOpSetAttributeOneWayPassword/Attribute:prev_pwd' => 'Предыдущее значение~~', + 'Class:CMDBChangeOpSetAttributeEncrypted' => 'Encrypted Field~~', + 'Class:CMDBChangeOpSetAttributeEncrypted/Attribute:prevstring' => 'Предыдущее значение~~', 'Class:CMDBChangeOpSetAttributeCaseLog' => 'Лог', 'Class:CMDBChangeOpSetAttributeCaseLog/Attribute:lastentry' => 'Посл.значение', 'Class:SynchroDataSource' => 'Источник синхронизации данных', @@ -786,7 +786,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Только администраторы', 'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Пользователи с правами на удаление', 'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Никто', - 'Class:SynchroAttribute' => 'Синх.характеристики', + 'Class:SynchroAttribute' => 'Синх.характеристики~~', 'Class:SynchroAttribute/Attribute:sync_source_id' => 'Синхронизация данных', 'Class:SynchroAttribute/Attribute:attcode' => 'Код атрибута', 'Class:SynchroAttribute/Attribute:update' => 'Обновить', @@ -795,13 +795,13 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Class:SynchroAttribute/Attribute:update_policy/Value:master_locked' => 'Заблокирован', 'Class:SynchroAttribute/Attribute:update_policy/Value:master_unlocked' => 'Разблокирован', 'Class:SynchroAttribute/Attribute:update_policy/Value:write_if_empty' => 'Инициализация если пусто', - 'Class:SynchroAttribute/Attribute:finalclass' => 'Класс', - 'Class:SynchroAttExtKey' => 'Синхро Атрибут (ExtKey)', + 'Class:SynchroAttribute/Attribute:finalclass' => 'Класс~~', + 'Class:SynchroAttExtKey' => 'Synchro Attribute (ExtKey)~~', 'Class:SynchroAttExtKey/Attribute:reconciliation_attcode' => 'Атрибут согласования', - 'Class:SynchroAttLinkSet' => 'Синхро Атрибут (Linkset)', + 'Class:SynchroAttLinkSet' => 'Synchro Attribute (Linkset)~~', 'Class:SynchroAttLinkSet/Attribute:row_separator' => 'Разделитель строк', 'Class:SynchroAttLinkSet/Attribute:attribute_separator' => 'Разделитель атрибутов', - 'Class:SynchroLog' => 'Synchr Журнал', + 'Class:SynchroLog' => 'Synchr Log~~', 'Class:SynchroLog/Attribute:sync_source_id' => 'Синх.исходные данные', 'Class:SynchroLog/Attribute:start_date' => 'Стартовать в', 'Class:SynchroLog/Attribute:end_date' => 'Закончить в', @@ -809,28 +809,28 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Class:SynchroLog/Attribute:status/Value:completed' => 'Завершен', 'Class:SynchroLog/Attribute:status/Value:error' => 'Ошибка', 'Class:SynchroLog/Attribute:status/Value:running' => 'Запущен', - 'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Кол-во обнаруженных репликаций ', - 'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Кол-во общих репликаций', - 'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Кол-во удаленных объектов', - 'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Кол-во ошибок во время удаления', - 'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Кол-во устаревших объектов', - 'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Кол-во ошибок при устаревании', - 'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Кол-во созданных объектов', - 'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Кол-во ошибок во время создания', - 'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Кол-во обновленных объектов', - 'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Кол-во ошибок во время обновления', - 'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Кол-во ошибок во время реконсиляции ', - 'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Кол-во исчезнувших репликаций', - 'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Кол-во обновленных объектов', - 'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Кол-во неизмененных объектов', + 'Class:SynchroLog/Attribute:stats_nb_replica_seen' => 'Nb replica seen~~', + 'Class:SynchroLog/Attribute:stats_nb_replica_total' => 'Nb replica total~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_deleted' => 'Nb objects deleted~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_deleted_errors' => 'Nb of errors while deleting~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted' => 'Nb objects obsoleted~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_obsoleted_errors' => 'Nb of errors while obsoleting~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_created' => 'Nb objects created~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_created_errors' => 'Nb or errors while creating~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_updated' => 'Nb objects updated~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_updated_errors' => 'Nb errors while updating~~', + 'Class:SynchroLog/Attribute:stats_nb_replica_reconciled_errors' => 'Nb of errors during reconciliation~~', + 'Class:SynchroLog/Attribute:stats_nb_replica_disappeared_no_action' => 'Nb replica disappeared~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_new_updated' => 'Nb objects updated~~', + 'Class:SynchroLog/Attribute:stats_nb_obj_new_unchanged' => 'Nb objects unchanged~~', 'Class:SynchroLog/Attribute:last_error' => 'Посл.ошибка', 'Class:SynchroLog/Attribute:traces' => 'Слежения', - 'Class:SynchroReplica' => 'Синхро Репликация', + 'Class:SynchroReplica' => 'Synchro Replica~~', 'Class:SynchroReplica/Attribute:sync_source_id' => 'Синх.исходные данные', 'Class:SynchroReplica/Attribute:dest_id' => 'Назначение объекта', 'Class:SynchroReplica/Attribute:dest_class' => 'Назначение типа', 'Class:SynchroReplica/Attribute:status_last_seen' => 'Был виден', - 'Class:SynchroReplica/Attribute:status' => 'Статус', + 'Class:SynchroReplica/Attribute:status' => 'Статус~~', 'Class:SynchroReplica/Attribute:status/Value:modified' => 'Изменен', 'Class:SynchroReplica/Attribute:status/Value:new' => 'Новый', 'Class:SynchroReplica/Attribute:status/Value:obsolete' => 'Устаревший', @@ -845,7 +845,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Class:appUserPreferences/Attribute:userid' => 'Пользователь', 'Class:appUserPreferences/Attribute:preferences' => 'Предпочтения', 'Core:ExecProcess:Code1' => 'Неверная команда или команда завершена с ошибкой (возможно, неверное имя скрипта)', - 'Core:ExecProcess:Code255' => 'Ошибка PHP (синтаксический разбор, или время выполнения)', + 'Core:ExecProcess:Code255' => 'Ошибка PHP (parsing, or runtime)~~', // Attribute Duration 'Core:Duration_Seconds' => '%1$d с', diff --git a/dictionaries/ru.dictionary.itop.ui.php b/dictionaries/ru.dictionary.itop.ui.php index e81392286..f9b33ec15 100644 --- a/dictionaries/ru.dictionary.itop.ui.php +++ b/dictionaries/ru.dictionary.itop.ui.php @@ -442,20 +442,20 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:History:LastModified_On_By' => 'Последнее изменение %1$s by %2$s.', 'UI:HistoryTab' => 'История', 'UI:NotificationsTab' => 'Оповещения', - 'UI:History:BulkImports' => 'История', + 'UI:History:BulkImports' => 'История~~', 'UI:History:BulkImports+' => 'List of CSV imports (latest import first)', - 'UI:History:BulkImportDetails' => 'Изменения, в результате импорта CSV, выполненого на %1$s (by %2$s)', + 'UI:History:BulkImportDetails' => 'Changes resulting from the CSV import performed on %1$s (by %2$s)~~', 'UI:History:Date' => 'Дата', 'UI:History:Date+' => 'Дата изменения', 'UI:History:User' => 'Пользователь', 'UI:History:User+' => 'Пользователь сделавший изменение', 'UI:History:Changes' => 'Изменения', 'UI:History:Changes+' => 'Изменения, внесенные в объект', - 'UI:History:StatsCreations' => 'Создан', + 'UI:History:StatsCreations' => 'Создан~~', 'UI:History:StatsCreations+' => 'Count of objects created', - 'UI:History:StatsModifs' => 'Изменен', + 'UI:History:StatsModifs' => 'Изменен~~', 'UI:History:StatsModifs+' => 'Count of objects modified', - 'UI:History:StatsDeletes' => 'Удален', + 'UI:History:StatsDeletes' => 'Удален~~', 'UI:History:StatsDeletes+' => 'Count of objects deleted', 'UI:Loading' => 'Загрузка...', 'UI:Menu:Actions' => 'Действия', @@ -470,8 +470,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:Menu:BulkDelete' => 'Удалить...', 'UI:UndefinedObject' => 'неопределённый', 'UI:Document:OpenInNewWindow:Download' => 'Открыть в новом окне: %1$s, Загрузка: %2$s', - 'UI:SplitDateTime-Date' => 'дата', - 'UI:SplitDateTime-Time' => 'время', + 'UI:SplitDateTime-Date' => 'дата~~', + 'UI:SplitDateTime-Time' => 'время~~', 'UI:TruncatedResults' => '%1$d объектов отображено из %2$d', 'UI:DisplayAll' => 'Показать всё', 'UI:CollapseList' => 'Свернуть', @@ -528,9 +528,9 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:LogOff:ClickHereToLoginAgain' => 'Нажмите здесь, чтобы снова войти...', 'UI:ChangePwdMenu' => 'Изменить пароль...', 'UI:Login:PasswordChanged' => 'Пароль успешно изменён!', - 'UI:AccessRO-All' => 'Только чтение', - 'UI:AccessRO-Users' => 'Только чтение для конечных пользователей', - 'UI:ApplicationEnvironment' => 'Среда применения: %1$s', + 'UI:AccessRO-All' => 'Только чтение~~', + 'UI:AccessRO-Users' => 'Только чтение для конечных пользователей~~', + 'UI:ApplicationEnvironment' => 'Application environment: %1$s~~', 'UI:Login:RetypePwdDoesNotMatch' => 'Пароли не совпадают', 'UI:Button:Login' => 'Войти', 'UI:Login:Error:AccessRestricted' => 'Доступ к iTop ограничен. Пожалуйста, свяжитесь с администратором iTop.', @@ -546,7 +546,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:CSVImport:idField' => 'id (Первичный ключ)', 'UI:Title:BulkImport' => 'iTop - Пакетный импорт', 'UI:Title:BulkImport+' => 'Мастер импорта CSV', - 'UI:Title:BulkSynchro_nbItem_ofClass_class' => 'Синхронизация %1$d объектов класса %2$s', + 'UI:Title:BulkSynchro_nbItem_ofClass_class' => 'Synchronization of %1$d objects of class %2$s~~', 'UI:CSVImport:ClassesSelectOne' => '-- выбрать один --', 'UI:CSVImport:ErrorExtendedAttCode' => 'Внутренняя ошибка: "%1$s" некорректный код потому, что "%2$s" НЕ являеться внешним ключом класса "%3$s"', 'UI:CSVImport:ObjectsWillStayUnchanged' => '%1$d объект(ы) останеться неизменным.', @@ -597,31 +597,31 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:UniversalSearch:Error' => 'Ошибка: %1$s', 'UI:UniversalSearch:LabelSelectTheClass' => 'Выбор класса для поиска: ', - 'UI:CSVReport-Value-Modified' => 'Изменен', - 'UI:CSVReport-Value-SetIssue' => 'Не может быть изменен - причина: %1$s', - 'UI:CSVReport-Value-ChangeIssue' => 'Не может быть изменен %1$s - причина: %2$s', + 'UI:CSVReport-Value-Modified' => 'Изменен~~', + 'UI:CSVReport-Value-SetIssue' => 'Не может быть изменен - причина: %1$s~~', + 'UI:CSVReport-Value-ChangeIssue' => 'Не может быть изменен %1$s - причина: %2$s~~', 'UI:CSVReport-Value-NoMatch' => 'Нет совпадений', 'UI:CSVReport-Value-Missing' => 'Отсутствует обязательное значение', - 'UI:CSVReport-Value-Ambiguous' => 'Неопределенный: найдено %1$s объектов', + 'UI:CSVReport-Value-Ambiguous' => 'Ambiguous: найдено %1$s объектов~~', 'UI:CSVReport-Row-Unchanged' => 'без изменений', 'UI:CSVReport-Row-Created' => 'созданный', - 'UI:CSVReport-Row-Updated' => 'обновлено %1$d cols', - 'UI:CSVReport-Row-Disappeared' => 'исчез, заменен %1$d cols', - 'UI:CSVReport-Row-Issue' => 'Проблема: %1$s', - 'UI:CSVReport-Value-Issue-Null' => 'Поле не должно быть пустым', - 'UI:CSVReport-Value-Issue-NotFound' => 'Не найден', - 'UI:CSVReport-Value-Issue-FoundMany' => 'Найдено %1$d значений', - 'UI:CSVReport-Value-Issue-Readonly' => 'Аттрибут \'%1$s\' доступен только для чтения и не может быть изменен (ткущее значение: %2$s, предложенное значение: %3$s)', - 'UI:CSVReport-Value-Issue-Format' => 'Не удалось обработать запрос: %1$s', + 'UI:CSVReport-Row-Updated' => 'updated %1$d cols~~', + 'UI:CSVReport-Row-Disappeared' => 'disappeared, changed %1$d cols~~', + 'UI:CSVReport-Row-Issue' => 'Issue: %1$s~~', + 'UI:CSVReport-Value-Issue-Null' => 'Поле не должно быть пустым~~', + 'UI:CSVReport-Value-Issue-NotFound' => 'Не найден~~', + 'UI:CSVReport-Value-Issue-FoundMany' => 'Найдено %1$d значений~~', + 'UI:CSVReport-Value-Issue-Readonly' => 'Аттрибут \'%1$s\' доступен только для чтения и не может быть изменен (ткущее значение: %2$s, предложенное значение: %3$s)~~', + 'UI:CSVReport-Value-Issue-Format' => 'Не удалось обработать запрос: %1$s~~', 'UI:CSVReport-Value-Issue-NoMatch' => 'Неизвестное значение атрибута \'%1$s\': ничего не найдено, проверьте правильность ввода', - 'UI:CSVReport-Value-Issue-Unknown' => 'Неизвестное значение атрибута \'%1$s\': %2$s', - 'UI:CSVReport-Row-Issue-Inconsistent' => 'Несоответствие атрибутов: %1$s', - 'UI:CSVReport-Row-Issue-Attribute' => 'Неизвестное значение(я) атрибута', - 'UI:CSVReport-Row-Issue-MissingExtKey' => 'Не может быть создан так как отсутсвует внешний ключ(и): %1$s', - 'UI:CSVReport-Row-Issue-DateFormat' => 'Формат даты неверен', + 'UI:CSVReport-Value-Issue-Unknown' => 'Неизвестное значение атрибута \'%1$s\': %2$s~~', + 'UI:CSVReport-Row-Issue-Inconsistent' => 'Несоответствие атрибутов: %1$s~~', + 'UI:CSVReport-Row-Issue-Attribute' => 'Неизвестное значение(я) атрибута~~', + 'UI:CSVReport-Row-Issue-MissingExtKey' => 'Не может быть создан так как отсутсвует внешний ключ(и): %1$s~~', + 'UI:CSVReport-Row-Issue-DateFormat' => 'Формат даты неверен~~', 'UI:CSVReport-Row-Issue-Reconciliation' => 'Невозможно согласовать', 'UI:CSVReport-Row-Issue-Ambiguous' => 'Согласование спорное', - 'UI:CSVReport-Row-Issue-Internal' => 'Внутренняя ошибка: %1$s, %2$s', + 'UI:CSVReport-Row-Issue-Internal' => 'Внутренняя ошибка: %1$s, %2$s~~', 'UI:CSVReport-Icon-Unchanged' => 'Неизмен.', 'UI:CSVReport-Icon-Modified' => 'Измен.', @@ -629,11 +629,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:CSVReport-Object-MissingToUpdate' => 'Отсутствующий объект: будет обновлен', 'UI:CSVReport-Object-MissingUpdated' => 'Отсутствующий объект: обновлен', 'UI:CSVReport-Icon-Created' => 'Создан', - 'UI:CSVReport-Object-ToCreate' => 'Был создан объект', - 'UI:CSVReport-Object-Created' => 'Объект создан', - 'UI:CSVReport-Icon-Error' => 'Ошибка', - 'UI:CSVReport-Object-Error' => 'ОШИБКА: %1$s', - 'UI:CSVReport-Object-Ambiguous' => 'Двусмыслен.: %1$s', + 'UI:CSVReport-Object-ToCreate' => 'Был создан объект~~', + 'UI:CSVReport-Object-Created' => 'Объект создан~~', + 'UI:CSVReport-Icon-Error' => 'Ошибка~~', + 'UI:CSVReport-Object-Error' => 'ОШИБКА: %1$s~~', + 'UI:CSVReport-Object-Ambiguous' => 'Двусмыслен.: %1$s~~', 'UI:CSVReport-Stats-Errors' => '%1$.0f %% загруженных объектов имеют ошибки. Проигнорированы.', 'UI:CSVReport-Stats-Created' => '%1$.0f %% загруженных объектов были созданы.', 'UI:CSVReport-Stats-Modified' => '%1$.0f %% загруженных объектов были изменены.', @@ -649,8 +649,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:Audit:HeaderNbObjects' => '# Объекты', 'UI:Audit:HeaderNbErrors' => '# Ошибки', 'UI:Audit:PercentageOk' => '% Ok', - 'UI:Audit:ErrorIn_Rule_Reason' => 'OQL ошибка в правиле %1$s: %2$s.', - 'UI:Audit:ErrorIn_Category_Reason' => 'OQL ошибка в категории %1$s: %2$s.', + 'UI:Audit:ErrorIn_Rule_Reason' => 'OQL ошибка в правиле %1$s: %2$s.~~', + 'UI:Audit:ErrorIn_Category_Reason' => 'OQL ошибка в категории %1$s: %2$s.~~', 'UI:RunQuery:Title' => 'iTop - Оценка запросов OQL', 'UI:RunQuery:QueryExamples' => 'Примеры запросов', @@ -663,7 +663,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:RunQuery:DevelopedQuery' => 'Переработанное выражение запроса: ', 'UI:RunQuery:SerializedFilter' => 'Сериализованные фильты: ', 'UI:RunQuery:Error' => 'Ошибка при выполнении запроса: %1$s', - 'UI:Query:UrlForExcel' => 'URL использовать для веб-запросов MS-Excel ', + 'UI:Query:UrlForExcel' => 'URL to use for MS-Excel web queries~~', 'UI:Query:UrlV1' => 'The list of fields has been left unspecified. The page export-V2.php cannot be invoked without this information. Therefore, the URL suggested here below points to the legacy page: export.php. This legacy version of the export has the following limitation: the list of exported fields may vary depending on the output format and the data model of iTop.
Should you want to garantee that the list of exported columns will remain stable on the long run, then you must specify a value for the attribute "Fields" and use the page export-V2.php.', 'UI:Schema:Title' => 'iTop схема объектов', 'UI:Schema:CategoryMenuItem' => 'Категория %1$s', @@ -754,9 +754,9 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:Error:NotEnoughRightsToDelete' => 'Этот объект не может быть удален, потому что текущий пользователь не имеет достаточных прав', 'UI:Error:CannotDeleteBecause' => 'This object could not be deleted because: %1$s', 'UI:Error:CannotDeleteBecauseOfDepencies' => 'Этот объект не может быть удален, потому что некоторые ручные операции должны быть выполнены до этого', - 'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'Объект невозможно удалить, необходимо применить действия вручную перед удалением', + 'UI:Error:CannotDeleteBecauseManualOpNeeded' => 'This object could not be deleted because some manual operations must be performed prior to that~~', 'UI:Archive_User_OnBehalfOf_User' => '%1$s от имени %2$s', - 'UI:Delete:Deleted' => 'удален', + 'UI:Delete:Deleted' => 'удален~~', 'UI:Delete:AutomaticallyDeleted' => 'автоматически удалён', 'UI:Delete:AutomaticResetOf_Fields' => 'автоматически сброшено поле(я): %1$s', 'UI:Delete:CleaningUpRefencesTo_Object' => 'Очищенны все ссылки(связи?) на %1$s...', @@ -765,9 +765,9 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:Delete:_Name_Class_Deleted' => '%1$s - %2$s удалено.', 'UI:Delete:ConfirmDeletionOf_Name' => 'Удаление %1$s', 'UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class' => 'Удаление %1$d объектов класса %2$s', - 'UI:Delete:CannotDeleteBecause' => 'Не смог удалить: %1$s', - 'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Должно удаляться автоматически, но это неполнимо: %1$s', - 'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Должно удаляться вручную, но это невыполнимо: %1$s', + 'UI:Delete:CannotDeleteBecause' => 'Could not be deleted: %1$s~~', + 'UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible' => 'Should be automaticaly deleted, but this is not feasible: %1$s~~', + 'UI:Delete:MustBeDeletedManuallyButNotPossible' => 'Must be deleted manually, but this is not feasible: %1$s~~', 'UI:Delete:WillBeDeletedAutomatically' => 'Будет удалено автоматически', 'UI:Delete:MustBeDeletedManually' => 'Необходимо удалить вручную', 'UI:Delete:CannotUpdateBecause_Issue' => 'Должно быть автоматически обновлено, но: %1$s', @@ -924,11 +924,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:NotificationsMenu:Title' => 'Конфигурация Уведомлений', 'UI:NotificationsMenu:Help' => 'Помощь', 'UI:NotificationsMenu:HelpContent' => '

В iTop уведомления полностью настраиваемые. Они основаны на двух наборах объектов: триггеры и действия.

-

Триггеры оперделяют когда уведомление будет выполнено. Есть 3 типа триггеров обробатывающих 3 разных фазы жизненного цикла объекта: +

Triggers define when a notification will be executed. There are different triggers as part of iTop core, but others can be brought by extensions:

    -
  1. "OnCreate" триггеры сработают когда объект заданного класса будет создан
  2. -
  3. "OnStateEnter" триггеры сработают перед тем как объект заданного класса войдёт в заданное состояние (выйдет из другого состояния)
  4. -
  5. "OnStateLeave" триггеры сработают когда объекты заданного класса выйдут из заданного состояния
  6. +
  7. Some triggers are executed when an object of the specified class is created, updated or deleted.
  8. +
  9. Some triggers are executed when an object of a given class enter or leave a specified state.
  10. +
  11. Some triggers are executed when a threshold on TTO or TTR has been reached.

@@ -937,7 +937,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(

Специальная страница: email.test.php доступна для тестирования и устранения неполадок в настройках почты.

Чтобы быть выполненными, действия необходимо ассоциировать с триггерами. -При ассоциации с триггером, каждое действие получает "порядковый" номер, который определяет порядок выполнения действий.

', +При ассоциации с триггером, каждое действие получает "порядковый" номер, который определяет порядок выполнения действий.

~~', 'UI:NotificationsMenu:Triggers' => 'Триггеры', 'UI:NotificationsMenu:AvailableTriggers' => 'Доступные триггеры', 'UI:NotificationsMenu:OnCreate' => 'При создании объекта', @@ -952,32 +952,32 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:TagAdminMenu:NoTags' => 'Не настроены поля тегов', 'UI:TagSetFieldData:Error' => 'Ошибка: %1$s', - 'Menu:AuditCategories' => 'Категории аудита', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:AuditCategories+' => 'Категории аудита', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:Notifications:Title' => 'Категории аудита', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:AuditCategories' => 'Audit Categories~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:AuditCategories+' => 'Audit Categories~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:Notifications:Title' => 'Audit Categories~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:RunQueriesMenu' => 'Выполнение запросов', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:RunQueriesMenu+' => 'Выполнение любых запросов', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:RunQueriesMenu' => 'Run Queries~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:RunQueriesMenu+' => 'Run any query~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:QueryMenu' => 'Книга запросов', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:QueryMenu+' => 'Книга запросов', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:QueryMenu' => 'Query phrasebook~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:QueryMenu+' => 'Query phrasebook~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:DataAdministration' => 'Администрирование данных', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:DataAdministration+' => 'Администрирование данных', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:DataAdministration' => 'Data administration~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:DataAdministration+' => 'Data administration~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UniversalSearchMenu' => 'Универсальный поиск', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UniversalSearchMenu+' => 'Поиск чего угодно...', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UniversalSearchMenu' => 'Universal Search~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UniversalSearchMenu+' => 'Search for anything...~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UserManagementMenu' => 'Управление пользователями', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UserManagementMenu+' => 'Управление пользователями', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UserManagementMenu' => 'User Management~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UserManagementMenu+' => 'User management~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:ProfilesMenu' => 'Профили пользователей', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:ProfilesMenu+' => 'Профили пользователей', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:ProfilesMenu:Title' => 'Профили пользователей', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:ProfilesMenu' => 'Profiles~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:ProfilesMenu+' => 'Profiles~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:ProfilesMenu:Title' => 'Profiles~~', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UserAccountsMenu' => 'Учетные записи пользователей', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UserAccountsMenu+' => 'Учетные записи пользователей', // Duplicated into itop-welcome-itil (will be removed from here...) - 'Menu:UserAccountsMenu:Title' => 'Учетные записи пользователей', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UserAccountsMenu' => 'User Accounts~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UserAccountsMenu+' => 'User Accounts~~', // Duplicated into itop-welcome-itil (will be removed from here...) + 'Menu:UserAccountsMenu:Title' => 'User Accounts~~', // Duplicated into itop-welcome-itil (will be removed from here...) 'UI:iTopVersion:Short' => '%1$s версия %2$s', 'UI:iTopVersion:Long' => '%1$s версия %2$s-%3$s основан на %4$s', @@ -986,7 +986,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:OpenDocumentInNewWindow_' => 'Открыть этот документ в новом окне: %1$s', 'UI:DownloadDocument_' => 'Скачать этот документ: %1$s', 'UI:Document:NoPreview' => 'Предварительный просмотр недоступен для документов данного типа', - 'UI:Download-CSV' => 'Загрузка %1$s', + 'UI:Download-CSV' => 'Загрузка %1$s~~', 'UI:DeadlineMissedBy_duration' => 'Пропущен %1$s', 'UI:Deadline_LessThan1Min' => '< 1 мин', @@ -1061,13 +1061,13 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Portal:Attachments' => 'Вложения', 'Portal:AddAttachment' => 'Добавить вложения', 'Portal:RemoveAttachment' => ' Удалить вложения', - 'Portal:Attachment_No_To_Ticket_Name' => 'Вложение #%1$d to %2$s (%3$s)', - 'Portal:SelectRequestTemplate' => 'Выберите шаблон для %1$s', + 'Portal:Attachment_No_To_Ticket_Name' => 'Вложение #%1$d to %2$s (%3$s)~~', + 'Portal:SelectRequestTemplate' => 'Select a template for %1$s~~', 'Enum:Undefined' => 'Неопределён', 'UI:DurationForm_Days_Hours_Minutes_Seconds' => '%1$s д %2$s ч %3$s мин %4$s с', 'UI:ModifyAllPageTitle' => 'Изменить все', - 'UI:Modify_N_ObjectsOf_Class' => 'Изменение %1$d объектов класса %2$s', - 'UI:Modify_M_ObjectsOf_Class_OutOf_N' => 'Изменение %1$d объектов класса %2$s из %3$d', + 'UI:Modify_N_ObjectsOf_Class' => 'Изменение %1$d объектов класса %2$s~~', + 'UI:Modify_M_ObjectsOf_Class_OutOf_N' => 'Изменение %1$d объектов класса %2$s из %3$d~~', 'UI:Menu:ModifyAll' => 'Изменить...', 'UI:Button:ModifyAll' => 'Изменить все', 'UI:Button:PreviewModifications' => 'Предпросмотр изменений >>', @@ -1080,30 +1080,30 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:BulkModifyStatusError' => 'Ошибка', 'UI:BulkModifyStatusModified' => 'Изменен', 'UI:BulkModifyStatusSkipped' => 'Пропущен', - 'UI:BulkModify_Count_DistinctValues' => '%1$d Различные значения:', - 'UI:BulkModify:Value_Exists_N_Times' => '%1$s, %2$d время(s)', - 'UI:BulkModify:N_MoreValues' => '%1$d больше значений...', - 'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Попытка установить поле только для чтения: %1$s', + 'UI:BulkModify_Count_DistinctValues' => '%1$d distinct values:~~', + 'UI:BulkModify:Value_Exists_N_Times' => '%1$s, %2$d time(s)~~', + 'UI:BulkModify:N_MoreValues' => '%1$d more values...~~', + 'UI:AttemptingToSetAReadOnlyAttribute_Name' => 'Attempting to set the read-only field: %1$s~~', 'UI:FailedToApplyStimuli' => 'Операция не может быть выполнена.', - 'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: Модификация %2$d объектов класса %3$s', + 'UI:StimulusModify_N_ObjectsOf_Class' => '%1$s: Modifying %2$d objects of class %3$s~~', 'UI:CaseLogTypeYourTextHere' => 'Введите свой текст:', - 'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:', - 'UI:CaseLog:InitialValue' => 'Первоначальное значение:', - 'UI:AttemptingToSetASlaveAttribute_Name' => 'Поле %1$s недоступно для записи, поскольку оно контролируется синхронизацией данных. Значение не установлено.', - 'UI:ActionNotAllowed' => 'Вы не можете выполнять это действие на этих объектах.', - 'UI:BulkAction:NoObjectSelected' => 'Пожалуйста, выберите хотя бы один объект для выполнения этой операции', - 'UI:AttemptingToChangeASlaveAttribute_Name' => 'Поле %1$s недоступно для записи, поскольку оно контролируется синхронизацией данных. Значение остается неизменным.', + 'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:~~', + 'UI:CaseLog:InitialValue' => 'Initial value:~~', + 'UI:AttemptingToSetASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value not set.~~', + 'UI:ActionNotAllowed' => 'You are not allowed to perform this action on these objects.~~', + 'UI:BulkAction:NoObjectSelected' => 'Please select at least one object to perform this operation~~', + 'UI:AttemptingToChangeASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value remains unchanged.~~', 'UI:Pagination:HeaderSelection' => 'Всего: %1$s элементов (%2$s элементов выделено).', 'UI:Pagination:HeaderNoSelection' => 'Всего: %1$s элементов', 'UI:Pagination:PageSize' => '%1$s объектов на страницу', - 'UI:Pagination:PagesLabel' => 'Страницы:', + 'UI:Pagination:PagesLabel' => 'Страницы:~~', 'UI:Pagination:All' => 'Все', - 'UI:HierarchyOf_Class' => 'Иерархия по: %1$s', - 'UI:Preferences' => 'Дополнительно...', - 'UI:ArchiveModeOn' => 'Активировать архивный режим ', - 'UI:ArchiveModeOff' => 'Деактивировать архивный режим ', - 'UI:ArchiveMode:Banner' => 'Архивный режим', - 'UI:ArchiveMode:Banner+' => 'Архивные объекты видны, и не разрешены никакие изменения ', + 'UI:HierarchyOf_Class' => 'Иерархия по: %1$s~~', + 'UI:Preferences' => 'Предпочтения...', + 'UI:ArchiveModeOn' => 'Activate archive mode~~', + 'UI:ArchiveModeOff' => 'Deactivate archive mode~~', + 'UI:ArchiveMode:Banner' => 'Archive mode~~', + 'UI:ArchiveMode:Banner+' => 'Archived objects are visible, and no modification is allowed~~', 'UI:FavoriteOrganizations' => 'Избранные организации', 'UI:FavoriteOrganizations+' => 'Отметьте в списке ниже организации, которые вы хотите видеть в раскрывающемся списке бокового меню для быстрого доступа. Обратите внимание, что это не параметр безопасности, объекты из любой организации по-прежнему видны и могут быть доступны, выбрав "Все организации" в раскрывающемся списке.', 'UI:FavoriteLanguage' => 'Язык пользовательского интерфейса', @@ -1115,8 +1115,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:NavigateAwayConfirmationMessage' => 'Все изменения будут отменены.', 'UI:CancelConfirmationMessage' => 'Настройки НЕ будут сохранены. Продолжить?', 'UI:AutoApplyConfirmationMessage' => 'Некоторые изменения не вступили в силу. Применить их немедленно?', - 'UI:Create_Class_InState' => 'Создайте %1$s в состоянии: ', - 'UI:OrderByHint_Values' => 'Порядок сортировки: %1$s', + 'UI:Create_Class_InState' => 'Create the %1$s in state: ~~', + 'UI:OrderByHint_Values' => 'Sort order: %1$s~~', 'UI:Menu:AddToDashboard' => 'Добавить на дашборд...', 'UI:Button:Refresh' => 'Обновить', 'UI:Button:GoPrint' => 'Печать...', @@ -1144,8 +1144,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:Button:MoveUp' => 'Вверх', 'UI:Button:MoveDown' => 'Вниз', - 'UI:OQL:UnknownClassAndFix' => 'Неизвестный класс"%1$s". You may try "%2$s" instead.', - 'UI:OQL:UnknownClassNoFix' => 'Неизвестный класс "%1$s"', + 'UI:OQL:UnknownClassAndFix' => 'Unknown class "%1$s". You may try "%2$s" instead.~~', + 'UI:OQL:UnknownClassNoFix' => 'Unknown class "%1$s"~~', 'UI:Dashboard:Edit' => 'Редактировать дашборд...', 'UI:Dashboard:Revert' => 'Вернуть оригинальную версию...', @@ -1202,14 +1202,14 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'UI:DashletGroupBy:Prop-Query' => 'Запрос', 'UI:DashletGroupBy:Prop-Style' => 'Стиль', 'UI:DashletGroupBy:Prop-GroupBy' => 'Группировка', - 'UI:DashletGroupBy:Prop-GroupBy:Hour' => 'Час %1$s (0-23)', - 'UI:DashletGroupBy:Prop-GroupBy:Month' => 'Месяц %1$s (1 - 12)', - 'UI:DashletGroupBy:Prop-GroupBy:DayOfWeek' => 'День недели для%1$s', - 'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'День месяца для %1$s', - 'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (час)', - 'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (месяц)', - 'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (день недели)', - 'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (день месяца)', + 'UI:DashletGroupBy:Prop-GroupBy:Hour' => 'Hour of %1$s (0-23)~~', + 'UI:DashletGroupBy:Prop-GroupBy:Month' => 'Month of %1$s (1 - 12)~~', + 'UI:DashletGroupBy:Prop-GroupBy:DayOfWeek' => 'Day of week for %1$s~~', + 'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'Day of month for %1$s~~', + 'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (hour)~~', + 'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (month)~~', + 'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (day of week)~~', + 'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (day of month)~~', 'UI:DashletGroupBy:MissingGroupBy' => 'Пожалуйста, выберите поле по которому объекты будут сгруппированы', 'UI:DashletGroupByPie:Label' => 'Круговая диаграмма', @@ -1242,7 +1242,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( // --- 'UI:DashletHeaderStatic:Label' => 'Заголовок', - 'UI:DashletHeaderStatic:Description' => 'Отображает горизонтальный разделитель', + 'UI:DashletHeaderStatic:Description' => 'Displays an horizontal separator~~', 'UI:DashletHeaderStatic:Prop-Title' => 'Заголовок', 'UI:DashletHeaderStatic:Prop-Title:Default' => 'Контакты', 'UI:DashletHeaderStatic:Prop-Icon' => 'Иконка', @@ -1313,7 +1313,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array( 'Class:Shortcut+' => '', 'Class:Shortcut/Attribute:name' => 'Название', 'Class:Shortcut/Attribute:name+' => 'Используется в меню и заголовке страницы', - 'Class:ShortcutOQL' => 'Ярлык результата поиска', + 'Class:ShortcutOQL' => 'Search result shortcut~~', 'Class:ShortcutOQL+' => '', 'Class:ShortcutOQL/Attribute:oql' => 'Запрос', 'Class:ShortcutOQL/Attribute:oql+' => 'OQL defining the list of objects to search for', diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index 0716386dc..4b3b18944 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -1160,19 +1160,9 @@ EOF $aUniquenessRules[$sCurrentRuleId]['disabled'] = $this->GetPropBooleanConverted($oUniquenessSingleRule, 'disabled', null); $aUniquenessRules[$sCurrentRuleId]['is_blocking'] = $this->GetPropBooleanConverted($oUniquenessSingleRule, 'is_blocking', null); - - try - { - // we're just checking all mandatory fields are present right now - // we will check for rule overrides validity later (see \MetaModel::InitClasses) - MetaModel::CheckUniquenessRuleValidity($aUniquenessRules[$sCurrentRuleId], true); - } - catch (CoreUnexpectedValue $e) - { - throw(new DOMFormatException("Invalid uniqueness rule declaration : class={$oClass->getAttribute('id')}, rule=$sCurrentRuleId, reason={$e->getMessage()}")); - } } + // we will check for rules validity later as for now we don't have objects hierarchy (see \MetaModel::InitClasses) $aClassParams['uniqueness_rules'] = var_export($aUniquenessRules, true); } diff --git a/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php b/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php index 22c34a6f0..423f5b94a 100644 --- a/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php +++ b/sources/renderer/bootstrap/fieldrenderer/bsfileuploadfieldrenderer.class.inc.php @@ -24,6 +24,7 @@ use Dict; use InlineImage; use DBObjectSet; use DBObjectSearch; +use AttachmentPlugIn; use Combodo\iTop\Renderer\FieldRenderer; use Combodo\iTop\Renderer\RenderingOutput; @@ -89,6 +90,10 @@ class BsFileUploadFieldRenderer extends FieldRenderer $oOutput->AddHtml(''); // JS for file upload + $iMaxUploadInBytes = AttachmentPlugIn::GetMaxUploadSize(); + $sMaxUploadLabel = AttachmentPlugIn::GetMaxUpload(); + $sFileTooBigLabel = Dict::Format('Attachments:Error:FileTooLarge', $sMaxUploadLabel); + $sFileTooBigLabelForJS = addslashes($sFileTooBigLabel); // Note : This is based on itop-attachement/main.attachments.php $oOutput->AddJs( << $iMaxUploadInBytes) + { + alert('$sFileTooBigLabelForJS'); + return false; + } + }, start: function() { // Scrolling to dropzone so the user can see that attachments are uploaded $(this)[0].scrollIntoView(); diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php index 1969285b5..1a23df7d7 100644 --- a/synchro/synchrodatasource.class.inc.php +++ b/synchro/synchrodatasource.class.inc.php @@ -2480,18 +2480,7 @@ class SynchroExecution // if ($this->m_oLastFullLoadStartDate == null) { - // No previous import known, use the full_load_periodicity value... and the current date - $this->m_oLastFullLoadStartDate = new DateTime(); // Now - $iLoadPeriodicity = $this->m_oDataSource->Get('full_load_periodicity'); // Duration in seconds - if ($iLoadPeriodicity > 0) - { - $sInterval = "-$iLoadPeriodicity seconds"; - $this->m_oLastFullLoadStartDate->Modify($sInterval); - } - else - { - $this->m_oLastFullLoadStartDate = new DateTime('1970-01-01'); - } + $this->m_oLastFullLoadStartDate = new DateTime('1970-01-01'); } if ($bFirstPass) { @@ -2712,13 +2701,21 @@ class SynchroExecution protected function DoJob1($iMaxReplica = null, $iCurrPos = -1) { $this->m_oStatLog->AddTrace(">>> Beginning of DoJob1(\$iMaxReplica = $iMaxReplica, \$iCurrPos = $iCurrPos)"); - $sLimitDate = $this->m_oLastFullLoadStartDate->Format('Y-m-d H:i:s'); + $sLastFullLoadStartDate = $this->m_oLastFullLoadStartDate->Format('Y-m-d H:i:s'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); // Get all the replicas that were not seen in the last import and mark them as obsolete $sDeletePolicy = $this->m_oDataSource->Get('delete_policy'); if ($sDeletePolicy != 'ignore') { + $oLimitDate = clone($this->m_oLastFullLoadStartDate); + $iLoadPeriodicity = $this->m_oDataSource->Get('full_load_periodicity'); // Duration in seconds + if ($iLoadPeriodicity > 0) + { + $sInterval = "-$iLoadPeriodicity seconds"; + $oLimitDate->Modify($sInterval); + } + $sLimitDate = $oLimitDate->Format('Y-m-d H:i:s'); $sSelectToObsolete = "SELECT SynchroReplica WHERE id > :curr_pos AND sync_source_id = :source_id AND status IN ('new', 'synchronized', 'modified', 'orphan') AND status_last_seen < :last_import"; $oSetScope = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToObsolete), array() /* order by*/, array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sLimitDate, 'curr_pos' => $iCurrPos)); $iCountScope = $oSetScope->Count(); @@ -2801,7 +2798,7 @@ class SynchroExecution //Count "seen" objects $sSelectSeen = "SELECT SynchroReplica WHERE sync_source_id = :source_id AND status IN ('new', 'synchronized', 'modified', 'orphan') AND status_last_seen >= :last_import"; - $oSetSeen = new DBObjectSet(DBObjectSearch::FromOQL($sSelectSeen), array() /* order by*/, array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sLimitDate)); + $oSetSeen = new DBObjectSet(DBObjectSearch::FromOQL($sSelectSeen), array() /* order by*/, array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sLastFullLoadStartDate)); $this->m_oStatLog->Set('stats_nb_replica_seen', $oSetSeen->Count());