.
*/
/**
* Languages panel.
*
* @package Admin\Lang
* @since 4.6.0
*/
if (!defined('txpinterface')) {
die('txpinterface is undefined.');
}
if ($event == 'lang') {
require_privs('lang');
$available_steps = array(
'get_language' => true,
'get_textpack' => true,
'remove_language' => true,
'save_language' => true,
'save_language_ui' => true,
'list_languages' => false,
);
if ($step && bouncer($step, $available_steps)) {
$step();
} else {
list_languages();
}
}
/**
* Generates a grid of every language that Textpattern supports.
*
* @param string|array $message The activity message
*/
function list_languages($message = '')
{
global $txp_user, $prefs;
$allTypes = TEXTPATTERN_LANG_ACTIVE | TEXTPATTERN_LANG_INSTALLED | TEXTPATTERN_LANG_AVAILABLE;
$available_lang = Txp::get('\Textpattern\L10n\Lang')->available($allTypes, $allTypes);
$installed_lang = Txp::get('\Textpattern\L10n\Lang')->available(TEXTPATTERN_LANG_INSTALLED);
$active_lang = Txp::get('\Textpattern\L10n\Lang')->available(TEXTPATTERN_LANG_ACTIVE);
$represented_lang = array_merge($active_lang, $installed_lang);
$site_lang = get_pref('language', TEXTPATTERN_DEFAULT_LANG, true);
$ui_lang = get_pref('language_ui', $site_lang, true);
$cpanel = '';
if (has_privs('lang.edit')) {
$langList = Txp::get('\Textpattern\L10n\Lang')->languageSelect('language', $site_lang);
$cpanel .= form(
tag(gTxt('active_language'), 'label', array('for' => 'language')).
$langList.
eInput('lang').
sInput('save_language')
);
}
$langList = Txp::get('\Textpattern\L10n\Lang')->languageSelect('language_ui', $ui_lang);
$lang_form = tag(
$cpanel.
form(
tag(gTxt('active_language_ui'), 'label', array('for' => 'language_ui')).
$langList.
eInput('lang').
sInput('save_language_ui')
), 'div', array('class' => 'txp-control-panel')
);
$grid = '';
$done = array();
$in_use_by = safe_rows('val, user_name', 'txp_prefs', "name = 'language_ui' AND val in ('".join("','", doSlash(array_keys($represented_lang)))."') AND user_name != '".doSlash($txp_user)."'");
$langUse = array();
foreach ($in_use_by as $row) {
$langUse[$row['val']][] = $row['user_name'];
}
foreach ($langUse as $key => $row) {
$langUse[$key] = tag(eLink('admin', 'author_list', 'search_method', 'login', '('.count($row).')', 'crit', join(',', doSlash($row))), 'span', array('class' => 'txp-lang-user-count'));
}
// Create the widget components.
foreach ($represented_lang + $available_lang as $langname => $langdata) {
if (in_array($langname, $done)) {
continue;
}
$file_updated = (isset($langdata['db_lastmod']) && $langdata['file_lastmod'] > $langdata['db_lastmod']);
if (array_key_exists($langname, $represented_lang)) {
if ($file_updated) {
$cellclass = 'warning';
$icon = 'ui-icon-alert';
$status = gTxt('installed').' / '.gTxt('update_available');
$disabled = (has_privs('lang.edit') ? '' : 'disabled');
} else {
$cellclass = 'success';
$icon = 'ui-icon-check';
$status = gTxt('installed');
$disabled = 'disabled';
}
if (isset($available_lang[$langname])) {
$btnText = ''.sp.escape_title(gTxt('update'));
} else {
$btnText = '';
$cellclass = 'warning';
}
$removeText = ''.sp.escape_title(gTxt('remove'));
$btnRemove = (
array_key_exists($langname, $active_lang)
? ''
: (has_privs('lang.edit')
? tag($removeText, 'button', array(
'type' => 'submit',
'name' => 'remove_language',
))
: '')
);
} else {
$cellclass = $icon = '';
$btnText = ''.sp.escape_title(gTxt('install'));
$disabled = $btnRemove = '';
}
$installLink = ($disabled
? span($btnText, array('class' => 'txp-button disabled'))
: tag($btnText, 'button', array(
'type' => 'submit',
'name' => 'get_language',
)));
$grid .= tag(
form(
graf(
($icon ? ''.$status.'' : '').n.
tag(gTxt($langdata['name']), 'strong', array('dir' => 'auto')).br.
tag($langname, 'code', array('dir' => 'ltr')).
($btnRemove && array_key_exists($langname, $langUse) ? n.$langUse[$langname] : '')
).
graf(
(has_privs('lang.edit')
? $installLink
: '')
.n. $btnRemove
).
hInput('lang_code', $langname).
eInput('lang').
sInput(null)
, '', '', 'post'),
'li',
array('class' => 'txp-grid-cell txp-grid-cell-2span'.($cellclass ? ' '.$cellclass : ''))
).n;
$done[] = $langname;
}
// Output table and content.
pagetop(gTxt('tab_languages'), $message);
echo n.'
'.
n.tag(
hed(gTxt('tab_languages'), 1, array('class' => 'txp-heading')),
'div', array('class' => 'txp-layout-1col')
).
n.tag_start('div', array(
'class' => 'txp-layout-1col',
'id' => 'language_container',
));
if (!empty($prefs['module_pophelp'])) {
echo graf(gTxt('language_preamble'), array('class' => 'txp-layout-textbox'));
}
if (isset($msg) && $msg) {
echo graf('
'.$msg, array('class' => 'alert-block error'));
}
echo $lang_form.
'
'.
((has_privs('lang.edit'))
? hed(gTxt('install_from_textpack'), 3).
n.tag(
form(
'
'.popHelp('get_textpack').
n.'
'.
fInput('submit', 'install_new', gTxt('upload')).
eInput('lang').
sInput('get_textpack'), '', '', 'post', '', '', 'text_uploader'
), 'div', array('class' => 'txp-control-panel'))
: '');
echo n.tag_end('div'). // End of .txp-layout-1col.
n.'
'; // End of .txp-layout.;
}
/**
* Saves the active language.
*/
function save_language()
{
global $locale;
require_privs('lang.edit');
extract(psa(array(
'language',
)));
$txpLocale = Txp::get('\Textpattern\L10n\Locale');
$langName = fetchLangName($language);
if (safe_field("lang", 'txp_lang', "lang = '".doSlash($language)."' LIMIT 1")) {
$txpLocale->setLocale(LC_TIME, LANG);
$old_formats = txp_dateformats();
$candidates = array_unique(array($language, $txpLocale->getLocaleLanguage($language)));
$locale = $txpLocale->getLanguageLocale($language);
$new_locale = $txpLocale->setLocale(LC_ALL, array_filter($candidates))->getLocale();
$new_language = $txpLocale->getLocaleLanguage($new_locale);
set_pref('locale', $new_locale);
$new_formats = txp_dateformats();
foreach (array('dateformat', 'archive_dateformat', 'comments_dateformat') as $dateformat) {
$key = array_search(get_pref($dateformat), $old_formats);
if ($key !== false && $new_formats[$key] != $old_formats[$key]) {
set_pref($dateformat, $new_formats[$key]);
}
}
if ($new_locale == $locale || $new_language == $language) {
$msg = gTxt('preferences_saved');
} else {
$msg = array(gTxt('locale_not_available_for_language', array('{name}' => $langName)), E_WARNING);
}
set_pref('language', $language);
list_languages($msg);
return;
}
list_languages(array(gTxt('language_not_installed', array('{name}' => $langName)), E_ERROR));
}
/**
* Saves the active admin-side language.
*/
function save_language_ui()
{
global $locale;
extract(psa(array(
'language_ui',
)));
if (get_pref('language_ui') != $language_ui) {
$langName = fetchLangName($language_ui);
if (safe_field("lang", 'txp_lang', "lang = '".doSlash($language_ui)."' LIMIT 1")) {
$locale = Txp::get('\Textpattern\L10n\Locale')->getLanguageLocale($language_ui);
if ($locale) {
set_pref('language_ui', $language_ui, 'admin', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE);
txp_die('', 307, '?event=lang');
} else {
$msg = array(gTxt('locale_not_available_for_language', array('{name}' => $langName)), E_WARNING);
}
} else {
$msg = array(gTxt('language_not_installed', array('{name}' => $langName)), E_ERROR);
}
} else {
$msg = gTxt('preferences_saved');
}
list_languages($msg);
}
/**
* Installs a language from a file.
*
* The HTTP POST parameter 'lang_code' is the installed language,
* e.g. 'en-gb', 'fi'.
*/
function get_language()
{
$lang_code = ps('lang_code');
$langName = fetchLangName($lang_code);
$txpLang = Txp::get('\Textpattern\L10n\Lang');
$installed = $txpLang->installed();
$installString = in_array($lang_code, $installed) ? 'language_updated' : 'language_installed';
if ($txpLang->installFile($lang_code)) {
callback_event('lang_installed', 'file', false, $lang_code);
$txpLang->available(TEXTPATTERN_LANG_AVAILABLE, TEXTPATTERN_LANG_INSTALLED | TEXTPATTERN_LANG_AVAILABLE);
Txp::get('\Textpattern\Plugin\Plugin')->installTextpacks();
return list_languages(gTxt($installString, array('{name}' => $langName)));
}
return list_languages(array(gTxt('language_not_installed', array('{name}' => $langName)), E_ERROR));
}
/**
* Writes a new language string to the database.
*
* The language is taken from a 'lang_code' HTTP POST or GET parameter.
*
* The '$value' argument takes a string as an array. This array consists of keys
* 'name', 'event', 'data', 'uLastmod'.
*
* @param array $value The string
* @param int $key Not used
*/
function install_lang_key(&$value, $key)
{
extract(gpsa(array(
'lang_code',
'updating',
)));
$exists = safe_field(
"name",
'txp_lang',
"name = '".doSlash($value['name'])."' AND lang = '".doSlash($lang_code)."'"
);
$q =
"name = '".doSlash($value['name'])."',
event = '".doSlash($value['event'])."',
data = '".doSlash($value['data'])."',
lastmod = '".doSlash(strftime('%Y%m%d%H%M%S', $value['uLastmod']))."'";
if ($exists !== false) {
$value['ok'] = safe_update(
'txp_lang',
$q,
"owner = '".doSlash(TEXTPATTERN_LANG_OWNER_SYSTEM)."' AND lang = '".doSlash($lang_code)."' AND name = '".doSlash($value['name'])."'"
);
} else {
$value['ok'] = safe_insert(
'txp_lang',
"$q, lang = '".doSlash($lang_code)."'"
);
}
}
/**
* Installs a Textpack.
*
* The Textpack to load is fed by a 'textpack' HTTP POST parameter.
*/
function get_textpack()
{
require_privs('lang.edit');
$textpack = ps('textpack');
$n = Txp::get('\Textpattern\L10n\Lang')->installTextpack($textpack, true);
list_languages(gTxt('textpack_strings_installed', array('{count}' => $n)));
}
/**
* Remove all language strings for the given lang code.
*
* Removed language code is specified with 'lang_code' HTTP POST
* parameter.
*/
function remove_language()
{
global $event;
require_privs('lang.edit');
$lang_code = ps('lang_code');
$langName = fetchLangName($lang_code);
$ret = safe_delete('txp_lang', "lang = '".doSlash($lang_code)."'");
if ($ret) {
callback_event('lang_deleted', '', 0, $lang_code);
$msg = gTxt('language_deleted', array('{name}' => $langName));
$represented_lang = Txp::get('\Textpattern\L10n\Lang')->available(
TEXTPATTERN_LANG_ACTIVE | TEXTPATTERN_LANG_INSTALLED,
TEXTPATTERN_LANG_ACTIVE | TEXTPATTERN_LANG_INSTALLED | TEXTPATTERN_LANG_AVAILABLE
);
$site_lang = get_pref('language', TEXTPATTERN_DEFAULT_LANG, true);
$ui_lang = get_pref('language_ui', $site_lang, true);
$ui_lang = (array_key_exists($ui_lang, $represented_lang)) ? $ui_lang : $site_lang;
set_pref('language_ui', $ui_lang, 'admin', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE);
load_lang($ui_lang, $event);
} else {
$msg = gTxt('cannot_delete', array('{thing}' => $langName));
}
list_languages($msg);
}
/**
* Get the lang name from the given language file.
*
* @param string $lang_code Language designator
* @return string
*/
function fetchLangName($lang_code)
{
$txpLang = Txp::get('\Textpattern\L10n\Lang');
$langFile = $txpLang->findFilename($lang_code);
$langInfo = $txpLang->fetchMeta($langFile);
$langName = (isset($langInfo['name'])) ? $langInfo['name'] : $lang_code;
return $langName;
}
/**
* Lists all language files in the 'lang' directory.
*
* @return array Available language filenames
* @deprecated in 4.7.0
*/
function get_lang_files()
{
return Txp::get('\Textpattern\L10n\Lang')->files();
}