Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/include/txp_lang.php - 501 lines - 16105 bytes - Summary - Text - Print

Description: Languages panel.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * http://textpattern.com
   6   *
   7   * Copyright (C) 2016 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 <http://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  include_once txpath.'/lib/txplib_update.php';
  36  
  37  if ($event == 'lang') {
  38      require_privs('lang');
  39  
  40      $available_steps = array(
  41          'get_language'    => true,
  42          'get_textpack'    => true,
  43          'remove_language' => true,
  44          'save_language'   => true,
  45          'list_languages'  => false,
  46      );
  47  
  48      if ($step && bouncer($step, $available_steps)) {
  49          $step();
  50      } else {
  51          list_languages();
  52      }
  53  }
  54  
  55  /**
  56   * Generate a &lt;select&gt; element of installed languages.
  57   *
  58   * @param  string $name The HTML name and ID to assign to the select control
  59   * @param  string $val  The currently active language identifier (en-gb, fr-fr, ...)
  60   * @return string HTML
  61   */
  62  
  63  function languages($name, $val)
  64  {
  65      $installed_langs = safe_column("lang", 'txp_lang', "1 = 1 GROUP BY lang");
  66  
  67      $vals = array();
  68  
  69      foreach ($installed_langs as $lang) {
  70          $vals[$lang] = safe_field("data", 'txp_lang', "name = '".doSlash($lang)."' AND lang = '".doSlash($lang)."'");
  71  
  72          if (trim($vals[$lang]) == '') {
  73              $vals[$lang] = $lang;
  74          }
  75      }
  76  
  77      asort($vals);
  78      reset($vals);
  79  
  80      return selectInput($name, $vals, $val, false, true, $name);
  81  }
  82  
  83  /**
  84   * Generates a &lt;table&gt; of every language that Textpattern supports.
  85   *
  86   * If requested with HTTP POST parameter 'force' set anything other than 'file',
  87   * outputs any errors in RPC server connection.
  88   *
  89   * @param string|array $message The activity message
  90   */
  91  
  92  function list_languages($message = '')
  93  {
  94      require_once txpath.'/lib/IXRClass.php';
  95  
  96      $active_lang = safe_field("val", 'txp_prefs', "name = 'language'");
  97  
  98      $lang_form = tag(
  99          form(
 100              tag(gTxt('active_language'), 'label', array('for' => 'language')).
 101              languages('language', $active_lang).
 102              eInput('lang').
 103              sInput('save_language')
 104          ), 'div', array(
 105              'class' => 'txp-control-panel',
 106          )
 107      );
 108  
 109      $client = new IXR_Client(RPC_SERVER);
 110  //    $client->debug = true;
 111  
 112      $available_lang = array();
 113      $rpc_connect = false;
 114      $show_files = false;
 115  
 116      // Get items from RPC.
 117      @set_time_limit(90); // TODO: 90 seconds: seriously?
 118      if ($client->query('tups.listLanguages', get_pref('blog_uid'))) {
 119          $rpc_connect = true;
 120          $response = $client->getResponse();
 121  
 122          foreach ($response as $language) {
 123              $available_lang[$language['language']]['rpc_lastmod'] = gmmktime($language['lastmodified']->hour, $language['lastmodified']->minute, $language['lastmodified']->second, $language['lastmodified']->month, $language['lastmodified']->day, $language['lastmodified']->year);
 124          }
 125      } elseif (gps('force') != 'file') {
 126          $msg = gTxt('rpc_connect_error')."<!--".$client->getErrorCode().' '.$client->getErrorMessage()."-->";
 127      }
 128  
 129      // Get items from Filesystem.
 130      $files = get_lang_files();
 131  
 132      if (is_array($files) && !empty($files)) {
 133          foreach ($files as $file) {
 134              if ($fp = @fopen(txpath.DS.'lang'.DS.$file, 'r')) {
 135                  $name = preg_replace('/\.(txt|textpack)$/i', '', $file);
 136                  $firstline = fgets($fp, 4069);
 137                  fclose($fp);
 138  
 139                  if (strpos($firstline, '#@version') !== false) {
 140                      @list($fversion, $ftime) = explode(';', trim(substr($firstline, strpos($firstline, ' ', 1))));
 141                  } else {
 142                      $fversion = $ftime = null;
 143                  }
 144  
 145                  $available_lang[$name]['file_note'] = (isset($fversion)) ? $fversion : 0;
 146                  $available_lang[$name]['file_lastmod'] = (isset($ftime)) ? $ftime : 0;
 147              }
 148          }
 149      }
 150  
 151      // Get installed items from the database.
 152      // We need a value here for the language itself, not for each one of the rows.
 153      $rows = safe_rows("lang, UNIX_TIMESTAMP(MAX(lastmod)) AS lastmod", 'txp_lang', "1 = 1 GROUP BY lang ORDER BY lastmod DESC");
 154      $installed_lang = array();
 155  
 156      foreach ($rows as $language) {
 157          $available_lang[$language['lang']]['db_lastmod'] = $language['lastmod'];
 158  
 159          if ($language['lang'] != $active_lang) {
 160              $installed_lang[] = $language['lang'];
 161          }
 162      }
 163  
 164      $list = '';
 165  
 166      // Create the language table components.
 167      foreach ($available_lang as $langname => $langdat) {
 168          $file_updated = (isset($langdat['db_lastmod']) && @$langdat['file_lastmod'] > $langdat['db_lastmod']);
 169          $rpc_updated = (@$langdat['rpc_lastmod'] > @$langdat['db_lastmod']);
 170  
 171          $rpc_install = tda(
 172              ($rpc_updated)
 173              ? strong(
 174                  eLink(
 175                      'lang',
 176                      'get_language',
 177                      'lang_code',
 178                      $langname,
 179                      (isset($langdat['db_lastmod'])
 180                          ? gTxt('update')
 181                          : gTxt('install')
 182                      ),
 183                      'updating',
 184                      isset($langdat['db_lastmod']),
 185                      ''
 186                  )
 187              ).
 188              n.span(safe_strftime('%d %b %Y %X', @$langdat['rpc_lastmod']), array('class' => 'date modified'))
 189              : (
 190                  (isset($langdat['rpc_lastmod'])
 191                      ? gTxt('up_to_date')
 192                      : '-'
 193                  ).
 194                  (isset($langdat['db_lastmod'])
 195                      ? n.span(safe_strftime('%d %b %Y %X', $langdat['db_lastmod']), array('class' => 'date modified'))
 196                      : ''
 197                  )
 198              ), (isset($langdat['db_lastmod']) && $rpc_updated)
 199                  ? ' class="highlight lang-value"'
 200                  : ' class="lang-value"'
 201          );
 202  
 203          $lang_file = tda(
 204              (isset($langdat['file_lastmod']))
 205              ? strong(
 206                  eLink(
 207                      'lang',
 208                      'get_language',
 209                      'lang_code',
 210                      $langname,
 211                      (
 212                          ($file_updated)
 213                          ? gTxt('update')
 214                          : gTxt('install')
 215                      ),
 216                      'force',
 217                      'file',
 218                      ''
 219                  )
 220              ).
 221              n.span(safe_strftime(get_pref('archive_dateformat'), $langdat['file_lastmod']), array(
 222                  'class' => 'date '.($file_updated ? 'created' : 'modified'),
 223              ))
 224              : '-', ' class="lang-value languages_detail'.((isset($langdat['db_lastmod']) && $rpc_updated) ? ' highlight' : '').'"'
 225          );
 226  
 227          $list .= tr(
 228          // Lang-Name and Date.
 229              hCell(
 230                  gTxt($langname), '', (isset($langdat['db_lastmod']) && $rpc_updated)
 231                          ? ' class="highlight lang-label" scope="row"'
 232                          : ' class="lang-label" scope="row"'
 233                  ).
 234              n.$rpc_install.
 235              n.$lang_file.
 236              tda((in_array($langname, $installed_lang) ? dLink('lang', 'remove_language', 'lang_code', $langname, 1) : '-'), ' class="languages_detail'.((isset($langdat['db_lastmod']) && $rpc_updated) ? ' highlight' : '').'"')
 237          ).n;
 238      }
 239  
 240      // Output table and content.
 241      pagetop(gTxt('tab_languages'), $message);
 242  
 243      echo n.'<div class="txp-layout">'.
 244          n.tag(
 245              hed(gTxt('tab_languages'), 1, array('class' => 'txp-heading')),
 246              'div', array('class' => 'txp-layout-1col')
 247          ).
 248          n.tag_start('div', array(
 249              'class' => 'txp-layout-1col',
 250              'id'    => 'language_container',
 251          ));
 252  
 253      if (isset($msg) && $msg) {
 254          echo graf('<span class="ui-icon ui-icon-alert"></span> '.$msg, array('class' => 'alert-block error'));
 255      }
 256  
 257      echo $lang_form,
 258          n.tag(
 259              toggle_box('languages_detail'), 'div', array('class' => 'txp-list-options')).
 260          n.tag_start('div', array('class' => 'txp-listtables')).
 261          n.tag_start('table', array('class' => 'txp-list')).
 262          n.tag_start('thead').
 263          tr(
 264              hCell(
 265                  gTxt('language'), '', ' scope="col"'
 266              ).
 267              hCell(
 268                  gTxt('from_server').popHelp('install_lang_from_server'), '', ' scope="col"'
 269              ).
 270              hCell(
 271                  gTxt('from_file').popHelp('install_lang_from_file'), '', ' class="languages_detail" scope="col"'
 272              ).
 273              hCell(
 274                  gTxt('remove_lang').popHelp('remove_lang'), '', ' class="languages_detail" scope="col"'
 275              )
 276          ).
 277          n.tag_end('thead').
 278          n.tag_start('tbody').
 279          $list.
 280          n.tag_end('tbody').
 281          n.tag_end('table').
 282          n.tag_end('div'). // End of .txp-listtables.
 283  
 284          hed(gTxt('install_from_textpack'), 2).
 285          n.tag(
 286              form(
 287                  '<label for="textpack-install">'.gTxt('install_textpack').'</label>'.popHelp('get_textpack').
 288                  n.'<textarea class="code" id="textpack-install" name="textpack" cols="'.INPUT_LARGE.'" rows="'.TEXTAREA_HEIGHT_SMALL.'" dir="ltr"></textarea>'.
 289                  fInput('submit', 'install_new', gTxt('upload')).
 290                  eInput('lang').
 291                  sInput('get_textpack'), '', '', 'post', '', '', 'text_uploader'
 292              ), 'div', array('class' => 'txp-control-panel'));
 293  
 294      echo n.tag_end('div'). // End of .txp-layout-1col.
 295          n.'</div>'; // End of .txp-layout.;
 296  }
 297  
 298  /**
 299   * Saves the active language.
 300   */
 301  
 302  function save_language()
 303  {
 304      global $textarray, $locale;
 305  
 306      extract(psa(array(
 307          'language',
 308      )));
 309  
 310      if (safe_field("lang", 'txp_lang', "lang = '".doSlash($language)."' LIMIT 1")) {
 311          $locale = Txp::get('\Textpattern\L10n\Locale')->getLanguageLocale($language);
 312          $new_locale = $prefs['locale'] = Txp::get('\Textpattern\L10n\Locale')->setLocale(LC_ALL, array($language, 'C'))->getLocale();
 313          set_pref('locale', $new_locale);
 314          if ($new_locale == $locale) {
 315              $msg = gTxt('preferences_saved');
 316          } else {
 317              $msg = array(gTxt('locale_not_available_for_language', array('{name}' => $language)), E_WARNING);
 318          }
 319          set_pref('language', $language);
 320          $textarray = load_lang($language);
 321          list_languages($msg);
 322  
 323          return;
 324      }
 325  
 326      list_languages(array(gTxt('language_not_installed', array('{name}' => $language)), E_ERROR));
 327  }
 328  
 329  /**
 330   * Installs a language from the RPC server or from a file.
 331   *
 332   * This function fetches language strings for the given language code from
 333   * either the RPC server or a file.
 334   *
 335   * Action is taken based on three HTTP POST parameters: 'lang_code', 'force' and
 336   * 'updating'. The 'lang_code' is the installed langauge, e.g. 'en-gb', 'fi-fi'.
 337   * The 'force' when set to 'file' can be used force an installation from a local
 338   * file. The 'updating' specifies whether only to install (0) or to update (1).
 339   */
 340  
 341  function get_language()
 342  {
 343      global $prefs, $textarray;
 344      require_once txpath.'/lib/IXRClass.php';
 345      $lang_code = gps('lang_code');
 346  
 347      $client = new IXR_Client(RPC_SERVER);
 348  //    $client->debug = true;
 349  
 350      @set_time_limit(90); // TODO: 90 seconds: seriously?
 351      if (gps('force') == 'file' || !$client->query('tups.getLanguage', $prefs['blog_uid'], $lang_code)) {
 352          if ((gps('force') == 'file' || gps('updating') !== '1') && install_language_from_file($lang_code)) {
 353              if (defined('LANG')) {
 354                  $textarray = load_lang(LANG);
 355              }
 356  
 357              callback_event('lang_installed', 'file', false, $lang_code);
 358  
 359              return list_languages(gTxt($lang_code).sp.gTxt('updated'));
 360          } else {
 361              pagetop(gTxt('installing_language'));
 362              echo graf('<span class="ui-icon ui-icon-alert"></span> '.gTxt('rpc_connect_error')."<!--".$client->getErrorCode().' '.$client->getErrorMessage()."-->", array('class' => 'alert-block error'));
 363          }
 364      } else {
 365          $response = $client->getResponse();
 366          $lang_struct = unserialize($response);
 367  
 368          if ($lang_struct === false) {
 369              $errors = $size = 1;
 370          } else {
 371              array_walk($lang_struct, 'install_lang_key');
 372              $size = count($lang_struct);
 373              $errors = 0;
 374  
 375              for ($i = 0; $i < $size; $i++) {
 376                  $errors += (!$lang_struct[$i]['ok']);
 377              }
 378  
 379              if (defined('LANG')) {
 380                  $textarray = load_lang(LANG);
 381              }
 382          }
 383  
 384          $msg = gTxt($lang_code).sp.gTxt('updated');
 385  
 386          callback_event('lang_installed', 'remote', false, $lang_code);
 387  
 388          if ($errors > 0) {
 389              $msg = array($msg.sprintf(" (%s errors, %s ok)", $errors, ($size-$errors)), E_ERROR);
 390          }
 391  
 392          list_languages($msg);
 393      }
 394  }
 395  
 396  /**
 397   * Writes a new language string to the database.
 398   *
 399   * The language is taken from a 'lang_code' HTTP POST or GET parameter.
 400   *
 401   * The '$value' argument takes a string as an array. This array consists of keys
 402   * 'name', 'event', 'data', 'uLastmod'.
 403   *
 404   * @param array $value  The string
 405   * @param int   $key    Not used
 406   */
 407  
 408  function install_lang_key(&$value, $key)
 409  {
 410      extract(gpsa(array(
 411          'lang_code',
 412          'updating',
 413      )));
 414  
 415      $exists = safe_field(
 416          "name",
 417          'txp_lang',
 418          "name = '".doSlash($value['name'])."' AND lang = '".doSlash($lang_code)."'"
 419      );
 420  
 421      $q =
 422          "name = '".doSlash($value['name'])."',
 423          event = '".doSlash($value['event'])."',
 424          data = '".doSlash($value['data'])."',
 425          lastmod = '".doSlash(strftime('%Y%m%d%H%M%S', $value['uLastmod']))."'";
 426  
 427      if ($exists !== false) {
 428          $value['ok'] = safe_update(
 429              'txp_lang',
 430              $q,
 431              "owner = '".doSlash(TEXTPATTERN_LANG_OWNER_SYSTEM)."' AND lang = '".doSlash($lang_code)."' AND name = '".doSlash($value['name'])."'"
 432          );
 433      } else {
 434          $value['ok'] = safe_insert(
 435              'txp_lang',
 436              "$q, lang = '".doSlash($lang_code)."'"
 437          );
 438      }
 439  }
 440  
 441  /**
 442   * Installs a Textpack.
 443   *
 444   * The Textpack is feeded by a 'textpack' HTTP POST parameter.
 445   *
 446   * @see install_textpack()
 447   */
 448  
 449  function get_textpack()
 450  {
 451      $textpack = ps('textpack');
 452      $n = install_textpack($textpack, true);
 453      list_languages(gTxt('textpack_strings_installed', array('{count}' => $n)));
 454  }
 455  
 456  /**
 457   * Remove all language strings for the given lang code.
 458   *
 459   * Removed language code is specified with 'lang_code' HTTP POST
 460   * parameter.
 461   */
 462  
 463  function remove_language()
 464  {
 465      $lang_code = ps('lang_code');
 466      $ret = safe_delete('txp_lang', "lang = '".doSlash($lang_code)."'");
 467  
 468      if ($ret) {
 469          callback_event('lang_deleted', '', 0, $lang_code);
 470          $msg = gTxt($lang_code).sp.gTxt('deleted');
 471      } else {
 472          $msg = gTxt('cannot_delete', array('{thing}' => $lang_code));
 473      }
 474  
 475      list_languages($msg);
 476  }
 477  
 478  /**
 479   * Lists all language files in the 'lang' directory.
 480   *
 481   * @return array Available language filenames
 482   */
 483  
 484  function get_lang_files()
 485  {
 486      $lang_dir = txpath.DS.'lang'.DS;
 487  
 488      if (!is_dir($lang_dir)) {
 489          trigger_error('Lang directory is not a directory: '.$lang_dir, E_USER_WARNING);
 490  
 491          return array();
 492      }
 493  
 494      if (chdir($lang_dir)) {
 495          if ($files = glob('*.{txt,textpack}', GLOB_BRACE)) {
 496              return $files;
 497          }
 498      }
 499  
 500      return array();
 501  }

title

Description

title

Description

title

Description

title

title

Body