Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1198134
in-portal
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Oct 30, 8:19 AM
Size
73 KB
Mime Type
text/x-diff
Expires
Sat, Nov 1, 8:19 AM (12 h, 42 m)
Engine
blob
Format
Raw Data
Handle
781203
Attached To
rINP In-Portal
in-portal
View Options
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
Event Timeline
Log In to Comment