Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/include/txp_lang.php - 465 lines - 15152 bytes - Summary - Text - Print

Description: Languages panel.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * https://textpattern.com/
   6   *
   7   * Copyright (C) 2020 The Textpattern Development Team
   8   *
   9   * This file is part of Textpattern.
  10   *
  11   * Textpattern is free software; you can redistribute it and/or
  12   * modify it under the terms of the GNU General Public License
  13   * as published by the Free Software Foundation, version 2.
  14   *
  15   * Textpattern is distributed in the hope that it will be useful,
  16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18   * GNU General Public License for more details.
  19   *
  20   * You should have received a copy of the GNU General Public License
  21   * along with Textpattern. If not, see <https://www.gnu.org/licenses/>.
  22   */
  23  
  24  /**
  25   * Languages panel.
  26   *
  27   * @package Admin\Lang
  28   * @since   4.6.0
  29   */
  30  
  31  if (!defined('txpinterface')) {
  32      die('txpinterface is undefined.');
  33  }
  34  
  35  if ($event == 'lang') {
  36      require_privs('lang');
  37  
  38      $available_steps = array(
  39          'get_language'     => true,
  40          'get_textpack'     => true,
  41          'remove_language'  => true,
  42          'save_language'    => true,
  43          'save_language_ui' => true,
  44          'list_languages'   => false,
  45      );
  46  
  47      if ($step && bouncer($step, $available_steps)) {
  48          $step();
  49      } else {
  50          list_languages();
  51      }
  52  }
  53  
  54  /**
  55   * Generates a grid of every language that Textpattern supports.
  56   *
  57   * @param string|array $message The activity message
  58   */
  59  
  60  function list_languages($message = '')
  61  {
  62      global $txp_user, $prefs;
  63  
  64      $allTypes = TEXTPATTERN_LANG_ACTIVE | TEXTPATTERN_LANG_INSTALLED | TEXTPATTERN_LANG_AVAILABLE;
  65      $available_lang = Txp::get('\Textpattern\L10n\Lang')->available($allTypes, $allTypes);
  66      $installed_lang = Txp::get('\Textpattern\L10n\Lang')->available(TEXTPATTERN_LANG_INSTALLED);
  67      $active_lang = Txp::get('\Textpattern\L10n\Lang')->available(TEXTPATTERN_LANG_ACTIVE);
  68      $represented_lang = array_merge($active_lang, $installed_lang);
  69  
  70      $site_lang = get_pref('language', TEXTPATTERN_DEFAULT_LANG, true);
  71      $ui_lang = get_pref('language_ui', $site_lang, true);
  72      $cpanel = '';
  73  
  74      if (has_privs('lang.edit')) {
  75          $langList = Txp::get('\Textpattern\L10n\Lang')->languageSelect('language', $site_lang);
  76          $cpanel .= form(
  77              tag(gTxt('active_language'), 'label', array('for' => 'language')).
  78              $langList.
  79              eInput('lang').
  80              sInput('save_language')
  81          );
  82      }
  83  
  84      $langList = Txp::get('\Textpattern\L10n\Lang')->languageSelect('language_ui', $ui_lang);
  85      $lang_form = tag(
  86          $cpanel.
  87          form(
  88              tag(gTxt('active_language_ui'), 'label', array('for' => 'language_ui')).
  89              $langList.
  90              eInput('lang').
  91              sInput('save_language_ui')
  92          ), 'div', array('class' => 'txp-control-panel')
  93      );
  94  
  95      $grid = '';
  96      $done = array();
  97      $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)."'");
  98  
  99      $langUse = array();
 100  
 101      foreach ($in_use_by as $row) {
 102          $langUse[$row['val']][] = $row['user_name'];
 103      }
 104  
 105      foreach ($langUse as $key => $row) {
 106          $langUse[$key] = tag(eLink('admin', 'author_list', 'search_method', 'login', '('.count($row).')', 'crit', join(',', doSlash($row))), 'span', array('class' => 'txp-lang-user-count'));
 107      }
 108  
 109      // Create the widget components.
 110      foreach ($represented_lang + $available_lang as $langname => $langdata) {
 111          if (in_array($langname, $done)) {
 112              continue;
 113          }
 114  
 115          $file_updated = (isset($langdata['db_lastmod']) && $langdata['file_lastmod'] > $langdata['db_lastmod']);
 116  
 117          if (array_key_exists($langname, $represented_lang)) {
 118              if ($file_updated) {
 119                  $cellclass = 'warning';
 120                  $icon = 'ui-icon-alert';
 121                  $status = gTxt('installed').' <span role="separator">/</span> '.gTxt('update_available');
 122                  $disabled = (has_privs('lang.edit') ? '' : 'disabled');
 123              } else {
 124                  $cellclass = 'success';
 125                  $icon = 'ui-icon-check';
 126                  $status = gTxt('installed');
 127                  $disabled = 'disabled';
 128              }
 129  
 130              if (isset($available_lang[$langname])) {
 131                  $btnText = '<span class="ui-icon ui-icon-refresh"></span>'.sp.escape_title(gTxt('update'));
 132              } else {
 133                  $btnText = '';
 134                  $cellclass = 'warning';
 135              }
 136  
 137              $removeText = '<span class="ui-icon ui-icon-minus"></span>'.sp.escape_title(gTxt('remove'));
 138  
 139              $btnRemove = (
 140                  array_key_exists($langname, $active_lang)
 141                      ? ''
 142                      : (has_privs('lang.edit')
 143                          ? tag($removeText, 'button', array(
 144                              'type' => 'submit',
 145                              'name' => 'remove_language',
 146                              ))
 147                          : '')
 148              );
 149          } else {
 150              $cellclass = $icon = '';
 151              $btnText = '<span class="ui-icon ui-icon-plus"></span>'.sp.escape_title(gTxt('install'));
 152              $disabled = $btnRemove = '';
 153          }
 154  
 155          $installLink = ($disabled
 156              ? span($btnText, array('class' => 'txp-button disabled'))
 157              : tag($btnText, 'button', array(
 158                  'type'      => 'submit',
 159                  'name'      => 'get_language',
 160              )));
 161  
 162          $grid .= tag(
 163              form(
 164                  graf(
 165                      ($icon ? '<span class="ui-icon '.$icon.'" role="status">'.$status.'</span>' : '').n.
 166                      tag(gTxt($langdata['name']), 'strong', array('dir' => 'auto')).br.
 167                      tag($langname, 'code', array('dir' => 'ltr')).
 168                      ($btnRemove && array_key_exists($langname, $langUse) ? n.$langUse[$langname] : '')
 169                  ).
 170                  graf(
 171                      (has_privs('lang.edit')
 172                          ? $installLink
 173                          : '')
 174                      .n. $btnRemove
 175                  ).
 176                  hInput('lang_code', $langname).
 177                  eInput('lang').
 178                  sInput(null)
 179              , '', '', 'post'),
 180              'li',
 181              array('class' => 'txp-grid-cell txp-grid-cell-2span'.($cellclass ? ' '.$cellclass : ''))
 182          ).n;
 183  
 184          $done[] = $langname;
 185      }
 186  
 187      // Output table and content.
 188      pagetop(gTxt('tab_languages'), $message);
 189  
 190      echo n.'<div class="txp-layout">'.
 191          n.tag(
 192              hed(gTxt('tab_languages'), 1, array('class' => 'txp-heading')),
 193              'div', array('class' => 'txp-layout-1col')
 194          ).
 195          n.tag_start('div', array(
 196              'class' => 'txp-layout-1col',
 197              'id'    => 'language_container',
 198          ));
 199  
 200      if (!empty($prefs['module_pophelp'])) {
 201          echo graf(gTxt('language_preamble'), array('class' => 'txp-layout-textbox'));
 202      }
 203  
 204      if (isset($msg) && $msg) {
 205          echo graf('<span class="ui-icon ui-icon-alert"></span> '.$msg, array('class' => 'alert-block error'));
 206      }
 207  
 208      echo $lang_form.
 209          '<ul class="txp-grid txp-grid-lang">'.
 210          $grid.
 211          '</ul>'.
 212  
 213          ((has_privs('lang.edit'))
 214              ? hed(gTxt('install_from_textpack'), 3).
 215                  n.tag(
 216                      form(
 217                          '<label for="textpack-install">'.gTxt('install_textpack').'</label>'.popHelp('get_textpack').
 218                          n.'<textarea class="code" id="textpack-install" name="textpack" cols="'.INPUT_LARGE.'" rows="'.TEXTAREA_HEIGHT_SMALL.'" dir="ltr" required="required"></textarea>'.
 219                          fInput('submit', 'install_new', gTxt('upload')).
 220                          eInput('lang').
 221                          sInput('get_textpack'), '', '', 'post', '', '', 'text_uploader'
 222                      ), 'div', array('class' => 'txp-control-panel'))
 223              : '');
 224  
 225      echo n.tag_end('div'). // End of .txp-layout-1col.
 226          n.'</div>'; // End of .txp-layout.;
 227  }
 228  
 229  /**
 230   * Saves the active language.
 231   */
 232  
 233  function save_language()
 234  {
 235      global $locale;
 236  
 237      require_privs('lang.edit');
 238  
 239      extract(psa(array(
 240          'language',
 241      )));
 242  
 243      $txpLocale = Txp::get('\Textpattern\L10n\Locale');
 244      $langName = fetchLangName($language);
 245  
 246      if (safe_field("lang", 'txp_lang', "lang = '".doSlash($language)."' LIMIT 1")) {
 247          $txpLocale->setLocale(LC_TIME, LANG);
 248          $old_formats = txp_dateformats();
 249          $candidates = array_unique(array($language, $txpLocale->getLocaleLanguage($language)));
 250          $locale = $txpLocale->getLanguageLocale($language);
 251          $new_locale = $txpLocale->setLocale(LC_ALL, array_filter($candidates))->getLocale();
 252          $new_language = $txpLocale->getLocaleLanguage($new_locale);
 253          set_pref('locale', $new_locale);
 254          $new_formats = txp_dateformats();
 255  
 256          foreach (array('dateformat', 'archive_dateformat', 'comments_dateformat') as $dateformat) {
 257              $key = array_search(get_pref($dateformat), $old_formats);
 258  
 259              if ($key !== false && $new_formats[$key] != $old_formats[$key]) {
 260                  set_pref($dateformat, $new_formats[$key]);
 261              }
 262          }
 263  
 264          if ($new_locale == $locale || $new_language == $language) {
 265              $msg = gTxt('preferences_saved');
 266          } else {
 267              $msg = array(gTxt('locale_not_available_for_language', array('{name}' => $langName)), E_WARNING);
 268          }
 269  
 270          set_pref('language', $language);
 271          list_languages($msg);
 272  
 273          return;
 274      }
 275  
 276      list_languages(array(gTxt('language_not_installed', array('{name}' => $langName)), E_ERROR));
 277  }
 278  
 279  /**
 280   * Saves the active admin-side language.
 281   */
 282  
 283  function save_language_ui()
 284  {
 285      global $locale;
 286  
 287      extract(psa(array(
 288          'language_ui',
 289      )));
 290  
 291      if (get_pref('language_ui') != $language_ui) {
 292          $langName = fetchLangName($language_ui);
 293  
 294          if (safe_field("lang", 'txp_lang', "lang = '".doSlash($language_ui)."' LIMIT 1")) {
 295              $locale = Txp::get('\Textpattern\L10n\Locale')->getLanguageLocale($language_ui);
 296  
 297              if ($locale) {
 298                  set_pref('language_ui', $language_ui, 'admin', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE);
 299                  txp_die('', 307, '?event=lang');
 300              } else {
 301                  $msg = array(gTxt('locale_not_available_for_language', array('{name}' => $langName)), E_WARNING);
 302              }
 303          } else {
 304              $msg = array(gTxt('language_not_installed', array('{name}' => $langName)), E_ERROR);
 305          }
 306      } else {
 307          $msg = gTxt('preferences_saved');
 308      }
 309  
 310      list_languages($msg);
 311  }
 312  
 313  /**
 314   * Installs a language from a file.
 315   *
 316   * The HTTP POST parameter 'lang_code' is the installed language,
 317   * e.g. 'en-gb', 'fi'.
 318   */
 319  
 320  function get_language()
 321  {
 322      $lang_code = ps('lang_code');
 323      $langName = fetchLangName($lang_code);
 324      $txpLang = Txp::get('\Textpattern\L10n\Lang');
 325      $installed = $txpLang->installed();
 326      $installString = in_array($lang_code, $installed) ? 'language_updated' : 'language_installed';
 327  
 328      if ($txpLang->installFile($lang_code)) {
 329          callback_event('lang_installed', 'file', false, $lang_code);
 330  
 331          $txpLang->available(TEXTPATTERN_LANG_AVAILABLE, TEXTPATTERN_LANG_INSTALLED | TEXTPATTERN_LANG_AVAILABLE);
 332          Txp::get('\Textpattern\Plugin\Plugin')->installTextpacks();
 333  
 334          return list_languages(gTxt($installString, array('{name}' => $langName)));
 335      }
 336  
 337      return list_languages(array(gTxt('language_not_installed', array('{name}' => $langName)), E_ERROR));
 338  }
 339  
 340  /**
 341   * Writes a new language string to the database.
 342   *
 343   * The language is taken from a 'lang_code' HTTP POST or GET parameter.
 344   *
 345   * The '$value' argument takes a string as an array. This array consists of keys
 346   * 'name', 'event', 'data', 'uLastmod'.
 347   *
 348   * @param array $value  The string
 349   * @param int   $key    Not used
 350   */
 351  
 352  function install_lang_key(&$value, $key)
 353  {
 354      extract(gpsa(array(
 355          'lang_code',
 356          'updating',
 357      )));
 358  
 359      $exists = safe_field(
 360          "name",
 361          'txp_lang',
 362          "name = '".doSlash($value['name'])."' AND lang = '".doSlash($lang_code)."'"
 363      );
 364  
 365      $q =
 366          "name = '".doSlash($value['name'])."',
 367          event = '".doSlash($value['event'])."',
 368          data = '".doSlash($value['data'])."',
 369          lastmod = '".doSlash(strftime('%Y%m%d%H%M%S', $value['uLastmod']))."'";
 370  
 371      if ($exists !== false) {
 372          $value['ok'] = safe_update(
 373              'txp_lang',
 374              $q,
 375              "owner = '".doSlash(TEXTPATTERN_LANG_OWNER_SYSTEM)."' AND lang = '".doSlash($lang_code)."' AND name = '".doSlash($value['name'])."'"
 376          );
 377      } else {
 378          $value['ok'] = safe_insert(
 379              'txp_lang',
 380              "$q, lang = '".doSlash($lang_code)."'"
 381          );
 382      }
 383  }
 384  
 385  /**
 386   * Installs a Textpack.
 387   *
 388   * The Textpack to load is fed by a 'textpack' HTTP POST parameter.
 389   */
 390  
 391  function get_textpack()
 392  {
 393      require_privs('lang.edit');
 394  
 395      $textpack = ps('textpack');
 396      $n = Txp::get('\Textpattern\L10n\Lang')->installTextpack($textpack, true);
 397      list_languages(gTxt('textpack_strings_installed', array('{count}' => $n)));
 398  }
 399  
 400  /**
 401   * Remove all language strings for the given lang code.
 402   *
 403   * Removed language code is specified with 'lang_code' HTTP POST
 404   * parameter.
 405   */
 406  
 407  function remove_language()
 408  {
 409      global $event;
 410  
 411      require_privs('lang.edit');
 412  
 413      $lang_code = ps('lang_code');
 414      $langName = fetchLangName($lang_code);
 415  
 416      $ret = safe_delete('txp_lang', "lang = '".doSlash($lang_code)."'");
 417  
 418      if ($ret) {
 419          callback_event('lang_deleted', '', 0, $lang_code);
 420          $msg = gTxt('language_deleted', array('{name}' => $langName));
 421          $represented_lang = Txp::get('\Textpattern\L10n\Lang')->available(
 422              TEXTPATTERN_LANG_ACTIVE | TEXTPATTERN_LANG_INSTALLED,
 423              TEXTPATTERN_LANG_ACTIVE | TEXTPATTERN_LANG_INSTALLED | TEXTPATTERN_LANG_AVAILABLE
 424          );
 425  
 426          $site_lang = get_pref('language', TEXTPATTERN_DEFAULT_LANG, true);
 427          $ui_lang = get_pref('language_ui', $site_lang, true);
 428          $ui_lang = (array_key_exists($ui_lang, $represented_lang)) ? $ui_lang : $site_lang;
 429          set_pref('language_ui', $ui_lang, 'admin', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE);
 430          load_lang($ui_lang, $event);
 431      } else {
 432          $msg = gTxt('cannot_delete', array('{thing}' => $langName));
 433      }
 434  
 435      list_languages($msg);
 436  }
 437  
 438  /**
 439   * Get the lang name from the given language file.
 440   *
 441   * @param  string $lang_code Language designator
 442   * @return string
 443   */
 444  
 445  function fetchLangName($lang_code)
 446  {
 447      $txpLang = Txp::get('\Textpattern\L10n\Lang');
 448      $langFile = $txpLang->findFilename($lang_code);
 449      $langInfo = $txpLang->fetchMeta($langFile);
 450      $langName = (isset($langInfo['name'])) ? $langInfo['name'] : $lang_code;
 451  
 452      return $langName;
 453  }
 454  
 455  /**
 456   * Lists all language files in the 'lang' directory.
 457   *
 458   * @return     array Available language filenames
 459   * @deprecated in 4.7.0
 460   */
 461  
 462  function get_lang_files()
 463  {
 464      return Txp::get('\Textpattern\L10n\Lang')->files();
 465  }

title

Description

title

Description

title

Description

title

title

Body