Conn =& $this->Application->GetADODBConnection(); $this->lang_object =& $this->Application->recallObject('lang.import', null, Array ('skip_autoload' => true)); $this->_updateEventsCache(); $this->ip_address = getenv('HTTP_X_FORWARDED_FOR') ? getenv('HTTP_X_FORWARDED_FOR') : getenv('REMOTE_ADDR'); } function _updateEventsCache() { $sql = 'SELECT EventId, CONCAT(Event,"_",Type) AS EventMix FROM ' . TABLE_PREFIX . 'Events'; $this->events_hash = $this->Conn->GetCol($sql, 'EventMix'); } function SetEncoding($enc) { $this->Encoding = $enc; } function _initImportTables($drop_only = false) { $this->tables['phrases'] = $this->prepareTempTable('phrases', $drop_only); $this->tables['emailmessages'] = $this->prepareTempTable('emailmessages', $drop_only); } /** * Create temp table for prefix, if table already exists, then delete it and create again * * @param string $prefix */ function prepareTempTable($prefix, $drop_only = false) { $idfield = $this->Application->getUnitOption($prefix, 'IDField'); $table = $this->Application->getUnitOption($prefix,'TableName'); $temp_table = $this->Application->GetTempName($table); $sql = 'DROP TABLE IF EXISTS %s'; $this->Conn->Query( sprintf($sql, $temp_table) ); if (!$drop_only) { $sql = 'CREATE TABLE %s SELECT * FROM %s WHERE 0'; $this->Conn->Query( sprintf($sql, $temp_table, $table) ); $sql = 'ALTER TABLE %1$s CHANGE %2$s %2$s INT(11) NOT NULL'; $this->Conn->Query( sprintf($sql, $temp_table, $idfield) ); } return $temp_table; } function Parse($filename, $phrase_types, $module_ids, $import_mode = LANG_SKIP_EXISTING) { // define the XML parsing routines/functions to call based on the handler path if( !file_exists($filename) || !$phrase_types /*|| !$module_ids*/ ) return false; if (defined('IS_INSTALL') && IS_INSTALL) { // new events could be added during module upgrade $this->_updateEventsCache(); } $this->_initImportTables(); $phrase_types = explode('|', substr($phrase_types, 1, -1) ); // $module_ids = explode('|', substr($module_ids, 1, -1) ); $this->phrase_types_allowed = array_flip($phrase_types); $this->import_mode = $import_mode; $xml_parser = xml_parser_create(); xml_set_element_handler( $xml_parser, Array(&$this, 'startElement'), Array(&$this, 'endElement') ); xml_set_character_data_handler( $xml_parser, Array(&$this, 'characterData') ); $fdata = file_get_contents($filename); $ret = xml_parse($xml_parser, $fdata); xml_parser_free($xml_parser); // clean up the parser object // copy data from temp tables to live foreach ($this->_languages as $language_id) { $this->_performUpgrade($language_id, 'phrases', 'Phrase'); $this->_performUpgrade($language_id, 'emailmessages', 'EventId'); } $this->_initImportTables(true); return $ret; } /** * Performs upgrade of given language pack part * * @param int $language_id * @param string $prefix * @param string $unique_field */ function _performUpgrade($language_id, $prefix, $unique_field) { // TODO: find a way to compare (intersect,diff) phrases in non-case sensitive way, but keeping original case in result $live_records = $this->_getTableData($language_id, $prefix, $unique_field, false); $temp_records = $this->_getTableData($language_id, $prefix, $unique_field, true); if ($this->import_mode == LANG_OVERWRITE_EXISTING) { // remove existing records before copy $common_records = array_intersect($temp_records, $live_records); if ($common_records) { $live_records = array_diff($live_records, $common_records); // remove overlaping records $common_records = array_map(Array(&$this->Conn, 'qstr'), $common_records); $sql = 'DELETE FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . ' WHERE (LanguageId = ' . $language_id . ') AND (' . $unique_field . ' IN (' . implode(',', $common_records) . '))'; $this->Conn->Query($sql); } } $temp_records = array_diff($temp_records, $live_records); if (!$temp_records) { // no new records found in temp table while comparing it to live table return ; } $temp_records = array_map(Array(&$this->Conn, 'qstr'), $temp_records); $sql = 'INSERT INTO ' . $this->Application->getUnitOption($prefix, 'TableName') . ' SELECT * FROM ' . $this->tables[$prefix] . ' WHERE (LanguageId = ' . $language_id . ')'; if ($live_records) { // subsctract live records from temp table during coping $sql .= ' AND (' . $unique_field . ' IN (' . implode(',', $temp_records) . '))'; } $this->Conn->Query($sql); } function _getTableData($language_id, $prefix, $unique_field, $temp_mode = false) { $table_name = $this->Application->getUnitOption($prefix, 'TableName'); if ($temp_mode) { $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $prefix); } $sql = 'SELECT ' . $unique_field . ' FROM ' . $table_name . ' WHERE LanguageId = ' . $language_id; return $this->Conn->GetCol($sql); } function startElement(&$parser, $element, $attributes) { array_push($this->path, $element); $path = implode(' ',$this->path); //check what path we are in $this->LastLine = xml_get_current_line_number($parser); $this->SecondData = false; switch ($path) { case 'LANGUAGES LANGUAGE': $this->current_language = Array ( 'PackName' => $attributes['PACKNAME'], 'LocalName' => $attributes['PACKNAME'], 'Encoding' => $attributes['ENCODING'], ); $sql = 'SELECT ' . $this->lang_object->IDField . ' FROM ' . $this->lang_object->TableName . ' WHERE PackName = ' . $this->Conn->qstr( $this->current_language['PackName'] ); $language_id = $this->Conn->GetOne($sql); if ($language_id) { $this->current_language['LanguageId'] = $language_id; $this->lang_object->Load($language_id); } break; case 'LANGUAGES LANGUAGE PHRASES': case 'LANGUAGES LANGUAGE EVENTS': if( !getArrayValue($this->current_language,'Charset') ) $this->current_language['Charset'] = 'iso-8859-1'; $this->lang_object->SetFieldsFromHash($this->current_language); if ( !getArrayValue($this->current_language, 'LanguageId') ) { $this->lang_object->SetDBField('Enabled', STATUS_ACTIVE); if ($this->lang_object->Create()) { $this->current_language['LanguageId'] = $this->lang_object->GetID(); if (defined('IS_INSTALL') && IS_INSTALL) { // language created during install becomes admin interface language $this->lang_object->setPrimary(true, true); } } } elseif ($this->import_mode == LANG_OVERWRITE_EXISTING) { // update live language record based on data from xml $this->lang_object->Update(); } $language_id = $this->lang_object->GetID(); if (!in_array($language_id, $this->_languages)) { $this->_languages[] = $language_id; } break; case 'LANGUAGES LANGUAGE PHRASES PHRASE': $phrase_module = getArrayValue($attributes,'MODULE'); if(!$phrase_module) $phrase_module = 'In-Portal'; $this->current_phrase = Array( 'LanguageId' => $this->current_language['LanguageId'], 'Phrase' => $attributes['LABEL'], 'PhraseType' => $attributes['TYPE'], 'PhraseId' => 0, 'Module' => $phrase_module, 'LastChanged' => adodb_mktime(), 'LastChangeIP' => $this->ip_address, 'Translation' => ''); break; case 'LANGUAGES LANGUAGE EVENTS EVENT': $this->current_event = Array( 'EmailMessageId'=> 0, 'LanguageId' => $this->current_language['LanguageId'], 'EventId' => $this->_getEventId($attributes['EVENT'], $attributes['TYPE']), 'MessageType' => $attributes['MESSAGETYPE'], 'Template' => ''); break; } // if($path == 'SHIPMENT PACKAGE') } function _getEventId($event_name, $event_type) { $cache_key = $event_name . '_' . $event_type; return array_key_exists($cache_key, $this->events_hash) ? $this->events_hash[$cache_key] : 0; } function characterData(&$parser, $line) { $line = trim($line); if(!$line) return ; $path = join (' ',$this->path); $language_nodes = Array('DATEFORMAT','TIMEFORMAT','INPUTDATEFORMAT','INPUTTIMEFORMAT','DECIMAL','THOUSANDS','CHARSET','UNITSYSTEM'); $node_field_map = Array('LANGUAGES LANGUAGE DATEFORMAT' => 'DateFormat', 'LANGUAGES LANGUAGE TIMEFORMAT' => 'TimeFormat', 'LANGUAGES LANGUAGE INPUTDATEFORMAT'=> 'InputDateFormat', 'LANGUAGES LANGUAGE INPUTTIMEFORMAT'=> 'InputTimeFormat', 'LANGUAGES LANGUAGE DECIMAL' => 'DecimalPoint', 'LANGUAGES LANGUAGE THOUSANDS' => 'ThousandSep', 'LANGUAGES LANGUAGE CHARSET' => 'Charset', 'LANGUAGES LANGUAGE UNITSYSTEM' => 'UnitSystem'); if( in_array( end($this->path), $language_nodes) ) { $this->current_language[ $node_field_map[$path] ] = $line; } else { switch($path) { case 'LANGUAGES LANGUAGE PHRASES PHRASE': if( isset($this->phrase_types_allowed[ $this->current_phrase['PhraseType'] ]) ) { $this->current_phrase['Translation'] .= $line; } break; case 'LANGUAGES LANGUAGE EVENTS EVENT': $cur_line = xml_get_current_line_number($parser); if ($cur_line != $this->LastLine) { $this->current_event['Template'] .= str_repeat("\r\n", ($cur_line - $this->LastLine) ); $this->LastLine = $cur_line; } $this->current_event['Template'] .= $line; $this->SecondData = true; break; } } } function endElement(&$parser, $element) { $path = implode(' ',$this->path); switch($path) { case 'LANGUAGES LANGUAGE PHRASES PHRASE': if( isset($this->phrase_types_allowed[ $this->current_phrase['PhraseType'] ]) ) { if ($this->current_language['Encoding'] == 'plain') { // nothing to decode! } else { $this->current_phrase['Translation'] = base64_decode($this->current_phrase['Translation']); } $this->Conn->doInsert($this->current_phrase, $this->tables['phrases']); } break; case 'LANGUAGES LANGUAGE EVENTS EVENT': if (!$this->current_event['EventId']) { // language pack contains event translation, that's name is not found in Events table continue; } if ($this->current_language['Encoding'] == 'plain') { $this->current_event['Template'] = rtrim($this->current_event['Template']); // nothing to decode! } else { $this->current_event['Template'] = base64_decode($this->current_event['Template']); } $this->Conn->doInsert($this->current_event, $this->tables['emailmessages']); break; } array_pop($this->path); } /** * Creates XML file with exported language data * * @param string $filename filename to export into * @param Array $phrase_types phrases types to export from modules passed in $module_ids * @param Array $language_ids IDs of languages to export * @param Array $module_ids IDs of modules to export phrases from */ function Create($filename, $phrase_types, $language_ids, $module_ids) { $fp = fopen($filename,'w'); if(!$fp || !$phrase_types || !$module_ids || !$language_ids) return false; $phrase_types = explode('|', substr($phrase_types, 1, -1) ); $module_ids = explode('|', substr($module_ids, 1, -1) ); $this->events_hash = array_flip($this->events_hash); $lang_table = $this->Application->getUnitOption('lang','TableName'); $phrases_table = $this->Application->getUnitOption('phrases','TableName'); $emailevents_table = $this->Application->getUnitOption('emailmessages','TableName'); $mainevents_table = $this->Application->getUnitOption('emailevents','TableName'); $phrase_tpl = "\t\t\t".'%s'."\n"; $event_tpl = "\t\t\t".'%s'."\n"; $sql = 'SELECT * FROM %s WHERE LanguageId = %s'; $ret = ''."\n"; foreach($language_ids as $language_id) { // languages $row = $this->Conn->GetRow( sprintf($sql, $lang_table, $language_id) ); $ret .= "\t".''.$row['DateFormat'].''; $ret .= ''.$row['TimeFormat'].''.$row['InputDateFormat'].''; $ret .= ''.$row['InputTimeFormat'].''.$row['DecimalPoint'].''; $ret .= ''.$row['ThousandSep'].''.$row['Charset'].''; $ret .= ''.$row['UnitSystem'].''."\n"; // phrases $phrases_sql = 'SELECT * FROM '.$phrases_table.' WHERE LanguageId = %s AND PhraseType IN (%s) AND Module IN (%s) ORDER BY Phrase'; if( in_array('In-Portal',$module_ids) ) array_push($module_ids, ''); // for old language packs $rows = $this->Conn->Query( sprintf($phrases_sql,$language_id, implode(',',$phrase_types), '\''.implode('\',\'',$module_ids).'\'' ) ); if($rows) { $ret .= "\t\t".''."\n"; foreach($rows as $row) { $data = $this->Encoding == 'base64' ? base64_encode($row['Translation']) : ''; $ret .= sprintf($phrase_tpl, $row['Phrase'], $row['Module'], $row['PhraseType'], $data ); } $ret .= "\t\t".''."\n"; } // email events if( in_array('In-Portal',$module_ids) ) unset( $module_ids[array_search('',$module_ids)] ); // for old language packs $module_sql = preg_replace('/(.*) OR $/', '\\1', preg_replace('/(.*),/U', 'INSTR(Module,\'\\1\') OR ', implode(',', $module_ids).',' ) ); $sql = 'SELECT EventId FROM '.$mainevents_table.' WHERE '.$module_sql; $event_ids = $this->Conn->GetCol($sql); if($event_ids) { $ret .= "\t\t".''."\n"; $event_sql = ' SELECT em.* FROM '.$emailevents_table.' em LEFT JOIN '.$mainevents_table.' e ON e.EventId = em.EventId WHERE em.LanguageId = %s AND em.EventId IN (%s) ORDER BY e.Event, e.Type'; $rows = $this->Conn->Query( sprintf($event_sql,$language_id, $event_ids ? implode(',',$event_ids) : '' ) ); foreach($rows as $row) { if (!array_key_exists($row['EventId'], $this->events_hash)) { // don't export existing translations of missing events continue; } list($event_name, $event_type) = explode('_', $this->events_hash[ $row['EventId'] ] ); $data = $this->Encoding == 'base64' ? base64_encode($row['Template']) : ''; $ret .= sprintf($event_tpl, $row['MessageType'], $event_name, $event_type, $data ); } $ret .= "\t\t".''."\n"; } $ret .= "\t".''."\n"; } $ret .= ''; fwrite($fp, $ret); fclose($fp); return true; } /** * Creates new instance of LangXML_Parser class * * @param int $type * @return LangXML_Parser */ function &makeClass($temp_mode = true) { $result = new LangXML_Parser($temp_mode); return $result; } } ?>