Index: branches/5.2.x/core/units/helpers/language_import_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/language_import_helper.php	(revision 15237)
+++ branches/5.2.x/core/units/helpers/language_import_helper.php	(revision 15238)
@@ -1,1223 +1,1222 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 /**
  * Language pack format version description
  *
  * v1
  * ==========
  * All language properties are separate nodes inside <LANGUAGE> node. There are
  * two more nodes PHRASES and EVENTS for phrase and email event translations.
  *
  * v2
  * ==========
  * All data, that will end up in Language table is now attributes of LANGUAGE node
  * and is name exactly as field name, that will be used to store that data.
  *
  * v4
  * ==========
  * Hint & Column translation added to each phrase translation
  *
  * v5
  * ==========
  * Use separate xml nodes for subject, headers, html & plain translations
  *
  * v6
  * ==========
  * Added e-mail design templates
  *
  */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	define('LANG_OVERWRITE_EXISTING', 1);
 	define('LANG_SKIP_EXISTING', 2);
 
 	class LanguageImportHelper extends kHelper {
 
 		/**
 		 * Current Language in import
 		 *
 		 * @var LanguagesItem
 		 */
 		var $lang_object = null;
 
 		/**
 		 * Current user's IP address
 		 *
 		 * @var string
 		 */
 		var $ip_address = '';
 
 		/**
 		 * Event type + name mapping to id (from system)
 		 *
 		 * @var Array
 		 */
 		var $events_hash = Array ();
 
 		/**
 		 * Language pack import mode
 		 *
 		 * @var int
 		 */
 		var $import_mode = LANG_SKIP_EXISTING;
 
 		/**
 		 * Language IDs, that were imported
 		 *
 		 * @var Array
 		 */
 		var $_languages = Array ();
 
 		/**
 		 * Temporary table names to perform import on
 		 *
 		 * @var Array
 		 */
 		var $_tables = Array ();
 
 		/**
 		 * Phrase types allowed for import/export operations
 		 *
 		 * @var Array
 		 */
 		var $phrase_types_allowed = Array ();
 
 		/**
 		 * Encoding, used for language pack exporting
 		 *
 		 * @var string
 		 */
 		var $_exportEncoding = 'base64';
 
 		/**
 		 * Exported data limits (all or only specified ones)
 		 *
 		 * @var Array
 		 */
 		var $_exportLimits = Array (
 			'phrases' => false,
 			'emailevents' => false,
 			'country-state' => false,
 		);
 
 		/**
 		 * Debug language pack import process
 		 *
 		 * @var bool
 		 */
 		var $_debugMode = false;
 
 		/**
 		 * Latest version of language pack format. Versions are not backwards compatible!
 		 *
 		 * @var int
 		 */
 		var $_latestVersion = 6;
 
 		/**
 		 * Prefix-based serial numbers, that should be changed after import is finished
 		 *
 		 * @var Array
 		 */
 		var $changedPrefixes = Array ();
 
 		public function __construct()
 		{
 			parent::__construct();
 
 			// "core/install/english.lang", phrase count: 3318, xml parse time on windows: 10s, insert time: 0.058s
 			set_time_limit(0);
 			ini_set('memory_limit', -1);
 
 			$this->lang_object = $this->Application->recallObject('lang.import', null, Array ('skip_autoload' => true));
 
 			if (!(defined('IS_INSTALL') && IS_INSTALL)) {
 				// perform only, when not in installation mode
 				$this->_updateEventsCache();
 			}
 
 			$this->ip_address = getenv('HTTP_X_FORWARDED_FOR') ? getenv('HTTP_X_FORWARDED_FOR') : getenv('REMOTE_ADDR');
 
 //			$this->_debugMode = $this->Application->isDebugMode();
 		}
 
 		/**
 		 * Performs import of given language pack (former Parse method)
 		 *
 		 * @param string $filename
 		 * @param string $phrase_types
 		 * @param Array $module_ids
 		 * @param int $import_mode
 		 * @return bool
 		 */
 		function performImport($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 ($this->_debugMode) {
 				$start_time = microtime(true);
 				$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
 			}
 
 			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;
 
 			$this->_parseXML($filename);
 
 			// copy data from temp tables to live
 			foreach ($this->_languages as $language_id) {
 				$this->_performUpgrade($language_id, 'phrases', 'PhraseKey', Array ('l%s_Translation', 'l%s_HintTranslation', 'l%s_ColumnTranslation', 'PhraseType'));
 				$this->_performUpgrade($language_id, 'emailevents', 'EventId', Array ('l%s_Subject', 'Headers', 'l%s_HtmlBody', 'l%s_PlainTextBody'));
 				$this->_performUpgrade($language_id, 'country-state', 'CountryStateId', Array ('l%s_Name'));
 			}
 
 			$this->_initImportTables(true);
 			$this->changedPrefixes = array_unique($this->changedPrefixes);
 
 			foreach ($this->changedPrefixes as $prefix) {
 				$this->Application->incrementCacheSerial($prefix);
 			}
 
 			if ($this->_debugMode) {
 				$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (microtime(true) - $start_time));
 			}
 
 			return true;
 		}
 
 		/**
 		 * Creates XML file with exported language data (former Create method)
 		 *
 		 * @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 performExport($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) );
 
 			$ret = '<LANGUAGES Version="' . $this->_latestVersion . '">' . "\n";
 
 			$export_fields = $this->_getExportFields();
 
 			// get languages
 			$sql = 'SELECT *
 					FROM ' . $this->Application->getUnitOption('lang','TableName') . '
 					WHERE LanguageId IN (' . implode(',', $language_ids) . ')';
 			$languages = $this->Conn->Query($sql, 'LanguageId');
 
 			// get phrases
 			$phrase_modules = $module_ids;
 			array_push($phrase_modules, ''); // for old language packs without module
 
 			$phrase_modules = $this->Conn->qstrArray($phrase_modules);
 
 			// apply phrase selection limit
 			if ($this->_exportLimits['phrases']) {
 				$escaped_phrases = $this->Conn->qstrArray($this->_exportLimits['phrases']);
 				$limit_where = 'Phrase IN (' . implode(',', $escaped_phrases) . ')';
 			}
 			else {
 				$limit_where = 'TRUE';
 			}
 
 			$sql = 'SELECT *
 					FROM ' . $this->Application->getUnitOption('phrases','TableName') . '
 					WHERE PhraseType IN (' . implode(',', $phrase_types) . ') AND Module IN (' . implode(',', $phrase_modules) . ') AND ' . $limit_where . '
 					ORDER BY Phrase';
 			$phrases = $this->Conn->Query($sql, 'PhraseId');
 
 			// email events
 			$module_sql = preg_replace('/(.*),/U', 'INSTR(Module,\'\\1\') OR ', implode(',', $module_ids) . ',');
 
 			// apply event selection limit
 			if ($this->_exportLimits['emailevents']) {
 				$escaped_email_events = $this->Conn->qstrArray($this->_exportLimits['emailevents']);
 				$limit_where = '`Event` IN (' . implode(',', $escaped_email_events) . ')';
 			}
 			else {
 				$limit_where = 'TRUE';
 			}
 
 			$sql = 'SELECT *
 					FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
 					WHERE `Type` IN (' . implode(',', $phrase_types) . ') AND (' . substr($module_sql, 0, -4) . ') AND ' . $limit_where . '
 					ORDER BY `Event`, `Type`';
 			$events = $this->Conn->Query($sql, 'EventId');
 
 			if ( in_array('Core', $module_ids) ) {
 				if ($this->_exportLimits['country-state']) {
 					$escaped_countries = $this->Conn->qstrArray($this->_exportLimits['country-state']);
 					$limit_where = '`IsoCode` IN (' . implode(',', $escaped_countries) . ')';
 				}
 				else {
 					$limit_where = 'TRUE';
 				}
 
 				$country_table = $this->Application->getUnitOption('country-state', 'TableName');
 
 				// countries
 				$sql = 'SELECT *
 						FROM ' . $country_table . '
 						WHERE Type = ' . DESTINATION_TYPE_COUNTRY . ' AND ' . $limit_where . '
 						ORDER BY `IsoCode`';
 				$countries = $this->Conn->Query($sql, 'CountryStateId');
 
 				// states
 				$sql = 'SELECT state.*
 						FROM ' . $country_table . ' state
 						JOIN ' . $country_table . ' country ON country.CountryStateId = state.StateCountryId
 						WHERE state.Type = ' . DESTINATION_TYPE_STATE . ' AND ' . str_replace('`IsoCode`', 'country.`IsoCode`', $limit_where) . '
 						ORDER BY state.`IsoCode`';
 				$states = $this->Conn->Query($sql, 'CountryStateId');
 
 				foreach ($states as $state_id => $state_data) {
 					$country_id = $state_data['StateCountryId'];
 
 					if ( !array_key_exists('States', $countries[$country_id]) ) {
 						$countries[$country_id]['States'] = Array ();
 					}
 
 					$countries[$country_id]['States'][] = $state_id;
 				}
 			}
 
 			foreach ($languages as $language_id => $language_info) {
 				// language
 				$ret .= "\t" . '<LANGUAGE Encoding="' . $this->_exportEncoding . '"';
 
 				foreach ($export_fields	as $export_field) {
 					$ret .= ' ' . $export_field . '="' . htmlspecialchars($language_info[$export_field]) . '"';
 				}
 
 				$ret .= '>' . "\n";
 
 				// filename replacements
 				$replacements = $language_info['FilenameReplacements'];
 
 				if ( $replacements ) {
 					$ret .= "\t\t" . '<REPLACEMENTS>' . $this->_exportConvert($replacements) . '</REPLACEMENTS>' . "\n";
 				}
 
 				// e-mail design templates
 				if ( $language_info['HtmlEmailTemplate'] || $language_info['TextEmailTemplate'] ) {
 					$ret .= "\t\t" . '<EMAILDESIGNS>' . "\n";
 
 					if ( $language_info['HtmlEmailTemplate'] ) {
 						$ret .= "\t\t\t" . '<HTML>' . $this->_exportConvert($language_info['HtmlEmailTemplate']) . '</HTML>' . "\n";
 					}
 
 					if ( $language_info['TextEmailTemplate'] ) {
 						$ret .= "\t\t\t" . '<TEXT>' . $this->_exportConvert($language_info['TextEmailTemplate']) . '</TEXT>' . "\n";
 					}
 
 					$ret .= "\t\t" . '</EMAILDESIGNS>' . "\n";
 				}
 
 				// phrases
 				if ($phrases) {
 					$ret .= "\t\t" . '<PHRASES>' . "\n";
 					foreach ($phrases as $phrase_id => $phrase) {
 						$translation = $phrase['l' . $language_id . '_Translation'];
 						$hint_translation = $phrase['l' . $language_id . '_HintTranslation'];
 						$column_translation = $phrase['l' . $language_id . '_ColumnTranslation'];
 
 						if (!$translation) {
 							// phrase is not translated on given language
 							continue;
 						}
 
 						if ( $this->_exportEncoding == 'base64' ) {
 							$hint_translation = base64_encode($hint_translation);
 							$column_translation = base64_encode($column_translation);
 						}
 						else {
 							$hint_translation = htmlspecialchars($hint_translation);
 							$column_translation = htmlspecialchars($column_translation);
 						}
 
 						$attributes = Array (
 							'Label="' . $phrase['Phrase'] . '"',
 							'Module="' . $phrase['Module'] . '"',
 							'Type="' . $phrase['PhraseType'] . '"'
 						);
 
 						if ( $phrase['l' . $language_id . '_HintTranslation'] ) {
 							$attributes[] = 'Hint="' . $hint_translation . '"';
 						}
 
 						if ( $phrase['l' . $language_id . '_ColumnTranslation'] ) {
 							$attributes[] = 'Column="' . $column_translation . '"';
 						}
 
 						$ret .= "\t\t\t" . '<PHRASE ' . implode(' ', $attributes) . '>' . $this->_exportConvert($translation) . '</PHRASE>' . "\n";
 					}
 
 					$ret .= "\t\t" . '</PHRASES>' . "\n";
 				}
 
 				// email events
 				if ($events) {
 					$ret .= "\t\t" . '<EVENTS>' . "\n";
 
 					foreach ($events as $event_data) {
 						$fields_hash = Array (
 							'HEADERS' => $event_data['Headers'],
 							'SUBJECT' => $event_data['l' . $language_id . '_Subject'],
 							'HTMLBODY' => $event_data['l' . $language_id . '_HtmlBody'],
 							'PLAINTEXTBODY' => $event_data['l' . $language_id . '_PlainTextBody'],
 						);
 
 						$data = '';
 
 						foreach ($fields_hash as $xml_node => $xml_content) {
 							if ( $xml_content ) {
 								$data .= "\t\t\t\t" . '<' . $xml_node . '>' . $this->_exportConvert($xml_content) . '</' . $xml_node . '>' . "\n";
 							}
 						}
 
 						if ( $data ) {
 							$ret .= "\t\t\t" . '<EVENT Event="' . $event_data['Event'] . '" Type="' . $event_data['Type'] . '">' . "\n" . $data . "\t\t\t" . '</EVENT>' . "\n";
 						}
 					}
 
 					$ret .= "\t\t" . '</EVENTS>' . "\n";
 				}
 
 				if (in_array('Core', $module_ids) && $countries) {
 					$ret .= "\t\t" . '<COUNTRIES>' . "\n";
 					foreach ($countries as $country_data) {
 						$translation = $country_data['l' . $language_id . '_Name'];
 
 						if (!$translation) {
 							// country is not translated on given language
 							continue;
 						}
 
 						$data = $this->_exportEncoding == 'base64' ? base64_encode($translation) : $translation;
 
 						if (array_key_exists('States', $country_data)) {
 							$ret .= "\t\t\t" . '<COUNTRY Iso="' . $country_data['IsoCode'] . '" Translation="' . $data . '">' . "\n";
 
 							foreach ($country_data['States'] as $state_id) {
 								$translation = $states[$state_id]['l' . $language_id . '_Name'];
 
 								if (!$translation) {
 									// state is not translated on given language
 									continue;
 								}
 
 								$data = $this->_exportEncoding == 'base64' ? base64_encode($translation) : $translation;
 								$ret .= "\t\t\t\t" . '<STATE Iso="' . $states[$state_id]['IsoCode'] . '" Translation="' . $data . '"/>' . "\n";
 							}
 
 							$ret  .= "\t\t\t" . '</COUNTRY>' . "\n";
 						}
 						else {
 							$ret .= "\t\t\t" . '<COUNTRY Iso="' . $country_data['IsoCode'] . '" Translation="' . $data . '"/>' . "\n";
 						}
 					}
 
 					$ret .= "\t\t" . '</COUNTRIES>' . "\n";
 				}
 
 				$ret .= "\t" . '</LANGUAGE>' . "\n";
 			}
 
 			$ret .= '</LANGUAGES>';
 			fwrite($fp, $ret);
 			fclose($fp);
 
 			return true;
 		}
 
 		/**
 		 * Converts string before placing into export file
 		 *
 		 * @param string $string
 		 * @return string
 		 * @access protected
 		 */
 		protected function _exportConvert($string)
 		{
 			return $this->_exportEncoding == 'base64' ? base64_encode($string) : '<![CDATA[' . $string . ']]>';
 		}
 
 		/**
 		 * Sets language pack encoding (not charset) used during export
 		 *
 		 * @param string $encoding
 		 */
 		function setExportEncoding($encoding)
 		{
 			$this->_exportEncoding = $encoding;
 		}
 
 		/**
 		 * Sets language pack data limit for export
 		 *
 		 * @param string $prefix
 		 * @param string $data
 		 */
 		function setExportLimit($prefix, $data = null)
 		{
 			if ( !isset($data) ) {
 				$key_field = $prefix == 'phrases' ? 'Phrase' : 'Event';
 				$ids = $this->getExportIDs($prefix);
 
 				$sql = 'SELECT ' . $key_field . '
 						FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . '
 						WHERE ' . $this->Application->getUnitOption($prefix, 'IDField') . ' IN (' . $ids . ')';
 				$rs = $this->Conn->QueryRaw($sql);
 
 				if ( $this->Conn->RowCount($rs) ) {
 					$data = '';
 
 					while ( ($row = $this->Conn->GetNextRow($rs)) ) {
 						$data .= ',' . $row[$key_field];
 					}
 
 					$data = substr($data, 1);
 				}
 
 				$this->Conn->Destroy($rs);
 			}
 
 			if ( !is_array($data) ) {
 				$data = str_replace(',', "\n", $data);
 				$data = preg_replace("/\n+/", "\n", str_replace("\r", '', trim($data)));
 				$data = $data ? array_map('trim', explode("\n", $data)) : Array ();
 			}
 
 			$this->_exportLimits[$prefix] = $data;
 		}
 
 		/**
 		 * Performs upgrade of given language pack part
 		 *
 		 * @param int $language_id
 		 * @param string $prefix
 		 * @param string $unique_field
 		 * @param Array $data_fields
 		 */
 		function _performUpgrade($language_id, $prefix, $unique_field, $data_fields)
 		{
 			$live_records = $this->_getTableData($language_id, $prefix, $unique_field, $data_fields[0], false);
 			$temp_records = $this->_getTableData($language_id, $prefix, $unique_field, $data_fields[0], true);
 
 			if (!$temp_records) {
 				// no data for given language
 				return ;
 			}
 
 			// perform insert for records, that are missing in live table
 			$to_insert = array_diff($temp_records, $live_records);
 
 			if ($to_insert) {
 				$to_insert = $this->Conn->qstrArray($to_insert);
 
 				$sql = 'INSERT INTO ' . $this->Application->getUnitOption($prefix, 'TableName') . '
 						SELECT *
 						FROM ' . $this->_tables[$prefix] . '
 						WHERE ' . $unique_field . ' IN (' . implode(',', $to_insert) . ')';
 				$this->Conn->Query($sql);
 
 				// new records were added
 				$this->changedPrefixes[] = $prefix;
 			}
 
 			// perform update for records, that are present in live table
 			$to_update = array_diff($temp_records, $to_insert);
 
 			if ($to_update) {
 				$to_update = $this->Conn->qstrArray($to_update);
 
 				$sql = 'UPDATE ' . $this->Application->getUnitOption($prefix, 'TableName') . ' live
 						SET ';
 
 				foreach ($data_fields as $index => $data_field) {
 					$data_field = sprintf($data_field, $language_id);
 
 					$sql .= '	live.' . $data_field . ' = (
 									SELECT temp' . $index . '.' . $data_field . '
 									FROM ' . $this->_tables[$prefix] . ' temp' . $index . '
 									WHERE temp' . $index . '.' . $unique_field . ' = live.' . $unique_field . '
 								),';
 				}
 
 				$sql = substr($sql, 0, -1); // cut last comma
 
 				$where_clause = Array (
 					// this won't make any difference, but just in case
 					$unique_field . ' IN (' . implode(',', $to_update) . ')',
 				);
 
 				if ($this->import_mode == LANG_SKIP_EXISTING) {
 					// empty OR not set
 					$data_field = sprintf($data_fields[0], $language_id);
 					$where_clause[] = '(' . $data_field . ' = "") OR (' . $data_field . ' IS NULL)';
 				}
 
 				if ($where_clause) {
 					$sql .= "\n" . 'WHERE (' . implode(') AND (', $where_clause) . ')';
 				}
 
 				$this->Conn->Query($sql);
 
 				if ($this->Conn->getAffectedRows() > 0) {
 					// existing records were updated
 					$this->changedPrefixes[] = $prefix;
 				}
 			}
 		}
 
 		/**
 		 * Returns data from given table used for language pack upgrade
 		 *
 		 * @param int $language_id
 		 * @param string $prefix
 		 * @param string $unique_field
 		 * @param string $data_field
 		 * @param bool $temp_mode
 		 * @return Array
 		 */
 		function _getTableData($language_id, $prefix, $unique_field, $data_field, $temp_mode = false)
 		{
 			$data_field = sprintf($data_field, $language_id);
 			$table_name = $this->Application->getUnitOption($prefix, 'TableName');
 
 			if ($temp_mode) {
 				// for temp table get only records, that have contents on given language (not empty and isset)
 				$sql = 'SELECT ' . $unique_field . '
 						FROM ' . $this->Application->GetTempName($table_name, 'prefix:' . $prefix) . '
 						WHERE (' . $data_field . ' <> "") AND (' . $data_field . ' IS NOT NULL)';
 			}
 			else {
 				// for live table get all records, no matter on what language
 				$sql = 'SELECT ' . $unique_field . '
 						FROM ' . $table_name;
 			}
 
 			return $this->Conn->GetCol($sql);
 		}
 
 		function _parseXML($filename)
 		{
 			if ( $this->_debugMode ) {
 				$start_time = microtime(true);
 				$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
 			}
 
 			$languages = simplexml_load_file($filename);
 
 			if ( $languages === false) {
 				// invalid language pack contents
 				return false;
 			}
 
 			// PHP 5.3 version would be: $languages->count()
 			if ( count($languages->children()) ) {
 				$this->_processLanguages($languages);
 			}
 
 			if ( $this->_debugMode ) {
 				$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (microtime(true) - $start_time));
 			}
 
 			return true;
 		}
 
 		/**
 		 * Creates temporary tables, used during language import
 		 *
 		 * @param bool $drop_only
 		 */
 		function _initImportTables($drop_only = false)
 		{
 			$this->_tables['phrases'] = $this->_prepareTempTable('phrases', $drop_only);
 			$this->_tables['emailevents'] = $this->_prepareTempTable('emailevents', $drop_only);
 			$this->_tables['country-state'] = $this->_prepareTempTable('country-state', $drop_only);
 		}
 
 		/**
 		 * Create temp table for prefix, if table already exists, then delete it and create again
 		 *
 		 * @param string $prefix
 		 * @param bool $drop_only
 		 * @return string Name of created temp table
 		 * @access protected
 		 */
 		protected function _prepareTempTable($prefix, $drop_only = false)
 		{
 			$id_field = $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 ' . $temp_table . ' SELECT * FROM ' . $table . ' WHERE 0';
 				$this->Conn->Query($sql);
 
 				$sql = 'ALTER TABLE %1$s CHANGE %2$s %2$s INT(11) NOT NULL DEFAULT "0"';
 				$this->Conn->Query( sprintf($sql, $temp_table, $id_field) );
 
 				switch ($prefix) {
 					case 'phrases':
 						$unique_field = 'PhraseKey';
 						break;
 
 					case 'emailevents':
 						$unique_field = 'EventId';
 						break;
 
 					case 'country-state':
 						$unique_field = 'CountryStateId';
 						break;
 
 					default:
 						throw new Exception('Unknown prefix "<strong>' . $prefix . '</strong>" during language pack import');
 						break;
 				}
 
 				$sql = 'ALTER TABLE ' . $temp_table . ' ADD UNIQUE (' . $unique_field . ')';
 				$this->Conn->Query($sql);
 			}
 
 			return $temp_table;
 		}
 
 		/**
 		 * Prepares mapping between event name+type and their ids in database
 		 *
 		 */
 		function _updateEventsCache()
 		{
 			$sql = 'SELECT EventId, CONCAT(Event,"_",Type) AS EventMix
 					FROM ' . TABLE_PREFIX . 'EmailEvents';
 			$this->events_hash = $this->Conn->GetCol($sql, 'EventMix');
 		}
 
 		/**
 		 * Returns language fields to be exported
 		 *
 		 * @return Array
 		 */
 		function _getExportFields()
 		{
 			return Array (
 				'PackName', 'LocalName', 'DateFormat', 'TimeFormat', 'InputDateFormat', 'InputTimeFormat',
 				'DecimalPoint', 'ThousandSep', 'Charset', 'UnitSystem', 'Locale', 'UserDocsUrl'
 			);
 		}
 
 		/**
 		 * Processes parsed XML
 		 *
 		 * @param SimpleXMLElement $languages
 		 */
 		function _processLanguages($languages)
 		{
 			$version = (int)$languages['Version'];
 
 			if ( !$version ) {
 				// version missing -> guess it
 				if ( $languages->DATEFORMAT->getName() ) {
 					$version = 1;
 				}
 				elseif ( (string)$languages->LANGUAGE['Charset'] != '' ) {
 					$version = 2;
 				}
 			}
 
 			if ( $version == 1 ) {
 				$field_mapping = Array (
 					'DATEFORMAT' => 'DateFormat',
 					'TIMEFORMAT' => 'TimeFormat',
 					'INPUTDATEFORMAT' => 'InputDateFormat',
 					'INPUTTIMEFORMAT' => 'InputTimeFormat',
 					'DECIMAL' => 'DecimalPoint',
 					'THOUSANDS' => 'ThousandSep',
 					'CHARSET' => 'Charset',
 					'UNITSYSTEM' => 'UnitSystem',
 					'DOCS_URL' => 'UserDocsUrl',
 				);
 			}
 			else {
 				$export_fields = $this->_getExportFields();
 			}
 
 			foreach ($languages as $language_node) {
 				$language_id = false;
 
 				$fields_hash = Array (
 					'PackName' => (string)$language_node['PackName'],
 					'LocalName' => (string)$language_node['PackName'],
 					'Encoding' => (string)$language_node['Encoding'],
 					'Charset' => 'utf-8',
 					'SynchronizationModes' => Language::SYNCHRONIZE_DEFAULT,
-					'HtmlEmailTemplate' => '$body',
 				);
 
 				if ( $version > 1 ) {
 					foreach ($export_fields as $export_field) {
 						if ( (string)$language_node[$export_field] ) {
 							$fields_hash[$export_field] = (string)$language_node[$export_field];
 						}
 					}
 				}
 
 				$container_nodes = Array ('PHRASES', 'EVENTS', 'COUNTRIES');
 
 				foreach ($language_node as $sub_node) {
 					/* @var $sub_node SimpleXMLElement */
 
 					if ( in_array($sub_node->getName(), $container_nodes) ) {
 						// PHP 5.3 version would be: !$sub_node->count()
 						if ( !count($sub_node->children()) ) {
 							continue;
 						}
 
 						if ( !$language_id ) {
 							$language_id = $this->_processLanguage($fields_hash);
 						}
 					}
 
 					switch ($sub_node->getName()) {
 						case 'PHRASES':
 							$this->_processPhrases($sub_node, $language_id, $fields_hash['Encoding']);
 							break;
 
 						case 'EVENTS':
 							$this->_processEvents($sub_node, $language_id, $fields_hash['Encoding']);
 							break;
 
 						case 'COUNTRIES':
 							$this->_processCountries($sub_node, $language_id, $fields_hash['Encoding']);
 							break;
 
 						case 'REPLACEMENTS':
 							// added since v2
 							$replacements = (string)$sub_node;
 
 							if ( $fields_hash['Encoding'] != 'plain' ) {
 								$replacements = base64_decode($replacements);
 							}
 
 							$fields_hash['FilenameReplacements'] = $replacements;
 							break;
 
 						case 'EMAILDESIGNS':
 							// added since v6
 							$this->_decodeEmailDesignTemplate($fields_hash, 'HtmlEmailTemplate', (string)$sub_node->HTML);
 							$this->_decodeEmailDesignTemplate($fields_hash, 'TextEmailTemplate', (string)$sub_node->TEXT);
 							break;
 
 						default:
 							if ( $version == 1 ) {
 								$fields_hash[$field_mapping[$sub_node->Name]] = (string)$sub_node;
 							}
 							break;
 					}
 				}
 			}
 		}
 
 		/**
 		 * Decodes e-mail template design from language pack
 		 *
 		 * @param Array $fields_hash
 		 * @param string $field
 		 * @param string $design_template
 		 */
 		protected function _decodeEmailDesignTemplate(&$fields_hash, $field, $design_template)
 		{
 			if ( $fields_hash['Encoding'] != 'plain' ) {
 				$design_template = base64_decode($design_template);
 			}
 
 			if ( $design_template ) {
 				$fields_hash[$field] = $design_template;
 			}
 		}
 
 		/**
 		 * Performs phases import
 		 *
 		 * @param SimpleXMLElement $phrases
 		 * @param int $language_id
 		 * @param string $language_encoding
 		 */
 		function _processPhrases($phrases, $language_id, $language_encoding)
 		{
 			static $other_translations = Array ();
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->Application->Debugger->profileStart('L[' . $language_id . ']P', 'Language: ' . $language_id . '; Phrases Import');
 			}
 
 			foreach ($phrases as $phrase_node) {
 				/* @var $phrase_node SimpleXMLElement */
 
 				$phrase_key = mb_strtoupper($phrase_node['Label']);
 
 				$fields_hash = Array (
 					'Phrase' => (string)$phrase_node['Label'],
 					'PhraseKey' => $phrase_key,
 					'PhraseType' => (int)$phrase_node['Type'],
 					'Module' => (string)$phrase_node['Module'] ? (string)$phrase_node['Module'] : 'Core',
 					'LastChanged' => TIMENOW,
 					'LastChangeIP' => $this->ip_address,
 				);
 
 				$translation = (string)$phrase_node;
 				$hint_translation = (string)$phrase_node['Hint'];
 				$column_translation = (string)$phrase_node['Column'];
 
 				if ( array_key_exists($fields_hash['PhraseType'], $this->phrase_types_allowed) ) {
 					if ( $language_encoding != 'plain' ) {
 						$translation = base64_decode($translation);
 						$hint_translation = base64_decode($hint_translation);
 						$column_translation = base64_decode($column_translation);
 					}
 
 					if ( array_key_exists($phrase_key, $other_translations) ) {
 						$other_translations[$phrase_key]['l' . $language_id . '_Translation'] = $translation;
 						$other_translations[$phrase_key]['l' . $language_id . '_HintTranslation'] = $hint_translation;
 						$other_translations[$phrase_key]['l' . $language_id . '_ColumnTranslation'] = $column_translation;
 					}
 					else {
 						$other_translations[$phrase_key] = Array (
 							'l' . $language_id . '_Translation' => $translation,
 							'l' . $language_id . '_HintTranslation' => $hint_translation,
 							'l' . $language_id . '_ColumnTranslation' => $column_translation,
 						);
 					}
 
 					$fields_hash = array_merge($fields_hash, $other_translations[$phrase_key]);
 					$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'REPLACE', false);
 				}
 			}
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->Application->Debugger->profileFinish('L[' . $language_id . ']P', 'Language: ' . $language_id . '; Phrases Import');
 			}
 
 			$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'REPLACE');
 		}
 
 		/**
 		 * Performs email event import
 		 *
 		 * @param SimpleXMLElement $events
 		 * @param int $language_id
 		 * @param string $language_encoding
 		 */
 		function _processEvents($events, $language_id, $language_encoding)
 		{
 			static $other_translations = Array ();
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->Application->Debugger->profileStart('L[' . $language_id . ']E', 'Language: ' . $language_id . '; Events Import');
 			}
 
 			$email_message_helper = $this->Application->recallObject('kEmailMessageHelper');
 			/* @var $email_message_helper kEmailMessageHelper */
 
 			foreach ($events as $event_node) {
 				/* @var $event_node SimpleXMLElement */
 
 				$message_type = (string)$event_node['MessageType'];
 				$event_id = $this->_getEventId((string)$event_node['Event'], (int)$event_node['Type']);
 
 				if ( !$event_id ) {
 					continue;
 				}
 
 				$fields_hash = Array (
 					'EventId' => $event_id,
 					'Event' => (string)$event_node['Event'],
 					'Type' => (int)$event_node['Type'],
 				);
 
 				if ( $message_type == '' ) {
 					$parsed = $email_message_helper->parseTemplate($event_node, '');
 					$parsed = array_map($language_encoding == 'plain' ? 'rtrim' : 'base64_decode', $parsed);
 
 				}
 				else {
 					$template = $language_encoding == 'plain' ? rtrim($event_node) : base64_decode($event_node);
 					$parsed = $email_message_helper->parseTemplate($template, $message_type);
 				}
 
 				if ( array_key_exists($event_id, $other_translations) ) {
 					$other_translations[$event_id]['l' . $language_id . '_Subject'] = $parsed['Subject'];
 					$other_translations[$event_id]['l' . $language_id . '_HtmlBody'] = $parsed['HtmlBody'];
 					$other_translations[$event_id]['l' . $language_id . '_PlainTextBody'] = $parsed['PlainTextBody'];
 				}
 				else {
 					$other_translations[$event_id] = Array (
 						'l' . $language_id . '_Subject' => $parsed['Subject'],
 						'l' . $language_id . '_HtmlBody' => $parsed['HtmlBody'],
 						'l' . $language_id . '_PlainTextBody' => $parsed['PlainTextBody'],
 					);
 				}
 
 				if ( $parsed['Headers'] ) {
 					$other_translations[$event_id]['Headers'] = $parsed['Headers'];
 				}
 				elseif ( !$parsed['Headers'] && !array_key_exists('Headers', $other_translations[$event_id]) ) {
 					$other_translations[$event_id]['Headers'] = $parsed['Headers'];
 				}
 
 				$fields_hash = array_merge($fields_hash, $other_translations[$event_id]);
 				$this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE', false);
 			}
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->Application->Debugger->profileFinish('L[' . $language_id . ']E', 'Language: ' . $language_id . '; Events Import');
 			}
 
 			if ( isset($fields_hash) ) {
 				// at least one email event in language pack was found in database
 				$this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE');
 			}
 		}
 
 		/**
 		 * Performs country_state translation import
 		 *
 		 * @param SimpleXMLElement $country_states
 		 * @param int $language_id
 		 * @param string $language_encoding
 		 * @param bool $process_states
 		 * @return void
 		 */
 		function _processCountries($country_states, $language_id, $language_encoding, $process_states = false)
 		{
 			static $other_translations = Array ();
 
 			foreach ($country_states as $country_state_node) {
 				/* @var $country_state_node SimpleXMLElement */
 
 				if ( $process_states ) {
 					$country_state_id = $this->_getStateId((string)$country_states['Iso'], (string)$country_state_node['Iso']);
 				}
 				else {
 					$country_state_id = $this->_getCountryId((string)$country_state_node['Iso']);
 				}
 
 				if ( !$country_state_id ) {
 					continue;
 				}
 
 				if ( $language_encoding == 'plain' ) {
 					$translation = rtrim($country_state_node['Translation']);
 				}
 				else {
 					$translation = base64_decode($country_state_node['Translation']);
 				}
 
 				$fields_hash = Array ('CountryStateId' => $country_state_id);
 
 				if ( array_key_exists($country_state_id, $other_translations) ) {
 					$other_translations[$country_state_id]['l' . $language_id . '_Name'] = $translation;
 				}
 				else {
 					$other_translations[$country_state_id] = Array ('l' . $language_id . '_Name' => $translation);
 				}
 
 				$fields_hash = array_merge($fields_hash, $other_translations[$country_state_id]);
 				$this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE', false);
 
 				// PHP 5.3 version would be: $country_state_node->count()
 				if ( !$process_states && count($country_state_node->children()) ) {
 					$this->_processCountries($country_state_node, $language_id, $language_encoding, true);
 				}
 			}
 
 			$this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE');
 		}
 
 		/**
 		 * Creates/updates language based on given fields and returns it's id
 		 *
 		 * @param Array $fields_hash
 		 * @return int
 		 */
 		function _processLanguage($fields_hash)
 		{
 			// 1. get language from database
 			$sql = 'SELECT ' . $this->lang_object->IDField . '
 					FROM ' . $this->lang_object->TableName . '
 					WHERE PackName = ' . $this->Conn->qstr($fields_hash['PackName']);
 			$language_id = $this->Conn->GetOne($sql);
 
 			if ($language_id) {
 				// 2. language found -> update, when allowed
 				$this->lang_object->Load($language_id);
 
 				if ($this->import_mode == LANG_OVERWRITE_EXISTING) {
 					// update live language record based on data from xml
 					$this->lang_object->SetFieldsFromHash($fields_hash);
 					$this->lang_object->Update();
 				}
 			}
 			else {
 				// 3. language not found -> create
 				$this->lang_object->SetFieldsFromHash($fields_hash);
 				$this->lang_object->SetDBField('Enabled', STATUS_ACTIVE);
 
 				if ($this->lang_object->Create()) {
 					$language_id = $this->lang_object->GetID();
 
 					if (defined('IS_INSTALL') && IS_INSTALL) {
 						// language created during install becomes admin interface language
 						$this->lang_object->setPrimary(true, true);
 					}
 				}
 			}
 
 			// 4. collect ID of every processed language
 			if (!in_array($language_id, $this->_languages)) {
 				$this->_languages[] = $language_id;
 			}
 
 			return $language_id;
 		}
 
 		/**
 		 * Returns event id based on it's name and type
 		 *
 		 * @param string $event_name
 		 * @param string $event_type
 		 * @return int
 		 */
 		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;
 		}
 
 		/**
 		 * Returns country id based on it's 3letter ISO code
 		 *
 		 * @param string $iso
 		 * @return int
 		 */
 		function _getCountryId($iso)
 		{
 			static $cache = null;
 
 			if (!isset($cache)) {
 				$sql = 'SELECT CountryStateId, IsoCode
 						FROM ' . TABLE_PREFIX . 'CountryStates
 						WHERE Type = ' . DESTINATION_TYPE_COUNTRY;
 				$cache = $this->Conn->GetCol($sql, 'IsoCode');
 			}
 
 			return array_key_exists($iso, $cache) ? $cache[$iso] : false;
 		}
 
 		/**
 		 * Returns state id based on 3letter country ISO code and 2letter state ISO code
 		 *
 		 * @param string $country_iso
 		 * @param string $state_iso
 		 * @return int
 		 */
 		function _getStateId($country_iso, $state_iso)
 		{
 			static $cache = null;
 
 			if (!isset($cache)) {
 				$sql = 'SELECT CountryStateId, CONCAT(StateCountryId, "-", IsoCode) AS IsoCode
 						FROM ' . TABLE_PREFIX . 'CountryStates
 						WHERE Type = ' . DESTINATION_TYPE_STATE;
 				$cache = $this->Conn->GetCol($sql, 'IsoCode');
 			}
 
 			$country_id = $this->_getCountryId($country_iso);
 
 			return array_key_exists($country_id . '-' . $state_iso, $cache) ? $cache[$country_id . '-' . $state_iso] : false;
 		}
 
 		/**
 		 * Returns comma-separated list of IDs, that will be exported
 		 *
 		 * @param string $prefix
 		 * @return string
 		 * @access public
 		 */
 		public function getExportIDs($prefix)
 		{
 			$ids = $this->Application->RecallVar($prefix . '_selected_ids');
 
 			if ( $ids ) {
 				// some records were selected in grid
 				return $ids;
 			}
 
 			$tag_params = Array (
 				'grid' => $prefix == 'phrases' ? 'Phrases' : 'Emails',
 				'skip_counting' => 1,
 				'per_page' => -1
 			);
 
 			$list = $this->Application->recallObject($prefix, $prefix . '_List', $tag_params);
 			/* @var $list kDBList */
 
 			$sql = $list->getCountSQL($list->GetSelectSQL());
 			$sql = str_replace('COUNT(*) AS count', $list->TableName . '.' . $list->IDField, $sql);
 
 			$ids = '';
 			$rs = $this->Conn->QueryRaw($sql);
 
 			if ( $this->Conn->RowCount($rs) ) {
 				while ( ($row = $this->Conn->GetNextRow($rs)) ) {
 					$ids .= ',' . $row[$list->IDField];
 				}
 
 				$ids = substr($ids, 1);
 			}
 
 			$this->Conn->Destroy($rs);
 
 			return $ids;
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/core/units/languages/languages_config.php
===================================================================
--- branches/5.2.x/core/units/languages/languages_config.php	(revision 15237)
+++ branches/5.2.x/core/units/languages/languages_config.php	(revision 15238)
@@ -1,273 +1,273 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'lang',
 	'ItemClass' => Array ('class' => 'LanguagesItem', 'file' => 'languages_item.php', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'LanguagesEventHandler', 'file' => 'languages_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'LanguagesTagProcessor', 'file' => 'languages_tag_processor.php', 'build_event' => 'OnBuild'),
 
 	'AutoLoad' => true,
 	'Hooks' => Array (
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'lang',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array('OnSave', 'OnMassDelete'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnScheduleTopFrameReload',
 		),
 	),
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 		5 => 'mode',
 	),
 
 	'IDField' => 'LanguageId',
 
 	'StatusField' => Array ('Enabled', 'PrimaryLang'),	// field, that is affected by Approve/Decline events
 
 	'TitleField' => 'PackName',		// field, used in bluebar when editing existing item
 
 	'TitlePresets' => Array (
 		'default' => Array (
 			'new_status_labels' => Array ('lang' => '!la_title_Adding_Language!'),
 			'edit_status_labels' => Array ('lang' => '!la_title_Editing_Language!'),
 		),
 		'languages_list' =>	Array (
 			'prefixes' => Array ('lang_List'), 'format' => "!la_title_Configuration! - !la_title_LanguagePacks!",
 			'toolbar_buttons' => Array (
 				'new_item', 'edit', 'delete', 'export', 'import', 'setprimary', 'refresh', 'view', 'dbl-click'
 			),
 		),
 		'languages_edit_general' => Array ('prefixes' => Array ('lang'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_General!"),
 		'phrases_list' => Array (
 			'prefixes' => Array ('lang', 'phrases_List'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_Labels!"
 		),
 		'phrase_edit' => Array (
 			'prefixes' => Array ('phrases'),
 			'new_status_labels' => Array ('phrases' => '!la_title_Adding_Phrase!'),
 			'edit_status_labels' => Array ('phrases'	=>	'!la_title_Editing_Phrase!'),
 			'format' => "#phrases_status# '#phrases_titlefield#'",
 		),
 		'import_language' => Array (
 			'prefixes' => Array ('phrases.import'), 'format' => "!la_title_InstallLanguagePackStep1!",
 		),
 		'import_language_step2' => Array (
 			'prefixes' => Array ('phrases.import'), 'format' => "!la_title_InstallLanguagePackStep2!",
 		),
 		'export_language' => Array (
 			'prefixes' => Array ('phrases.export'), 'format' => "!la_title_ExportLanguagePackStep1!",
 		),
 		'export_language_results' => Array (
 			'prefixes' => Array(), 'format' => "!la_title_ExportLanguagePackResults!",
 		),
 		'events_list' => Array (
 			'prefixes' => Array ('lang', 'emailevents_List'), 'format' => "#lang_status# '#lang_titlefield#' - !la_title_EmailEvents!",
 		),
 		'email_messages_edit' => Array (
 			'prefixes' => Array ('lang', 'emailevents'),
 			'format' => "#lang_status# '#lang_titlefield#' - !la_title_EditingEmailEvent! '#emailevents_titlefield#'",
 			'toolbar_buttons' => Array ('select', 'cancel', 'prev', 'next'),
 		),
 		// for separate language list
 		'languages_list_st' => Array (
 			'prefixes' => Array ('lang_List'), 'format' => "!la_title_LanguagesManagement!",
 		),
 	),
 
 	'EditTabPresets' => Array (
 		'Default' => Array (
 			'general' => Array ('title' => 'la_tab_General', 't' => 'regional/languages_edit', 'priority' => 1),
 			'labels' => Array ('title' => 'la_tab_Labels', 't' => 'regional/languages_edit_phrases', 'priority' => 2),
 			'email_events' => Array ('title' => 'la_tab_EmailEvents', 't' => 'regional/languages_edit_email_events', 'priority' => 3),
 		),
 	),
 
 	'PermSection' => Array ('main' => 'in-portal:configure_lang'),
 
 	'Sections' => Array (
 		'in-portal:configure_lang' => Array (
 			'parent' => 'in-portal:website_setting_folder',
 			'icon' => 'conf_regional',
 			'label' => 'la_tab_Regional',
 			'url' => Array ('t' => 'regional/languages_list', 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit', 'delete', 'advanced:set_primary', 'advanced:import', 'advanced:export'),
 			'priority' => 4,
 			'type' => stTREE,
 		),
 
 		// "Lang. Management"
 		/*'in-portal:lang_management' => Array (
 			'parent' => 'in-portal:system',
 			'icon'			=>	'core:settings_general',
 			'label'			=>	'la_title_LangManagement',
 			'url'			=>	Array ('t' => 'languages/language_list', 'pass' => 'm'),
 			'permissions'	=>	Array ('view', 'add', 'edit', 'delete'),
 			'perm_prefix'	=>	'lang',
 			'priority'		=>	10.03,
 			'show_mode'		=>	smSUPER_ADMIN,
 			'type'			=>	stTREE,
 		),*/
 	),
 
 	'TableName' => TABLE_PREFIX . 'Languages',
 
 	'AutoDelete' => true,
 	'AutoClone' => true,
 
 	'ListSQLs' => Array ('' => 'SELECT * FROM %s'),
 	'ItemSQLs' => Array ('' => 'SELECT * FROM %s'),
 
 	'ListSortings' => Array (
 		'' => Array (
 			'Sorting' => Array ('Priority' => 'desc', 'PackName' => 'asc'),
 		),
 	),
 
 	'Fields' => Array (
 		'LanguageId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'PackName' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'PackName',
 			'not_null' => 1, 'required' => 1, 'default' => ''
 		),
 		'LocalName' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'LocalName', 'option_key_field' => 'LocalName',
 			'not_null' => 1, 'required' => 1, 'default' => ''
 		),
 		'Enabled' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_Disabled', 1 => 'la_Active'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 1
 		),
 		'PrimaryLang' => Array(
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0
 		),
 		'AdminInterfaceLang' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0
 		),
 		'Priority' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'IconURL' => Array ('type' => 'string', 'max_len' => 255, 'default' => NULL),
 		'IconDisabledURL' => Array ('type' => 'string', 'max_len' => 255, 'default' => NULL),
 		'InputDateFormat' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array ('m/d/Y' => 'mm/dd/yyyy', 'd/m/Y' => 'dd/mm/yyyy', 'm.d.Y' => 'mm.dd.yyyy', 'd.m.Y' => 'dd.mm.yyyy'),
 			'not_null' => 1, 'required' => 1, 'default' => 'm/d/Y'
 		),
 		'InputTimeFormat' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array ('g:i:s A' => 'g:i:s A', 'g:i A' => 'g:i A', 'H:i:s' => 'H:i:s', 'H:i' => 'H:i'),
 			'not_null' => '1', 'required' => 1, 'default' => 'g:i:s A',
 		),
 		'DateFormat' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => 'm/d/Y'),
 		'TimeFormat' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => 'g:i:s A'),
 		'DecimalPoint' => Array ('type' => 'string', 'not_null' => 1, 'required' => 1, 'default' => '.'),
 		'ThousandSep' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'Charset' => Array ('type' => 'string', 'not_null' => '1', 'required' => 1, 'default' => 'utf-8'),
 		'UnitSystem' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Metric', 2 => 'la_US_UK'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 1
 		),
 		'FilenameReplacements' => Array ('type' => 'string', 'default' => NULL),
 		'Locale' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter',
 			'options_sql' => "	SELECT CONCAT(LocaleName, ' ' ,'\/',Locale,'\/') AS Name, Locale
 								FROM " . TABLE_PREFIX . 'LocalesList
 								ORDER BY LocaleId',
 			'option_title_field' => 'Name', 'option_key_field' => 'Locale',
 		 	'not_null' => 1, 'default' => 'en-US',
 		),
 		'UserDocsUrl' => Array ('type' => 'string', 'max_len' => 255, 'not_null' => 1, 'default' => ''),
 		'SynchronizationModes' => Array (
 			'type' => 'string', 'max_len' => 255,
 			'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_opt_SynchronizeToOthers', 2 => 'la_opt_SynchronizeFromOthers'), 'use_phrases' => 1, 'multiple' => 1,
 			'not_null' => 1, 'default' => ''
 		),
 		'HtmlEmailTemplate' => Array (
 			'type' => 'string',
 			'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!', 'body_missing' => '!la_error_EmailTemplateBodyMissing!'),
