6 * @copyright (c) 2005 phpBB Group
7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
14 if (!defined('IN_PHPBB'))
26 var $language_header = '';
27 var $lang_header = '';
29 var $language_file = '';
30 var $language_directory = '';
32 function main($id, $mode)
34 global $db, $user, $auth, $template;
35 global $safe_mode, $file_uploads;
38 * @todo make this work with the request class, might require some additional functionality
39 * inside the request class. Reducing some of the redundance of this code would certainly
42 phpbb_request
::enable_super_globals();
44 include_once(PHPBB_ROOT_PATH
. 'includes/functions_user.' . PHP_EXT
);
46 $this->default_variables();
48 // Check and set some common vars
50 $action = (phpbb_request
::is_set_post('update_details')) ?
'update_details' : '';
51 $action = (phpbb_request
::is_set_post('download_file')) ?
'download_file' : $action;
52 $action = (phpbb_request
::is_set_post('upload_file')) ?
'upload_file' : $action;
53 $action = (phpbb_request
::is_set_post('upload_data')) ?
'upload_data' : $action;
54 $action = (phpbb_request
::is_set_post('submit_file')) ?
'submit_file' : $action;
55 $action = (phpbb_request
::is_set_post('remove_store')) ?
'details' : $action;
57 $submit = (empty($action) && !phpbb_request
::is_set_post('update') && !phpbb_request
::is_set_post('test_connection')) ?
false : true;
58 $action = (empty($action)) ?
request_var('action', '') : $action;
60 $form_name = 'acp_lang';
61 add_form_key('acp_lang');
63 $lang_id = request_var('id', 0);
64 if (phpbb_request
::is_set_post('missing_file'))
66 $missing_file = request_var('missing_file', array('' => 0));
68 * @todo Do NOT overwrite a request variable.
70 phpbb_request
::overwrite('language_file', key($missing_file));
73 $selected_lang_file = request_var('language_file', '|common.' . PHP_EXT
);
75 list($this->language_directory
, $this->language_file
) = explode('|', $selected_lang_file);
77 $this->language_directory
= basename($this->language_directory
);
78 $this->language_file
= basename($this->language_file
);
80 $user->add_lang('acp/language');
81 $this->tpl_name
= 'acp_language';
82 $this->page_title
= 'ACP_LANGUAGE_PACKS';
84 if ($submit && $action == 'upload_data' && request_var('test_connection', ''))
86 $test_connection = false;
87 $action = 'upload_file';
88 $method = request_var('method', '');
90 include_once(PHPBB_ROOT_PATH
. 'includes/functions_transfer.' . PHP_EXT
);
95 $transfer = new ftp(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
99 $transfer = new ftp_fsock(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
103 trigger_error($user->lang
['INVALID_UPLOAD_METHOD'], E_USER_ERROR
);
107 $test_connection = $transfer->open_session();
108 $transfer->close_session();
115 include_once(PHPBB_ROOT_PATH
. 'includes/functions_transfer.' . PHP_EXT
);
117 $method = request_var('method', '');
119 if (!class_exists($method))
121 trigger_error('Method does not exist.', E_USER_ERROR
);
124 $requested_data = call_user_func(array($method, 'data'));
125 foreach ($requested_data as $data => $default)
127 $default_value = request_var($data, '');
128 $template->assign_block_vars('data', array(
130 'NAME' => $user->lang
[strtoupper($method . '_' . $data)],
131 'EXPLAIN' => $user->lang
[strtoupper($method . '_' . $data) . '_EXPLAIN'],
132 'DEFAULT' => (empty($default_value)) ?
$default : $default_value
136 $hidden_data = build_hidden_fields(array(
137 'file' => $this->language_file
,
138 'dir' => $this->language_directory
,
139 'language_file' => $selected_lang_file,
144 * @todo Do not use $_POST here, but phpbb_request::variable which needs to support more dimensions
146 $hidden_data .= build_hidden_fields(array('entry' => $_POST['entry']), true, STRIP
);
148 $template->assign_vars(array(
151 'U_ACTION' => $this->u_action
. "&id=$lang_id&action=upload_data",
152 'U_BACK' => $this->u_action
. "&id=$lang_id&action=details&language_file=" . urlencode($selected_lang_file),
153 'HIDDEN' => $hidden_data,
155 'S_CONNECTION_SUCCESS' => (request_var('test_connection', '') && $test_connection === true) ?
true : false,
156 'S_CONNECTION_FAILED' => (request_var('test_connection', '') && $test_connection !== true) ?
true : false
160 case 'update_details':
162 if (!$submit ||
!check_form_key($form_name))
164 trigger_error($user->lang
['FORM_INVALID']. adm_back_link($this->u_action
), E_USER_WARNING
);
169 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
173 FROM ' . LANG_TABLE
. "
174 WHERE lang_id = $lang_id";
175 $result = $db->sql_query($sql);
176 $row = $db->sql_fetchrow($result);
177 $db->sql_freeresult($result);
180 'lang_english_name' => request_var('lang_english_name', $row['lang_english_name']),
181 'lang_local_name' => utf8_normalize_nfc(request_var('lang_local_name', $row['lang_local_name'], true)),
182 'lang_author' => utf8_normalize_nfc(request_var('lang_author', $row['lang_author'], true)),
185 $db->sql_query('UPDATE ' . LANG_TABLE
. '
186 SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
187 WHERE lang_id = ' . $lang_id);
189 add_log('admin', 'LOG_LANGUAGE_PACK_UPDATED', $sql_ary['lang_english_name']);
191 trigger_error($user->lang
['LANGUAGE_DETAILS_UPDATED'] . adm_back_link($this->u_action
));
195 case 'download_file':
198 if (!$submit ||
!check_form_key($form_name))
200 trigger_error($user->lang
['FORM_INVALID']. adm_back_link($this->u_action
), E_USER_WARNING
);
203 if (!$lang_id ||
empty($_POST['entry']))
205 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
208 if ($this->language_directory
!= 'email' && !is_array($_POST['entry']))
210 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
213 if (!$this->language_file ||
(!$this->language_directory
&& !in_array($this->language_file
, $this->main_files
)))
215 trigger_error($user->lang
['NO_FILE_SELECTED'] . adm_back_link($this->u_action
), E_USER_WARNING
);
219 FROM ' . LANG_TABLE
. "
220 WHERE lang_id = $lang_id";
221 $result = $db->sql_query($sql);
222 $row = $db->sql_fetchrow($result);
223 $db->sql_freeresult($result);
227 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
230 // Before we attempt to write anything let's check if the admin really chose a correct filename
231 switch ($this->language_directory
)
234 // Get email templates
235 $email_files = filelist(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'], 'email', 'txt');
236 $email_files = $email_files['email/'];
238 if (!in_array($this->language_file
, $email_files))
240 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
246 $acp_files = filelist(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'], 'acp', PHP_EXT
);
247 $acp_files = $acp_files['acp/'];
249 if (!in_array($this->language_file
, $acp_files))
251 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
257 $mods_files = filelist(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'], 'mods', PHP_EXT
);
258 $mods_files = (isset($mods_files['mods/'])) ?
$mods_files['mods/'] : array();
260 if (!in_array($this->language_file
, $mods_files))
262 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
267 if (!in_array($this->language_file
, $this->main_files
))
269 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
276 $mkdir_ary = array('language', 'language/' . $row['lang_iso']);
278 if ($this->language_directory
)
280 $mkdir_ary[] = 'language/' . $row['lang_iso'] . '/' . $this->language_directory
;
283 foreach ($mkdir_ary as $dir)
285 $dir = PHPBB_ROOT_PATH
. 'store/' . $dir;
289 if (!@mkdir
($dir, 0777))
291 trigger_error("Could not create directory $dir", E_USER_ERROR
);
293 phpbb
::$system->chmod($dir, phpbb
::CHMOD_READ | phpbb
::CHMOD_WRITE
);
298 // Get target filename for storage folder
299 $filename = $this->get_filename($row['lang_iso'], $this->language_directory
, $this->language_file
, true, true);
300 $fp = @fopen
(PHPBB_ROOT_PATH
. $filename, 'wb');
304 trigger_error(sprintf($user->lang
['UNABLE_TO_WRITE_FILE'], $filename) . adm_back_link($this->u_action
. '&id=' . $lang_id . '&action=details&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING
);
307 if ($this->language_directory
== 'email')
310 $entry = $this->prepare_lang_entry($_POST['entry'], false);
315 $name = (($this->language_directory
) ?
$this->language_directory
. '_' : '') . $this->language_file
;
316 $header = str_replace(array('{FILENAME}', '{LANG_NAME}', '{CHANGED}', '{AUTHOR}'), array($name, $row['lang_english_name'], date('Y-m-d', time()), $row['lang_author']), $this->language_file_header
);
318 if (strpos($this->language_file
, 'help_') === 0)
321 $header .= '$help = array(' . "\n";
322 fwrite($fp, $header);
324 foreach ($_POST['entry'] as $key => $value)
326 if (!is_array($value))
331 $entry = "\tarray(\n";
333 foreach ($value as $_key => $_value)
335 $entry .= "\t\t" . (int) $_key . "\t=> '" . $this->prepare_lang_entry($_value) . "',\n";
342 $footer = ");\n\n?>";
343 fwrite($fp, $footer);
348 $header .= $this->lang_header
;
349 fwrite($fp, $header);
351 foreach ($_POST['entry'] as $key => $value)
353 $entry = $this->format_lang_array($key, $value);
357 $footer = "));\n\n?>";
358 fwrite($fp, $footer);
364 if ($action == 'download_file')
366 header('Pragma: no-cache');
367 header('Content-Type: application/octetstream; name="' . $this->language_file
. '"');
368 header('Content-disposition: attachment; filename=' . $this->language_file
);
370 $fp = @fopen
(PHPBB_ROOT_PATH
. $filename, 'rb');
371 while ($buffer = fread($fp, 1024))
377 add_log('admin', 'LOG_LANGUAGE_FILE_SUBMITTED', $this->language_file
);
381 else if ($action == 'upload_data')
383 $sql = 'SELECT lang_iso
384 FROM ' . LANG_TABLE
. "
385 WHERE lang_id = $lang_id";
386 $result = $db->sql_query($sql);
387 $row = $db->sql_fetchrow($result);
388 $db->sql_freeresult($result);
390 $file = request_var('file', '');
391 $dir = request_var('dir', '');
393 $selected_lang_file = $dir . '|' . $file;
395 $old_file = '/' . $this->get_filename($row['lang_iso'], $dir, $file, false, true);
396 $lang_path = 'language/' . $row['lang_iso'] . '/' . (($dir) ?
$dir . '/' : '');
398 include_once(PHPBB_ROOT_PATH
. 'includes/functions_transfer.' . PHP_EXT
);
399 $method = request_var('method', '');
401 if ($method != 'ftp' && $method != 'ftp_fsock')
403 trigger_error($user->lang
['INVALID_UPLOAD_METHOD'], E_USER_ERROR
);
406 $transfer = new $method(request_var('host', ''), request_var('username', ''), request_var('password', ''), request_var('root_path', ''), request_var('port', ''), request_var('timeout', ''));
408 if (($result = $transfer->open_session()) !== true)
410 trigger_error($user->lang
[$result] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING
);
413 $transfer->rename($lang_path . $file, $lang_path . $file . '.bak');
414 $result = $transfer->copy_file('store/' . $lang_path . $file, $lang_path . $file);
416 if ($result === false)
418 // If failed, try to rename again and print error out...
419 $transfer->delete_file($lang_path . $file);
420 $transfer->rename($lang_path . $file . '.bak', $lang_path . $file);
422 trigger_error($user->lang
['UPLOAD_FAILED'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING
);
425 $transfer->close_session();
427 // Remove from storage folder
428 if (file_exists(PHPBB_ROOT_PATH
. 'store/' . $lang_path . $file))
430 @unlink
(PHPBB_ROOT_PATH
. 'store/' . $lang_path . $file);
433 add_log('admin', 'LOG_LANGUAGE_FILE_REPLACED', $file);
435 trigger_error($user->lang
['UPLOAD_COMPLETED'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)));
438 add_log('admin', 'LOG_LANGUAGE_FILE_SUBMITTED', $this->language_file
);
447 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
450 $this->page_title
= 'LANGUAGE_PACK_DETAILS';
453 FROM ' . LANG_TABLE
. '
454 WHERE lang_id = ' . $lang_id;
455 $result = $db->sql_query($sql);
456 $lang_entries = $db->sql_fetchrow($result);
457 $db->sql_freeresult($result);
459 $lang_iso = $lang_entries['lang_iso'];
460 $missing_vars = $missing_files = array();
462 // Get email templates
463 $email_files = filelist(PHPBB_ROOT_PATH
. 'language/' . phpbb
::$config['default_lang'], 'email', 'txt');
464 $email_files = $email_files['email/'];
467 $acp_files = filelist(PHPBB_ROOT_PATH
. 'language/' . phpbb
::$config['default_lang'], 'acp', PHP_EXT
);
468 $acp_files = $acp_files['acp/'];
471 $mods_files = filelist(PHPBB_ROOT_PATH
. 'language/' . phpbb
::$config['default_lang'], 'mods', PHP_EXT
);
472 $mods_files = (isset($mods_files['mods/'])) ?
$mods_files['mods/'] : array();
474 // Check if our current filename matches the files
475 switch ($this->language_directory
)
478 if (!in_array($this->language_file
, $email_files))
480 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
485 if (!in_array($this->language_file
, $acp_files))
487 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
492 if (!in_array($this->language_file
, $mods_files))
494 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
499 if (!in_array($this->language_file
, $this->main_files
))
501 trigger_error($user->lang
['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action
. '&action=details&id=' . $lang_id), E_USER_WARNING
);
505 if (phpbb_request
::is_set_post('remove_store'))
507 $store_filename = $this->get_filename($lang_iso, $this->language_directory
, $this->language_file
, true, true);
509 if (file_exists(PHPBB_ROOT_PATH
. $store_filename))
511 @unlink
(PHPBB_ROOT_PATH
. $store_filename);
515 include_once(PHPBB_ROOT_PATH
. 'includes/functions_transfer.' . PHP_EXT
);
517 $methods = transfer
::methods();
519 foreach ($methods as $method)
521 $template->assign_block_vars('buttons', array(
526 $template->assign_vars(array(
528 'U_ACTION' => $this->u_action
. "&action=details&id=$lang_id",
529 'U_BACK' => $this->u_action
,
530 'LANG_LOCAL_NAME' => $lang_entries['lang_local_name'],
531 'LANG_ENGLISH_NAME' => $lang_entries['lang_english_name'],
532 'LANG_ISO' => $lang_entries['lang_iso'],
533 'LANG_AUTHOR' => $lang_entries['lang_author'],
534 'ALLOW_UPLOAD' => sizeof($methods)
538 // If current lang is different from the default lang, then first try to grab missing/additional vars
539 if ($lang_iso != phpbb
::$config['default_lang'])
541 $is_missing_var = false;
543 foreach ($this->main_files
as $file)
545 if (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, '', $file)))
547 $missing_vars[$file] = $this->compare_language_files(phpbb
::$config['default_lang'], $lang_iso, '', $file);
549 if (sizeof($missing_vars[$file]))
551 $is_missing_var = true;
556 $missing_files[] = $this->get_filename($lang_iso, '', $file);
560 // Now go through acp/mods directories
561 foreach ($acp_files as $file)
563 if (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, 'acp', $file)))
565 $missing_vars['acp/' . $file] = $this->compare_language_files(phpbb
::$config['default_lang'], $lang_iso, 'acp', $file);
567 if (sizeof($missing_vars['acp/' . $file]))
569 $is_missing_var = true;
574 $missing_files[] = $this->get_filename($lang_iso, 'acp', $file);
578 if (sizeof($mods_files))
580 foreach ($mods_files as $file)
582 if (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, 'mods', $file)))
584 $missing_vars['mods/' . $file] = $this->compare_language_files(phpbb
::$config['default_lang'], $lang_iso, 'mods', $file);
586 if (sizeof($missing_vars['mods/' . $file]))
588 $is_missing_var = true;
593 $missing_files[] = $this->get_filename($lang_iso, 'mods', $file);
598 // More missing files... for example email templates?
599 foreach ($email_files as $file)
601 if (!file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, 'email', $file)))
603 $missing_files[] = $this->get_filename($lang_iso, 'email', $file);
607 if (sizeof($missing_files))
609 $template->assign_vars(array(
610 'S_MISSING_FILES' => true,
611 'L_MISSING_FILES' => sprintf($user->lang
['THOSE_MISSING_LANG_FILES'], $lang_entries['lang_local_name']),
612 'MISSING_FILES' => implode('<br />', $missing_files))
618 $template->assign_vars(array(
619 'S_MISSING_VARS' => true,
620 'L_MISSING_VARS_EXPLAIN' => sprintf($user->lang
['THOSE_MISSING_LANG_VARIABLES'], $lang_entries['lang_local_name']),
621 'U_MISSING_ACTION' => $this->u_action
. "&action=$action&id=$lang_id")
624 foreach ($missing_vars as $file => $vars)
631 $template->assign_block_vars('missing', array(
633 'TPL' => $this->print_language_entries($vars, '', false),
634 'KEY' => (strpos($file, '/') === false) ?
'|' . $file : str_replace('/', '|', $file))
640 // Main language files
641 $s_lang_options = '<option value="|common.' . PHP_EXT
. '" class="sep">' . $user->lang
['LANGUAGE_FILES'] . '</option>';
642 foreach ($this->main_files
as $file)
644 if (strpos($file, 'help_') === 0)
649 $prefix = (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, '', $file, true, true))) ?
'* ' : '';
651 $selected = (!$this->language_directory
&& $this->language_file
== $file) ?
' selected="selected"' : '';
652 $s_lang_options .= '<option value="|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>';
656 $s_lang_options .= '<option value="|common.' . PHP_EXT
. '" class="sep">' . $user->lang
['HELP_FILES'] . '</option>';
657 foreach ($this->main_files
as $file)
659 if (strpos($file, 'help_') !== 0)
664 $prefix = (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, '', $file, true, true))) ?
'* ' : '';
666 $selected = (!$this->language_directory
&& $this->language_file
== $file) ?
' selected="selected"' : '';
667 $s_lang_options .= '<option value="|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>';
670 // Now every other language directory
671 $check_files = array('email', 'acp', 'mods');
673 foreach ($check_files as $check)
675 if (!sizeof($
{$check . '_files'}))
680 $s_lang_options .= '<option value="|common.' . PHP_EXT
. '" class="sep">' . $user->lang
[strtoupper($check) . '_FILES'] . '</option>';
682 foreach ($
{$check . '_files'} as $file)
684 $prefix = (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, $check, $file, true, true))) ?
'* ' : '';
686 $selected = ($this->language_directory
== $check && $this->language_file
== $file) ?
' selected="selected"' : '';
687 $s_lang_options .= '<option value="' . $check . '|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>';
691 // Get Language Entries - if saved within store folder, we take this one (with the option to remove it)
694 $is_email_file = ($this->language_directory
== 'email') ?
true : false;
695 $is_help_file = (strpos($this->language_file
, 'help_') === 0) ?
true : false;
697 $file_from_store = (file_exists(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, $this->language_directory
, $this->language_file
, true, true))) ?
true : false;
698 $no_store_filename = $this->get_filename($lang_iso, $this->language_directory
, $this->language_file
);
700 if (!$file_from_store && !file_exists(PHPBB_ROOT_PATH
. $no_store_filename))
702 $print_message = sprintf($user->lang
['MISSING_LANGUAGE_FILE'], $no_store_filename);
708 $lang = file_get_contents(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, $this->language_directory
, $this->language_file
, $file_from_store));
713 include(PHPBB_ROOT_PATH
. $this->get_filename($lang_iso, $this->language_directory
, $this->language_file
, $file_from_store));
722 $print_message = (($this->language_directory
) ?
$this->language_directory
. '/' : '') . $this->language_file
;
725 // Normal language pack entries
726 $template->assign_vars(array(
727 'U_ENTRY_ACTION' => $this->u_action
. "&action=details&id=$lang_id#entries",
728 'S_EMAIL_FILE' => $is_email_file,
729 'S_FROM_STORE' => $file_from_store,
730 'S_LANG_OPTIONS' => $s_lang_options,
731 'PRINT_MESSAGE' => $print_message,
738 $name = (($this->language_directory
) ?
$this->language_directory
. '/' : '') . $this->language_file
;
740 if (isset($missing_vars[$name]) && sizeof($missing_vars[$name]))
742 $tpl .= $this->print_language_entries($missing_vars[$name], '* ');
745 $tpl .= $this->print_language_entries($lang);
747 $template->assign_var('TPL', $tpl);
752 $template->assign_vars(array(
767 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
771 FROM ' . LANG_TABLE
. '
772 WHERE lang_id = ' . $lang_id;
773 $result = $db->sql_query($sql);
774 $row = $db->sql_fetchrow($result);
775 $db->sql_freeresult($result);
777 if ($row['lang_iso'] == phpbb
::$config['default_lang'])
779 trigger_error($user->lang
['NO_REMOVE_DEFAULT_LANG'] . adm_back_link($this->u_action
), E_USER_WARNING
);
782 $db->sql_query('DELETE FROM ' . LANG_TABLE
. ' WHERE lang_id = ' . $lang_id);
784 $sql = 'UPDATE ' . USERS_TABLE
. "
785 SET user_lang = '" . $db->sql_escape(phpbb
::$config['default_lang']) . "'
786 WHERE user_lang = '" . $db->sql_escape($row['lang_iso']) . "'";
787 $db->sql_query($sql);
789 // We also need to remove the translated entries for custom profile fields - we want clean tables, don't we?
790 $sql = 'DELETE FROM ' . PROFILE_LANG_TABLE
. ' WHERE lang_id = ' . $lang_id;
791 $db->sql_query($sql);
793 $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE
. ' WHERE lang_id = ' . $lang_id;
794 $db->sql_query($sql);
796 $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE
. " WHERE image_lang = '" . $db->sql_escape($row['lang_iso']) . "'";
797 $result = $db->sql_query($sql);
799 phpbb
::$acm->destroy_sql(STYLES_IMAGESET_DATA_TABLE
);
801 add_log('admin', 'LOG_LANGUAGE_PACK_DELETED', $row['lang_english_name']);
803 trigger_error(sprintf($user->lang
['LANGUAGE_PACK_DELETED'], $row['lang_english_name']) . adm_back_link($this->u_action
));
807 $lang_iso = request_var('iso', '');
808 $lang_iso = basename($lang_iso);
810 if (!$lang_iso ||
!file_exists(PHPBB_ROOT_PATH
. "language/$lang_iso/iso.txt"))
812 trigger_error($user->lang
['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action
), E_USER_WARNING
);
815 $file = file(PHPBB_ROOT_PATH
. "language/$lang_iso/iso.txt");
819 'name' => trim(htmlspecialchars($file[0])),
820 'local_name'=> trim(htmlspecialchars($file[1], ENT_COMPAT
, 'UTF-8')),
821 'author' => trim(htmlspecialchars($file[2], ENT_COMPAT
, 'UTF-8'))
825 $sql = 'SELECT lang_iso
826 FROM ' . LANG_TABLE
. "
827 WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'";
828 $result = $db->sql_query($sql);
829 $row = $db->sql_fetchrow($result);
830 $db->sql_freeresult($result);
834 trigger_error($user->lang
['LANGUAGE_PACK_ALREADY_INSTALLED'] . adm_back_link($this->u_action
), E_USER_WARNING
);
837 if (!$lang_pack['name'] ||
!$lang_pack['local_name'])
839 trigger_error($user->lang
['INVALID_LANGUAGE_PACK'] . adm_back_link($this->u_action
), E_USER_WARNING
);
844 'lang_iso' => $lang_pack['iso'],
845 'lang_dir' => $lang_pack['iso'],
846 'lang_english_name' => $lang_pack['name'],
847 'lang_local_name' => $lang_pack['local_name'],
848 'lang_author' => $lang_pack['author']
851 $db->sql_query('INSERT INTO ' . LANG_TABLE
. ' ' . $db->sql_build_array('INSERT', $sql_ary));
852 $lang_id = $db->sql_nextid();
854 $valid_localized = array(
855 'icon_back_top', 'icon_contact_aim', 'icon_contact_email', 'icon_contact_icq', 'icon_contact_jabber', 'icon_contact_msnm', 'icon_contact_pm', 'icon_contact_yahoo', 'icon_contact_www', 'icon_post_delete', 'icon_post_edit', 'icon_post_info', 'icon_post_quote', 'icon_post_report', 'icon_user_online', 'icon_user_offline', 'icon_user_profile', 'icon_user_search', 'icon_user_warn', 'button_pm_forward', 'button_pm_new', 'button_pm_reply', 'button_topic_locked', 'button_topic_new', 'button_topic_reply',
861 FROM ' . STYLES_IMAGESET_TABLE
;
862 $result = $db->sql_query($sql);
863 while ($imageset_row = $db->sql_fetchrow($result))
865 if (@file_exists
(PHPBB_ROOT_PATH
. "styles/{$imageset_row['imageset_path']}/imageset/{$lang_pack['iso']}/imageset.cfg"))
867 $cfg_data_imageset_data = parse_cfg_file(PHPBB_ROOT_PATH
. "styles/{$imageset_row['imageset_path']}/imageset/{$lang_pack['iso']}/imageset.cfg");
868 foreach ($cfg_data_imageset_data as $image_name => $value)
870 if (strpos($value, '*') !== false)
872 if (substr($value, -1, 1) === '*')
874 list($image_filename, $image_height) = explode('*', $value);
879 list($image_filename, $image_height, $image_width) = explode('*', $value);
884 $image_filename = $value;
885 $image_height = $image_width = 0;
888 if (strpos($image_name, 'img_') === 0 && $image_filename)
890 $image_name = substr($image_name, 4);
891 if (in_array($image_name, $valid_localized))
894 'image_name' => (string) $image_name,
895 'image_filename' => (string) $image_filename,
896 'image_height' => (int) $image_height,
897 'image_width' => (int) $image_width,
898 'imageset_id' => (int) $imageset_row['imageset_id'],
899 'image_lang' => (string) $lang_pack['iso'],
906 $db->sql_freeresult($result);
908 if (sizeof($sql_ary))
910 $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE
, $sql_ary);
911 phpbb
::$acm->destroy_sql(STYLES_IMAGESET_DATA_TABLE
);
914 // Now let's copy the default language entries for custom profile fields for this new language - makes admin's life easier.
915 $sql = 'SELECT lang_id
916 FROM ' . LANG_TABLE
. "
917 WHERE lang_iso = '" . $db->sql_escape(phpbb
::$config['default_lang']) . "'";
918 $result = $db->sql_query($sql);
919 $default_lang_id = (int) $db->sql_fetchfield('lang_id');
920 $db->sql_freeresult($result);
922 // From the mysql documentation:
923 // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14.
924 // Due to this we stay on the safe side if we do the insertion "the manual way"
926 $sql = 'SELECT field_id, lang_name, lang_explain, lang_default_value
927 FROM ' . PROFILE_LANG_TABLE
. '
928 WHERE lang_id = ' . $default_lang_id;
929 $result = $db->sql_query($sql);
931 while ($row = $db->sql_fetchrow($result))
933 $row['lang_id'] = $lang_id;
934 $db->sql_query('INSERT INTO ' . PROFILE_LANG_TABLE
. ' ' . $db->sql_build_array('INSERT', $row));
936 $db->sql_freeresult($result);
938 $sql = 'SELECT field_id, option_id, field_type, lang_value
939 FROM ' . PROFILE_FIELDS_LANG_TABLE
. '
940 WHERE lang_id = ' . $default_lang_id;
941 $result = $db->sql_query($sql);
943 while ($row = $db->sql_fetchrow($result))
945 $row['lang_id'] = $lang_id;
946 $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_LANG_TABLE
. ' ' . $db->sql_build_array('INSERT', $row));
948 $db->sql_freeresult($result);
950 add_log('admin', 'LOG_LANGUAGE_PACK_INSTALLED', $lang_pack['name']);
952 trigger_error(sprintf($user->lang
['LANGUAGE_PACK_INSTALLED'], $lang_pack['name']) . adm_back_link($this->u_action
));
960 trigger_error($user->lang
['NO_LANG_ID'] . adm_back_link($this->u_action
), E_USER_WARNING
);
964 FROM ' . LANG_TABLE
. '
965 WHERE lang_id = ' . $lang_id;
966 $result = $db->sql_query($sql);
967 $row = $db->sql_fetchrow($result);
968 $db->sql_freeresult($result);
970 $use_method = request_var('use_method', '');
971 $methods = array('.tar');
973 $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
974 foreach ($available_methods as $type => $module)
976 if (!@extension_loaded
($module))
984 // Let the user decide in which format he wants to have the pack
987 $this->page_title
= 'SELECT_DOWNLOAD_FORMAT';
990 foreach ($methods as $method)
992 $radio_buttons .= '<label><input type="radio"' . ((!$radio_buttons) ?
' id="use_method"' : '') . ' class="radio" value="' . $method . '" name="use_method" /> ' . $method . '</label>';
995 $template->assign_vars(array(
996 'S_SELECT_METHOD' => true,
997 'U_BACK' => $this->u_action
,
998 'U_ACTION' => $this->u_action
. "&action=$action&id=$lang_id",
999 'RADIO_BUTTONS' => $radio_buttons)
1005 if (!in_array($use_method, $methods))
1007 $use_method = '.tar';
1010 include_once(PHPBB_ROOT_PATH
. 'includes/functions_compress.' . PHP_EXT
);
1012 if ($use_method == '.zip')
1014 $compress = new compress_zip('w', PHPBB_ROOT_PATH
. 'store/lang_' . $row['lang_iso'] . $use_method);
1018 $compress = new compress_tar('w', PHPBB_ROOT_PATH
. 'store/lang_' . $row['lang_iso'] . $use_method, $use_method);
1021 // Get email templates
1022 $email_templates = filelist(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'], 'email', 'txt');
1023 $email_templates = $email_templates['email/'];
1026 $acp_files = filelist(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'], 'acp', PHP_EXT
);
1027 $acp_files = $acp_files['acp/'];
1030 $mod_files = filelist(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'], 'mods', PHP_EXT
);
1031 $mod_files = (isset($mod_files['mods/'])) ?
$mod_files['mods/'] : array();
1034 $this->add_to_archive($compress, $this->main_files
, $row['lang_iso']);
1036 // Add search files if they exist...
1037 if (file_exists(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'] . '/search_ignore_words.' . PHP_EXT
))
1039 $this->add_to_archive($compress, array('search_ignore_words.' . PHP_EXT
), $row['lang_iso']);
1042 if (file_exists(PHPBB_ROOT_PATH
. 'language/' . $row['lang_iso'] . '/search_synonyms.' . PHP_EXT
))
1044 $this->add_to_archive($compress, array('search_synonyms.' . PHP_EXT
), $row['lang_iso']);
1047 // Write files in folders
1048 $this->add_to_archive($compress, $email_templates, $row['lang_iso'], 'email');
1049 $this->add_to_archive($compress, $acp_files, $row['lang_iso'], 'acp');
1050 $this->add_to_archive($compress, $mod_files, $row['lang_iso'], 'mods');
1053 $iso_src = htmlspecialchars_decode($row['lang_english_name']) . "\n";
1054 $iso_src .= htmlspecialchars_decode($row['lang_local_name']) . "\n";
1055 $iso_src .= htmlspecialchars_decode($row['lang_author']);
1056 $compress->add_data($iso_src, 'language/' . $row['lang_iso'] . '/iso.txt');
1059 $compress->add_data('', 'language/' . $row['lang_iso'] . '/index.html');
1060 $compress->add_data('', 'language/' . $row['lang_iso'] . '/email/index.html');
1061 $compress->add_data('', 'language/' . $row['lang_iso'] . '/acp/index.html');
1063 if (sizeof($mod_files))
1065 $compress->add_data('', 'language/' . $row['lang_iso'] . '/mods/index.html');
1070 $compress->download('lang_' . $row['lang_iso']);
1071 @unlink
(PHPBB_ROOT_PATH
. 'store/lang_' . $row['lang_iso'] . $use_method);
1078 $sql = 'SELECT user_lang, COUNT(user_lang) AS lang_count
1079 FROM ' . USERS_TABLE
. '
1080 GROUP BY user_lang';
1081 $result = $db->sql_query($sql);
1083 $lang_count = array();
1084 while ($row = $db->sql_fetchrow($result))
1086 $lang_count[$row['user_lang']] = $row['lang_count'];
1088 $db->sql_freeresult($result);
1091 FROM ' . LANG_TABLE
. '
1092 ORDER BY lang_english_name';
1093 $result = $db->sql_query($sql);
1095 $installed = array();
1097 while ($row = $db->sql_fetchrow($result))
1099 $installed[] = $row['lang_iso'];
1100 $tagstyle = ($row['lang_iso'] == phpbb
::$config['default_lang']) ?
'*' : '';
1102 $template->assign_block_vars('lang', array(
1103 'U_DETAILS' => $this->u_action
. "&action=details&id={$row['lang_id']}",
1104 'U_DOWNLOAD' => $this->u_action
. "&action=download&id={$row['lang_id']}",
1105 'U_DELETE' => $this->u_action
. "&action=delete&id={$row['lang_id']}",
1107 'ENGLISH_NAME' => $row['lang_english_name'],
1109 'LOCAL_NAME' => $row['lang_local_name'],
1110 'ISO' => $row['lang_iso'],
1111 'USED_BY' => (isset($lang_count[$row['lang_iso']])) ?
$lang_count[$row['lang_iso']] : 0,
1114 $db->sql_freeresult($result);
1116 $new_ary = $iso = array();
1117 $dp = @opendir
(PHPBB_ROOT_PATH
. 'language');
1121 while (($file = readdir($dp)) !== false)
1123 if ($file[0] != '.' && file_exists(PHPBB_ROOT_PATH
. "language/$file/iso.txt"))
1125 if (!in_array($file, $installed))
1127 if ($iso = file(PHPBB_ROOT_PATH
. "language/$file/iso.txt"))
1129 if (sizeof($iso) == 3)
1131 $new_ary[$file] = array(
1133 'name' => trim($iso[0]),
1134 'local_name'=> trim($iso[1]),
1135 'author' => trim($iso[2])
1147 if (sizeof($new_ary))
1149 foreach ($new_ary as $iso => $lang_ary)
1151 $template->assign_block_vars('notinst', array(
1152 'ISO' => htmlspecialchars($lang_ary['iso']),
1153 'LOCAL_NAME' => htmlspecialchars($lang_ary['local_name'], ENT_COMPAT
, 'UTF-8'),
1154 'NAME' => htmlspecialchars($lang_ary['name'], ENT_COMPAT
, 'UTF-8'),
1155 'U_INSTALL' => $this->u_action
. '&action=install&iso=' . urlencode($lang_ary['iso']))
1165 * Set default language variables/header
1167 function default_variables()
1169 $this->language_file_header
= '<?php
1172 * {FILENAME} [{LANG_NAME}]
1175 * @version $' . 'Id: ' . '$
1176 * @copyright (c) ' . date('Y') . ' phpBB Group
1177 * @author {CHANGED} - {AUTHOR}
1178 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
1185 if (!defined(\'IN_PHPBB\'))
1190 if (empty($lang) || !is_array($lang))
1195 // DEVELOPERS PLEASE NOTE
1197 // All language files should use UTF-8 as their encoding and the files must not contain a BOM.
1199 // Placeholders can now contain order information, e.g. instead of
1200 // \'Page %s of %s\' you can (and should) write \'Page %1$s of %2$s\', this allows
1201 // translators to re-order the output of data while ensuring it remains correct
1203 // You do not need this where single placeholders are used, e.g. \'Message %d\' is fine
1204 // equally where a string contains only two placeholders which are used to wrap text
1205 // in a url you again do not need to specify an order e.g., \'Click %sHERE%s\' is fine
1208 $this->lang_header
= '
1209 $lang = array_merge($lang, array(
1212 // Language files in language root directory
1213 $this->main_files
= array('common.' . PHP_EXT
, 'groups.' . PHP_EXT
, 'install.' . PHP_EXT
, 'mcp.' . PHP_EXT
, 'memberlist.' . PHP_EXT
, 'posting.' . PHP_EXT
, 'search.' . PHP_EXT
, 'ucp.' . PHP_EXT
, 'viewforum.' . PHP_EXT
, 'viewtopic.' . PHP_EXT
, 'help_bbcode.' . PHP_EXT
, 'help_faq.' . PHP_EXT
);
1217 * Get filename/location of language file
1219 function get_filename($lang_iso, $directory, $filename, $check_store = false, $only_return_filename = false)
1223 $check_filename = "language/$lang_iso/" . (($directory) ?
$directory . '/' : '') . $filename;
1227 $check_store_filename = ($safe_mode) ?
"store/langfile_{$lang_iso}" . (($directory) ?
'_' . $directory : '') . "_{$filename}" : "store/language/$lang_iso/" . (($directory) ?
$directory . '/' : '') . $filename;
1229 if (!$only_return_filename && file_exists(PHPBB_ROOT_PATH
. $check_store_filename))
1231 return $check_store_filename;
1233 else if ($only_return_filename)
1235 return $check_store_filename;
1239 return $check_filename;
1243 * Add files to archive
1245 function add_to_archive(&$compress, $filelist, $lang_iso, $directory = '')
1247 foreach ($filelist as $file)
1249 // Get source filename
1250 $source = $this->get_filename($lang_iso, $directory, $file, true);
1251 $destination = 'language/' . $lang_iso . '/' . (($directory) ?
$directory . '/' : '') . $file;
1253 // Add file to archive
1254 $compress->add_custom_file(PHPBB_ROOT_PATH
. $source, $destination);
1259 * Little helper to add some hardcoded template bits
1261 function add_input_field()
1263 $keys = func_get_args();
1265 $non_static = array_shift($keys);
1266 $value = array_shift($keys);
1270 return '<strong>' . htmlspecialchars($value, ENT_COMPAT
, 'UTF-8') . '</strong>';
1273 // If more then 270 characters, then we present a textarea, else an input field
1274 $textarea = (utf8_strlen($value) > 270) ?
true : false;
1277 $tpl .= ($textarea) ?
'<textarea name="' : '<input type="text" name="';
1278 $tpl .= 'entry[' . implode('][', array_map('utf8_htmlspecialchars', $keys)) . ']"';
1280 $tpl .= ($textarea) ?
' cols="80" rows="5" class="langvalue">' : ' class="langvalue" value="';
1281 $tpl .= htmlspecialchars($value, ENT_COMPAT
, 'UTF-8');
1282 $tpl .= ($textarea) ?
'</textarea>' : '" />';
1288 * Print language entries
1290 function print_language_entries(&$lang_ary, $key_prefix = '', $input_field = true)
1294 foreach ($lang_ary as $key => $value)
1296 if (is_array($value))
1301 <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT
, 'UTF-8') . '<strong>' . htmlspecialchars($key, ENT_COMPAT
, 'UTF-8') . '</strong></td>
1304 foreach ($value as $_key => $_value)
1306 if (is_array($_value))
1311 <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT
, 'UTF-8') . ' <strong>' . htmlspecialchars($_key, ENT_COMPAT
, 'UTF-8') . '</strong></td>
1314 foreach ($_value as $__key => $__value)
1319 <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT
, 'UTF-8') . '<strong>' . htmlspecialchars($__key, ENT_COMPAT
, 'UTF-8') . '</strong></td>
1322 $tpl .= $this->add_input_field($input_field, $__value, $key, $_key, $__key);
1333 <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT
, 'UTF-8') . '<strong>' . htmlspecialchars($_key, ENT_COMPAT
, 'UTF-8') . '</strong></td>
1336 $tpl .= $this->add_input_field($input_field, $_value, $key, $_key);
1345 <td class="spacer" colspan="2"> </td>
1353 <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT
, 'UTF-8') . '<strong>' . htmlspecialchars($key, ENT_COMPAT
, 'UTF-8') . '</strong></td>
1356 $tpl .= $this->add_input_field($input_field, $value, $key);
1367 * Compare two language files
1369 function compare_language_files($source_lang, $dest_lang, $directory, $file)
1371 $return_ary = array();
1374 include(PHPBB_ROOT_PATH
. "language/{$source_lang}/" . (($directory) ?
$directory . '/' : '') . $file);
1375 $lang_entry_src = $lang;
1379 if (!file_exists(PHPBB_ROOT_PATH
. $this->get_filename($dest_lang, $directory, $file, true)))
1384 include(PHPBB_ROOT_PATH
. $this->get_filename($dest_lang, $directory, $file, true));
1386 $lang_entry_dst = $lang;
1390 $diff_array_keys = array_diff(array_keys($lang_entry_src), array_keys($lang_entry_dst));
1391 unset($lang_entry_dst);
1393 foreach ($diff_array_keys as $key)
1395 $return_ary[$key] = $lang_entry_src[$key];
1398 unset($lang_entry_src);
1404 * Return language string value for storage
1406 function prepare_lang_entry($text, $store = true)
1408 $text = (STRIP
) ?
stripslashes($text) : $text;
1410 // Adjust for storage...
1413 $text = str_replace("'", "\\'", str_replace('\\', '\\\\', $text));
1420 * Format language array for storage
1422 function format_lang_array($key, $value, $tabs = "\t")
1426 if (!is_array($value))
1428 $entry .= "{$tabs}'" . $this->prepare_lang_entry($key) . "'\t=> '" . $this->prepare_lang_entry($value) . "',\n";
1432 $_tabs = $tabs . "\t";
1433 $entry .= "\n{$tabs}'" . $this->prepare_lang_entry($key) . "'\t=> array(\n";
1435 foreach ($value as $_key => $_value)
1437 $entry .= $this->format_lang_array($_key, $_value, $_tabs);
1440 $entry .= "{$tabs}),\n\n";