diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 8ba2b804a..6e38c5ad2 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1570,10 +1570,6 @@ class Config { $aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aModuleInfo['webservice'])); } - if (isset($aModuleInfo['dictionary'])) - { - $aDictionaries = array_unique(array_merge($aDictionaries, $aModuleInfo['dictionary'])); - } if (isset($aModuleInfo['settings'])) { list($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId); @@ -1609,6 +1605,17 @@ class Config $this->SetAppModules($aAppModules); $this->SetDataModels($aDataModels); $this->SetWebServiceCategories($aWebServiceCategories); + + // Scan dictionaries + // + if (!is_null($sModulesDir)) + { + foreach(glob(APPROOT.$sModulesDir.'/dictionaries/*.dict.php') as $sFilePath) + { + $sFile = basename($sFilePath); + $aDictionaries[] = $sModulesDir.'/dictionaries/'.$sFile; + } + } $this->SetDictionaries($aDictionaries); } } diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index 30c095c2c..1d6f7703b 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -257,7 +257,21 @@ EOF; { $this->Log("Compilation of module $sModuleName in version $sModuleVersion produced not code at all. No file written."); } - + } // foreach module + + // Compile the dictionaries -out of the modules + // + $sDictDir = $sTargetDir.'/dictionaries'; + if (!is_dir($sDictDir)) + { + $this->Log("Creating directory $sDictDir"); + mkdir($sDictDir, 0777, true); + } + + $oDictionaries = $this->oFactory->ListActiveChildNodes('dictionaries', 'dictionary'); + foreach($oDictionaries as $oDictionaryNode) + { + $this->CompileDictionary($oDictionaryNode, $sTargetDir); } } @@ -451,10 +465,18 @@ EOF; /** * Adds quotes and escape characters */ - protected function QuoteForPHP($sStr) + protected function QuoteForPHP($sStr, $bSimpleQuotes = false) { - $sEscaped = str_replace(array('\\', '"', "\n"), array('\\\\', '\\"', '\\n'), $sStr); - $sRet = '"'.$sEscaped.'"'; + if ($bSimpleQuotes) + { + $sEscaped = str_replace(array('\\', "'"), array('\\\\', "\\'"), $sStr); + $sRet = "'$sEscaped'"; + } + else + { + $sEscaped = str_replace(array('\\', '"', "\n"), array('\\\\', '\\"', '\\n'), $sStr); + $sRet = '"'.$sEscaped.'"'; + } return $sRet; } @@ -1408,8 +1430,38 @@ EOF; return $sPHP; } // function CompileUserRights + protected function CompileDictionary($oDictionaryNode, $sTargetDir) + { + $sLang = $oDictionaryNode->getAttribute('id'); + $sEnglishLanguageDesc = $oDictionaryNode->GetChildText('english_description'); + $sLocalizedLanguageDesc = $oDictionaryNode->GetChildText('localized_description'); + + $aEntriesPHP = array(); + $oEntries = $oDictionaryNode->GetUniqueElement('entries'); + foreach($oEntries->getElementsByTagName('entry') as $oEntry) + { + $sStringCode = $oEntry->getAttribute('id'); + $sValue = $oEntry->GetText(); + $aEntriesPHP[] = "\t'$sStringCode' => ".self::QuoteForPHP($sValue, true).","; + } + $sEntriesPHP = implode("\n", $aEntriesPHP); + + $sEscEnglishLanguageDesc = self::QuoteForPHP($sEnglishLanguageDesc); + $sEscLocalizedLanguageDesc = self::QuoteForPHP($sLocalizedLanguageDesc); + $sPHPDict = +<< +?> \ No newline at end of file diff --git a/setup/modelfactory.class.inc.php b/setup/modelfactory.class.inc.php index 850c63cb6..0fe46b23a 100644 --- a/setup/modelfactory.class.inc.php +++ b/setup/modelfactory.class.inc.php @@ -111,6 +111,24 @@ class MFModule { return array(); } + + public function GetDictionaryFiles() + { + $aDictionaries = array(); + if ($hDir = opendir($this->sRootDir)) + { + while (($sFile = readdir($hDir)) !== false) + { + $aMatches = array(); + if (preg_match("/^[^\\.]+.dict.".$this->sName.".php$/i", $sFile, $aMatches)) // Dictionary files are named like .dict..php + { + $aDictionaries[] = $this->sRootDir.'/'.$sFile; + } + } + closedir($hDir); + } + return $aDictionaries; + } } /** @@ -125,15 +143,20 @@ class ModelFactory protected $oModules; protected $oClasses; protected $oMenus; + protected $oDictionaries; static protected $aLoadedClasses; static protected $aWellKnownParents = array('DBObject', 'CMDBObject','cmdbAbstractObject'); // static protected $aWellKnownMenus = array('DataAdministration', 'Catalogs', 'ConfigManagement', 'Contact', 'ConfigManagementCI', 'ConfigManagement:Shortcuts', 'ServiceManagement'); static protected $aLoadedModules; static protected $aLoadErrors; - + protected $aDict; + protected $aDictKeys; + public function __construct($aRootDirs, $aRootNodeExtensions = array()) { + $this->aDict = array(); + $this->aDictKeys = array(); $this->aRootDirs = $aRootDirs; $this->oDOMDocument = new MFDocument(); $this->oRoot = $this->oDOMDocument->CreateElement('itop_design'); @@ -143,6 +166,9 @@ class ModelFactory $this->oRoot->AppendChild($this->oModules); $this->oClasses = $this->oDOMDocument->CreateElement('classes'); $this->oRoot->AppendChild($this->oClasses); + $this->oDictionaries = $this->oDOMDocument->CreateElement('dictionaries'); + $this->oRoot->AppendChild($this->oDictionaries); + foreach (self::$aWellKnownParents as $sWellKnownParent) { $this->AddWellKnownParent($sWellKnownParent); @@ -353,6 +379,65 @@ class ModelFactory $oDeltaRoot = $oDocument->childNodes->item(0); $this->LoadDelta($oDocument, $oDeltaRoot, $this->oDOMDocument); } + + $aDictionaries = $oModule->GetDictionaryFiles(); + + try + { + $this->ResetTempDictionary(); + foreach($aDictionaries as $sPHPFile) + { + $sDictFileContents = file_get_contents($sPHPFile); + $sDictFileContents = str_replace(array('<'.'?'.'php', '?'.'>'), '', $sDictFileContents); + $sDictFileContents = str_replace('Dict::Add', '$this->AddToTempDictionary', $sDictFileContents); + eval($sDictFileContents); + } + + foreach ($this->aDict as $sLanguageCode => $aDictDefinition) + { + $oNodes = $this->GetNodeById('dictionary', $sLanguageCode, $this->oDictionaries); + if ($oNodes->length == 0) + { + $oXmlDict = $this->oDOMDocument->CreateElement('dictionary'); + $oXmlDict->setAttribute('id', $sLanguageCode); + $this->oDictionaries->AddChildNode($oXmlDict); + $oXmlEntries = $this->oDOMDocument->CreateElement('english_description', $aDictDefinition['english_description']); + $oXmlDict->AppendChild($oXmlEntries); + $oXmlEntries = $this->oDOMDocument->CreateElement('localized_description', $aDictDefinition['localized_description']); + $oXmlDict->AppendChild($oXmlEntries); + $oXmlEntries = $this->oDOMDocument->CreateElement('entries'); + $oXmlDict->AppendChild($oXmlEntries); + } + else + { + $oXmlDict = $oNodes->item(0); + $oXmlEntries = $oXmlDict->GetUniqueElement('entries'); + } + + foreach ($aDictDefinition['entries'] as $sCode => $sLabel) + { + + $oXmlEntry = $this->oDOMDocument->CreateElement('entry'); + $oXmlEntry->setAttribute('id', $sCode); + $oXmlValue = $this->oDOMDocument->CreateCDATASection($sLabel); + $oXmlEntry->appendChild($oXmlValue); + if (array_key_exists($sLanguageCode, $this->aDictKeys) && array_key_exists($sCode, $this->aDictKeys[$sLanguageCode])) + { + $oXmlEntries->RedefineChildNode($oXmlEntry); + } + else + { + $oXmlEntries->appendChild($oXmlEntry); + } + $this->aDictKeys[$sLanguageCode][$sCode] = true; + } + } + } + catch(Exception $e) + { + throw new Exception('Failed to load dictionary file "'.$sPHPFile.'", reason: '.$e->getMessage()); + } + } catch(Exception $e) { @@ -365,6 +450,33 @@ class ModelFactory } } + /** + * Collects the PHP Dict entries into the ModelFactory for transforming the dictionary into an XML structure + * @param string $sLanguageCode The language code + * @param string $sEnglishLanguageDesc English description of the language (unused but kept for API compatibility) + * @param string $sLocalizedLanguageDesc Localized description of the language (unused but kept for API compatibility) + * @param hash $aEntries The entries to load: string_code => translation + */ + protected function AddToTempDictionary($sLanguageCode, $sEnglishLanguageDesc, $sLocalizedLanguageDesc, $aEntries) + { + $this->aDict[$sLanguageCode]['english_description'] = $sEnglishLanguageDesc; + $this->aDict[$sLanguageCode]['localized_description'] = $sLocalizedLanguageDesc; + if (!array_key_exists('entries', $this->aDict[$sLanguageCode])) + { + $this->aDict[$sLanguageCode]['entries'] = array(); + } + + foreach($aEntries as $sKey => $sValue) + { + $this->aDict[$sLanguageCode]['entries'][$sKey] = $sValue; + } + } + + protected function ResetTempDictionary() + { + $this->aDict = array(); + } + /** * XML load errors (XML format and validation) */ @@ -568,7 +680,7 @@ class ModelFactory public function GetClassXMLTemplate($sName, $sIcon) { - $sHeader = ''; + $sHeader = ''; return <<