-			'default' => NULL
+			'default' => '$body'
 		),
 		'TextEmailTemplate' => Array (
 			'type' => 'string',
 			'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!', 'body_missing' => '!la_error_EmailTemplateBodyMissing!'),
 			'default' => NULL
 		),
 	),
 
 	'VirtualFields'	=> Array (
 		'CopyLabels' => Array ('type' => 'int', 'default' => 0),
 		'CopyFromLanguage' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Languages ORDER BY PackName', 'option_title_field' => 'PackName', 'option_key_field' => 'LanguageId',
 			'default' => '',
 		),
 	),
 
 	'Grids'	=> Array(
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				'0_0' => 'icon16_disabled.png',
 				'0_1' => 'icon16_disabled.png',
 				'1_0' => 'icon16_item.png',
 				'1_1' => 'icon16_primary.png',
 			),
 			'Fields' => Array(
 				'LanguageId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 50, ),
 				'PackName' => Array ('filter_block' => 'grid_options_filter', 'width' => 150, ),//
 				'PrimaryLang' => Array ('title' => 'la_col_IsPrimaryLanguage', 'filter_block' => 'grid_options_filter', 'width' => 150, ),
 				'AdminInterfaceLang' => Array ('filter_block' => 'grid_options_filter', 'width' => 150, ),
 				'Charset' => Array ('filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Priority' => Array ('filter_block' => 'grid_like_filter', 'width' => 60, ),
 				'Enabled' => Array ('filter_block' => 'grid_options_filter', 'width' => 80, ),
 				'SynchronizationModes' => Array ('filter_block' => 'grid_picker_filter', 'width' => 120, 'format' => ', ', 'hidden' => 1),
 			),
 		),
 
 		/*'LangManagement' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				'0_0' => 'icon16_disabled.png',
 				'0_1' => 'icon16_disabled.png',
 				'1_0' => 'icon16_item.png',
 				'1_1' => 'icon16_primary.png',
 			),
 			'Fields' => Array (
 				'LanguageId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60),
 				'PackName' => Array ('title' => 'column:la_fld_Language', 'filter_block' => 'grid_options_filter', 'width' => 120),
 				'LocalName' => Array ('title' => 'column:la_fld_Prefix', 'filter_block' => 'grid_options_filter', 'width' => 120),
 				'IconURL' => Array ('title' => 'column:la_fld_Image', 'filter_block' => 'grid_empty_filter', 'width' => 80),
 			),
 		),*/
 	),
 );
\ No newline at end of file
Index: branches/5.2.x/core/units/languages/languages_event_handler.php
===================================================================
--- branches/5.2.x/core/units/languages/languages_event_handler.php	(revision 15237)
+++ branches/5.2.x/core/units/languages/languages_event_handler.php	(revision 15238)
@@ -1,790 +1,789 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class LanguagesEventHandler extends kDBEventHandler
 	{
 		/**
 		 * Allows to override standard permission mapping
 		 *
 		 * @return void
 		 * @access protected
 		 * @see kEventHandler::$permMapping
 		 */
 		protected function mapPermissions()
 		{
 			parent::mapPermissions();
 
 			$permissions = Array (
 				'OnChangeLanguage' => Array ('self' => true),
 				'OnSetPrimary' => Array ('self' => 'advanced:set_primary|add|edit'),
 				'OnImportLanguage' => Array ('self' => 'advanced:import'),
 				'OnExportLanguage' => Array ('self' => 'advanced:export'),
 				'OnExportProgress' => Array ('self' => 'advanced:export'),
 				'OnReflectMultiLingualFields' => Array ('self' => 'view'),
 				'OnSynchronizeLanguages' => Array ('self' => 'edit'),
 			);
 
 			$this->permMapping = array_merge($this->permMapping, $permissions);
 		}
 
 		/**
 		 * Checks user permission to execute given $event
 		 *
 		 * @param kEvent $event
 		 * @return bool
 		 * @access public
 		 */
 		public function CheckPermission(kEvent $event)
 		{
 			if ( $event->Name == 'OnItemBuild' ) {
 				// check permission without using $event->getSection(),
 				// so first cache rebuild won't lead to "ldefault_Name" field being used
 				return true;
 			}
 
 			return parent::CheckPermission($event);
 		}
 
 		/**
 		 * Allows to get primary language object
 		 *
 		 * @param kEvent $event
 		 * @return int
 		 * @access public
 		 */
 		public function getPassedID(kEvent $event)
 		{
 			if ( $event->Special == 'primary' ) {
 				return $this->Application->GetDefaultLanguageId();
 			}
 
 			return parent::getPassedID($event);
 		}
 
 		/**
 		 * [HOOK] Updates table structure on new language adding/removing language
 		 *
 		 * @param kEvent $event
 		 */
 		function OnReflectMultiLingualFields($event)
 		{
 			if ($this->Application->GetVar('ajax') == 'yes') {
 				$event->status = kEvent::erSTOP;
 			}
 
 			if (is_object($event->MasterEvent)) {
 				if ($event->MasterEvent->status != kEvent::erSUCCESS) {
 					// only rebuild when all fields are validated
 					return ;
 				}
 
 				if (($event->MasterEvent->Name == 'OnSave') && !$this->Application->GetVar('new_language')) {
 					// only rebuild during new language adding
 					return ;
 				}
 			}
 
 			$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
 			/* @var $ml_helper kMultiLanguageHelper */
 
 			$ml_helper->massCreateFields();
 			$event->SetRedirectParam('action_completed', 1);
 		}
 
 		/**
 		 * Allows to set selected language as primary
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSetPrimary($event)
 		{
 			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$this->StoreSelectedIDs($event);
 			$ids = $this->getSelectedIDs($event);
 			if ($ids) {
 				$id = array_shift($ids);
 				$object = $event->getObject( Array('skip_autoload' => true) );
 				/* @var $object LanguagesItem */
 
 				$object->Load($id);
 				$object->copyMissingData( $object->setPrimary() );
 			}
 		}
 
 		/**
 		 * [HOOK] Reset primary status of other languages if we are saving primary language
 		 *
 		 * @param kEvent $event
 		 */
 		function OnUpdatePrimary($event)
 		{
 			if ($event->MasterEvent->status != kEvent::erSUCCESS) {
 				return ;
 			}
 
 			$object = $event->getObject( Array('skip_autoload' => true) );
 			/* @var $object LanguagesItem */
 
 			$object->SwitchToLive();
 
 			// set primary for each languages, that have this checkbox checked
 			$ids = explode(',', $event->MasterEvent->getEventParam('ids'));
 			foreach ($ids as $id) {
 				$object->Load($id);
 				if ($object->GetDBField('PrimaryLang')) {
 					$object->copyMissingData( $object->setPrimary(true, false) );
 				}
 
 				if ($object->GetDBField('AdminInterfaceLang')) {
 					$object->setPrimary(true, true);
 				}
 			}
 
 			// if no primary language left, then set primary last language (not to load again) from edited list
 			$sql = 'SELECT '.$object->IDField.'
 					FROM '.$object->TableName.'
 					WHERE PrimaryLang = 1';
 			$primary_language = $this->Conn->GetOne($sql);
 
 			if (!$primary_language) {
 				$object->setPrimary(false, false); // set primary language
 			}
 
 			$sql = 'SELECT '.$object->IDField.'
 					FROM '.$object->TableName.'
 					WHERE AdminInterfaceLang = 1';
 			$primary_language = $this->Conn->GetOne($sql);
 
 			if (!$primary_language) {
 				$object->setPrimary(false, true); // set admin interface language
 			}
 		}
 
 		/**
 		 * Prefills options with dynamic values
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterConfigRead(kEvent $event)
 		{
 			parent::OnAfterConfigRead($event);
 
 			$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
 
 			// set dynamic hints for options in date format fields
 			$options = $fields['InputDateFormat']['options'];
 			if ($options) {
 				foreach ($options as $i => $v) {
 					$options[$i] = $v . ' (' . adodb_date($i) . ')';
 				}
 				$fields['InputDateFormat']['options'] = $options;
 			}
 
 			$options = $fields['InputTimeFormat']['options'];
 			if ($options) {
 				foreach ($options as $i => $v) {
 					$options[$i] = $v . ' (' . adodb_date($i) . ')';
 				}
 				$fields['InputTimeFormat']['options'] = $options;
 			}
 
 			$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
 		}
 
 		/**
 		 * Occurs before creating item
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemCreate(kEvent $event)
 		{
 			parent::OnBeforeItemCreate($event);
 
 			$this->_itemChanged($event);
 		}
 
 		/**
 		 * Occurs before updating item
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemUpdate(kEvent $event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$status_fields = $this->Application->getUnitOption($event->Prefix, 'StatusField');
 			$status_field = array_shift($status_fields);
 
 			if ( $object->GetDBField('PrimaryLang') == 1 && $object->GetDBField($status_field) == 0 ) {
 				$object->SetDBField($status_field, 1);
 			}
 
 			$this->_itemChanged($event);
 		}
 
 
 		/**
 		 * Dynamically changes required fields
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function _itemChanged(kEvent $event)
 		{
 			$this->setRequired($event);
 		}
 
 		/**
 		 * Dynamically changes required fields
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemValidate(kEvent $event)
 		{
 			parent::OnBeforeItemValidate($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$email_message_helper = $this->Application->recallObject('kEmailMessageHelper');
 			/* @var $email_message_helper kEmailMessageHelper */
 
 			$email_message_helper->parseField($object, 'HtmlEmailTemplate');
 			$email_message_helper->parseField($object, 'TextEmailTemplate');
 
 			$check_field = $object->GetDBField('TextEmailTemplate') ? 'TextEmailTemplate' : 'HtmlEmailTemplate';
 			$check_value = $object->GetDBField($check_field);
 
 			if ( $check_value && strpos($check_value, '$body') === false ) {
 				$object->SetError($check_field, 'body_missing');
 			}
 		}
 
 		/**
 		 * Dynamically changes required fields
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function setRequired(kEvent $event)
 		{
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$object->setRequired('HtmlEmailTemplate', !$object->GetDBField('TextEmailTemplate'));
 			$object->setRequired('TextEmailTemplate', !$object->GetDBField('HtmlEmailTemplate'));
 		}
 
 		/**
 		 * Shows only enabled languages on front
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 * @see kDBEventHandler::OnListBuild()
 		 */
 		protected function SetCustomQuery(kEvent $event)
 		{
 			parent::SetCustomQuery($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBList */
 
 			if ( in_array($event->Special, Array ('enabled', 'selected', 'available')) ) {
 				$object->addFilter('enabled_filter', '%1$s.Enabled = ' . STATUS_ACTIVE);
 			}
 
 			// site domain language picker
 			if ( $event->Special == 'selected' || $event->Special == 'available' ) {
 				$edit_picker_helper = $this->Application->recallObject('EditPickerHelper');
 				/* @var $edit_picker_helper EditPickerHelper */
 
 				$edit_picker_helper->applyFilter($event, 'Languages');
 			}
 
 			// apply domain-based language filtering
 			$languages = $this->Application->siteDomainField('Languages');
 
 			if ( strlen($languages) ) {
 				$languages = explode('|', substr($languages, 1, -1));
 				$object->addFilter('domain_filter', '%1$s.LanguageId IN (' . implode(',', $languages) . ')');
 			}
 		}
 
 		/**
 		 * Copy labels from another language
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterItemCreate(kEvent $event)
 		{
 			parent::OnAfterItemCreate($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$src_language = $object->GetDBField('CopyFromLanguage');
 
 			if ( $object->GetDBField('CopyLabels') && $src_language ) {
 				$dst_language = $object->GetID();
 
 				// 1. schedule data copy after OnSave event is executed
 				$var_name = $event->getPrefixSpecial() . '_copy_data' . $this->Application->GetVar('m_wid');
 				$pending_actions = $this->Application->RecallVar($var_name, Array ());
 
 				if ( $pending_actions ) {
 					$pending_actions = unserialize($pending_actions);
 				}
 
 				$pending_actions[$src_language] = $dst_language;
 				$this->Application->StoreVar($var_name, serialize($pending_actions));
 				$object->SetDBField('CopyLabels', 0);
 			}
 		}
 
 		/**
 		 * Saves language from temp table to live
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnSave(kEvent $event)
 		{
 			parent::OnSave($event);
 
 			if ( $event->status != kEvent::erSUCCESS ) {
 				return;
 			}
 
 			$var_name = $event->getPrefixSpecial() . '_copy_data' . $this->Application->GetVar('m_wid');
 			$pending_actions = $this->Application->RecallVar($var_name, Array ());
 
 			if ( $pending_actions ) {
 				$pending_actions = unserialize($pending_actions);
 			}
 
 			// create multilingual columns for phrases & email events table first (actual for 6+ language)
 			$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
 			/* @var $ml_helper kMultiLanguageHelper */
 
 			$ml_helper->createFields('phrases');
 			$ml_helper->createFields('emailevents');
 
 			foreach ($pending_actions as $src_language => $dst_language) {
 				// phrases import
 				$sql = 'UPDATE ' . $this->Application->getUnitOption('phrases', 'TableName') . '
 						SET l' . $dst_language . '_Translation = l' . $src_language . '_Translation';
 				$this->Conn->Query($sql);
 
 				// events import
 				$sql = 'UPDATE ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
 						SET
 							l' . $dst_language . '_Subject = l' . $src_language . '_Subject,
 							l' . $dst_language . '_HtmlBody = l' . $src_language . '_HtmlBody,
 							l' . $dst_language . '_PlainTextBody = l' . $src_language . '_PlainTextBody';
 				$this->Conn->Query($sql);
 			}
 
 			$this->Application->RemoveVar($var_name);
 
 			$event->CallSubEvent('OnReflectMultiLingualFields');
 			$event->CallSubEvent('OnUpdatePrimary');
 		}
 
 		/**
 		 * Prepare temp tables for creating new item
 		 * but does not create it. Actual create is
 		 * done in OnPreSaveCreated
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnPreCreate(kEvent $event)
 		{
 			parent::OnPreCreate($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$object->SetDBField('CopyLabels', 1);
 
 			$sql = 'SELECT ' . $object->IDField . '
 					FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 					WHERE PrimaryLang = 1';
 			$primary_lang_id = $this->Conn->GetOne($sql);
 
 			$object->SetDBField('CopyFromLanguage', $primary_lang_id);
 			$object->SetDBField('SynchronizationModes', Language::SYNCHRONIZE_DEFAULT);
-			$object->SetDBField('HtmlEmailTemplate', '$body');
 
 			$this->setRequired($event);
 		}
 
 		/**
 		 * Sets dynamic required fields
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterItemLoad(kEvent $event)
 		{
 			parent::OnAfterItemLoad($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$this->setRequired($event);
 		}
 		/**
 		 * Sets new language mark
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeDeleteFromLive(kEvent $event)
 		{
 			parent::OnBeforeDeleteFromLive($event);
 
 			$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
 
 			$sql = 'SELECT ' . $id_field . '
 					FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 					WHERE ' . $id_field . ' = ' . $event->getEventParam('id');
 			$id = $this->Conn->GetOne($sql);
 
 			if ( !$id ) {
 				$this->Application->SetVar('new_language', 1);
 			}
 		}
 
 		function OnChangeLanguage($event)
 		{
 			$language_id = $this->Application->GetVar('language');
 			$language_field = $this->Application->isAdmin ? 'AdminLanguage' : 'FrontLanguage';
 
 			$this->Application->SetVar('m_lang', $language_id);
 
 			// set new language for this session
 			$this->Application->Session->SetField('Language', $language_id);
 
 			// remember last user language
 			if ($this->Application->RecallVar('user_id') == USER_ROOT) {
 				$this->Application->StorePersistentVar($language_field, $language_id);
 			}
 			else {
 				$object = $this->Application->recallObject('u.current');
 				/* @var $object kDBItem */
 
 				$object->SetDBField($language_field, $language_id);
 				$object->Update();
 			}
 
 			// without this language change in admin will cause erase of last remembered tree section
 			$this->Application->SetVar('skip_last_template', 1);
 		}
 
 		/**
 		 * Parse language XML file into temp tables and redirect to progress bar screen
 		 *
 		 * @param kEvent $event
 		 */
 		function OnImportLanguage($event)
 		{
 			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$items_info = $this->Application->GetVar('phrases_import');
 			if ($items_info) {
 				list ($id, $field_values) = each($items_info);
 
 				$object = $this->Application->recallObject('phrases.import', 'phrases', Array('skip_autoload' => true));
 				/* @var $object kDBItem */
 
 				$object->setID($id);
 				$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 
 				if (!$object->Validate()) {
 					$event->status = kEvent::erFAIL;
 					return ;
 				}
 
 				$filename = $object->GetField('LangFile', 'full_path');
 
 				if (!filesize($filename)) {
 					$object->SetError('LangFile', 'la_empty_file', 'la_EmptyFile');
 					$event->status = kEvent::erFAIL;
 				}
 
 				$language_import_helper = $this->Application->recallObject('LanguageImportHelper');
 				/* @var $language_import_helper LanguageImportHelper */
 
 				$language_import_helper->performImport(
 					$filename,
 					$object->GetDBField('PhraseType'),
 					$object->GetDBField('Module'),
 					$object->GetDBField('ImportOverwrite') ? LANG_OVERWRITE_EXISTING : LANG_SKIP_EXISTING
 				);
 
 				// delete uploaded language pack after import is finished
 				unlink($filename);
 
 				$event->SetRedirectParam('opener', 'u');
 			}
 		}
 
 		/**
 		 * Stores ids of selected languages and redirects to export language step 1
 		 *
 		 * @param kEvent $event
 		 */
 		function OnExportLanguage($event)
 		{
 			if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$this->Application->setUnitOption('phrases', 'AutoLoad', false);
 
 			$this->StoreSelectedIDs($event);
 			$this->Application->StoreVar('export_language_ids', implode(',', $this->getSelectedIDs($event)));
 
 			$event->setRedirectParams(
 				Array (
 					'phrases.export_event' => 'OnNew',
 					'pass' => 'all,phrases.export',
 					'export_mode' => $event->Prefix,
 				)
 			);
 		}
 
 		/**
 		 * Saves selected languages to xml file passed
 		 *
 		 * @param kEvent $event
 		 */
 		function OnExportProgress($event)
 		{
 			$items_info = $this->Application->GetVar('phrases_export');
 			if ( $items_info ) {
 				list($id, $field_values) = each($items_info);
 				$object = $this->Application->recallObject('phrases.export', null, Array ('skip_autoload' => true));
 				/* @var $object kDBItem */
 
 				$object->setID($id);
 				$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 
 				if ( !$object->Validate() ) {
 					$event->status = kEvent::erFAIL;
 					return;
 				}
 
 				$file_helper = $this->Application->recallObject('FileHelper');
 				/* @var $file_helper FileHelper */
 
 				$file_helper->CheckFolder(EXPORT_PATH);
 
 				if ( !is_writable(EXPORT_PATH) ) {
 					$event->status = kEvent::erFAIL;
 					$object->SetError('LangFile', 'write_error', 'la_ExportFolderNotWritable');
 
 					return;
 				}
 
 				if ( substr($field_values['LangFile'], -5) != '.lang' ) {
 					$field_values['LangFile'] .= '.lang';
 				}
 
 				$filename = EXPORT_PATH . '/' . $field_values['LangFile'];
 
 				$language_import_helper = $this->Application->recallObject('LanguageImportHelper');
 				/* @var $language_import_helper LanguageImportHelper */
 
 				if ( $object->GetDBField('DoNotEncode') ) {
 					$language_import_helper->setExportEncoding('plain');
 				}
 
 				$data_types = Array (
 					'phrases' => 'ExportPhrases',
 					'emailevents' => 'ExportEmailEvents',
 					'country-state' => 'ExportCountries'
 				);
 
 				$export_mode = $this->Application->GetVar('export_mode');
 				$allowed_data_types = explode('|', substr($field_values['ExportDataTypes'], 1, -1));
 
 				if ( $export_mode == $event->Prefix ) {
 					foreach ($data_types as $prefix => $export_limit_field) {
 						$export_limit = in_array($prefix, $allowed_data_types) ? $field_values[$export_limit_field] : '-';
 						$language_import_helper->setExportLimit($prefix, $export_limit);
 					}
 				}
 				else {
 					foreach ($data_types as $prefix => $export_limit_field) {
 						$export_limit = in_array($prefix, $allowed_data_types) ? null : '-';
 						$language_import_helper->setExportLimit($prefix, $export_limit);
 					}
 				}
 
 				$lang_ids = explode(',', $this->Application->RecallVar('export_language_ids'));
 				$language_import_helper->performExport($filename, $field_values['PhraseType'], $lang_ids, $field_values['Module']);
 			}
 
 			$event->redirect = 'regional/languages_export_step2';
 			$event->SetRedirectParam('export_file', $field_values['LangFile']);
 		}
 
 		/**
 		 * Returns to previous template in opener stack
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnGoBack(kEvent $event)
 		{
 			$event->SetRedirectParam('opener', 'u');
 		}
 
 		function OnScheduleTopFrameReload($event)
 		{
 			$this->Application->StoreVar('RefreshTopFrame',1);
 		}
 
 		/**
 		 * Do now allow deleting current language
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemDelete(kEvent $event)
 		{
 			parent::OnBeforeItemDelete($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			if ( $object->GetDBField('PrimaryLang') || $object->GetDBField('AdminInterfaceLang') || $object->GetID() == $this->Application->GetVar('m_lang') ) {
 				$event->status = kEvent::erFAIL;
 			}
 		}
 
 		/**
 		 * Deletes phrases and email events on given language
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterItemDelete(kEvent $event)
 		{
 			parent::OnAfterItemDelete($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			// clean EmailEvents table
 			$fields_hash = Array (
 				'l' . $object->GetID() . '_Subject' => NULL,
 				'l' . $object->GetID() . '_HtmlBody' => NULL,
 				'l' . $object->GetID() . '_PlainTextBody' => NULL,
 			);
 			$this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('emailevents', 'TableName'), 1);
 
 			// clean Phrases table
 			$fields_hash = Array (
 				'l' . $object->GetID() . '_Translation' => NULL,
 				'l' . $object->GetID() . '_HintTranslation' => NULL,
 				'l' . $object->GetID() . '_ColumnTranslation' => NULL,
 			);
 			$this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('phrases', 'TableName'), 1);
 		}
 
 		/**
 		 * Copy missing phrases across all system languages (starting from primary)
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnSynchronizeLanguages($event)
 		{
 			if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$source_languages = $target_languages = Array ();
 
 			// get language list with primary language first
 			$sql = 'SELECT SynchronizationModes, LanguageId
 					FROM ' . TABLE_PREFIX . 'Languages
 					WHERE SynchronizationModes <> ""
 					ORDER BY PrimaryLang DESC';
 			$languages = $this->Conn->GetCol($sql, 'LanguageId');
 
 			foreach ($languages as $language_id => $synchronization_modes) {
 				$synchronization_modes = explode('|', substr($synchronization_modes, 1, -1));
 
 				if ( in_array(Language::SYNCHRONIZE_TO_OTHERS, $synchronization_modes) ) {
 					$source_languages[] = $language_id;
 				}
 
 				if ( in_array(Language::SYNCHRONIZE_FROM_OTHERS, $synchronization_modes) ) {
 					$target_languages[] = $language_id;
 				}
 			}
 
 			foreach ($source_languages as $source_id) {
 				foreach ($target_languages as $target_id) {
 					if ( $source_id == $target_id ) {
 						continue;
 					}
 
 					$sql = 'UPDATE ' . TABLE_PREFIX . 'LanguageLabels
 							SET l' . $target_id . '_Translation = l' . $source_id . '_Translation
 							WHERE COALESCE(l' . $target_id . '_Translation, "") = "" AND COALESCE(l' . $source_id . '_Translation, "") <> ""';
 					$this->Conn->Query($sql);
 				}
 			}
 		}
 	}
\ No newline at end of file