Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Lang import controller
  19   *
  20   * @package    tool_langimport
  21   * @copyright  2014 Dan Poltawski <dan@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace tool_langimport;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  require_once($CFG->libdir.'/filelib.php');
  29  require_once($CFG->libdir.'/componentlib.class.php');
  30  
  31  /**
  32   * Lang import controller
  33   *
  34   * @package    tool_langimport
  35   * @copyright  2014 Dan Poltawski <dan@moodle.com>
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class controller {
  39      /** @var array list of informational messages */
  40      public $info;
  41      /** @var array  list of error messages */
  42      public $errors;
  43      /** @var \lang_installer */
  44      private $installer;
  45      /** @var array languages available on the remote server */
  46      public $availablelangs;
  47  
  48      /**
  49       * Constructor.
  50       */
  51      public function __construct() {
  52          make_temp_directory('');
  53          make_upload_directory('lang');
  54  
  55          $this->info = array();
  56          $this->errors = array();
  57          $this->installer = new \lang_installer();
  58  
  59          $this->availablelangs = $this->installer->get_remote_list_of_languages();
  60      }
  61  
  62      /**
  63       * Install language packs provided
  64       *
  65       * @param string|array $langs array of langcodes or individual langcodes
  66       * @param bool $updating true if updating the langpacks
  67       * @return int false if an error encountered or
  68       * @throws \moodle_exception when error is encountered installing langpack
  69       */
  70      public function install_languagepacks($langs, $updating = false) {
  71          global $CFG;
  72  
  73          $this->installer->set_queue($langs);
  74          $results = $this->installer->run();
  75  
  76          $updatedpacks = 0;
  77  
  78          foreach ($results as $langcode => $langstatus) {
  79              switch ($langstatus) {
  80                  case \lang_installer::RESULT_DOWNLOADERROR:
  81                      $a       = new \stdClass();
  82                      $a->url  = $this->installer->lang_pack_url($langcode);
  83                      $a->dest = $CFG->dataroot.'/lang';
  84                      $this->errors[] = get_string('remotedownloaderror', 'error', $a);
  85                      throw new \moodle_exception('remotedownloaderror', 'error', '', $a);
  86                      break;
  87                  case \lang_installer::RESULT_INSTALLED:
  88                      $updatedpacks++;
  89                      if ($updating) {
  90                          event\langpack_updated::event_with_langcode($langcode)->trigger();
  91                          $this->info[] = get_string('langpackupdated', 'tool_langimport', $langcode);
  92                      } else {
  93                          $this->info[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
  94                          event\langpack_imported::event_with_langcode($langcode)->trigger();
  95                      }
  96                      break;
  97                  case \lang_installer::RESULT_UPTODATE:
  98                      $this->info[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
  99                      break;
 100              }
 101          }
 102  
 103          return $updatedpacks;
 104      }
 105  
 106      /**
 107       * Uninstall language pack
 108       *
 109       * @param string $lang language code
 110       * @return bool true if language succesfull installed
 111       */
 112      public function uninstall_language($lang) {
 113          global $CFG;
 114  
 115          $dest1 = $CFG->dataroot.'/lang/'.$lang;
 116          $dest2 = $CFG->dirroot.'/lang/'.$lang;
 117          $rm1 = false;
 118          $rm2 = false;
 119          if (file_exists($dest1)) {
 120              $rm1 = remove_dir($dest1);
 121          }
 122          if (file_exists($dest2)) {
 123              $rm2 = remove_dir($dest2);
 124          }
 125  
 126          if ($rm1 or $rm2) {
 127              // Set the default site language to en if the deleted language pack is the default site language.
 128              if ($CFG->lang === $lang) {
 129                  set_config('lang', 'en');
 130                  // Fix the user's current language to the default site language.
 131                  fix_current_language($CFG->lang);
 132              }
 133              $this->info[] = get_string('langpackremoved', 'tool_langimport', $lang);
 134              event\langpack_removed::event_with_langcode($lang)->trigger();
 135              return true;
 136          } else {    // Nothing deleted, possibly due to permission error.
 137              $this->errors[] = get_string('langpacknotremoved', 'tool_langimport', $lang);
 138              return false;
 139          }
 140      }
 141  
 142      /**
 143       * Updated all install language packs with the latest found on servre
 144       *
 145       * @return bool true if languages succesfully updated.
 146       */
 147      public function update_all_installed_languages() {
 148          global $CFG;
 149  
 150          if (!$availablelangs = $this->installer->get_remote_list_of_languages()) {
 151              $this->errors[] = get_string('cannotdownloadlanguageupdatelist', 'error');
 152              return false;
 153          }
 154  
 155          $md5array = array();    // Convert to (string)langcode => (string)md5.
 156          foreach ($availablelangs as $alang) {
 157              $md5array[$alang[0]] = $alang[1];
 158          }
 159  
 160          // Filter out unofficial packs.
 161          $currentlangs = array_keys(get_string_manager()->get_list_of_translations(true));
 162          $updateablelangs = array();
 163          foreach ($currentlangs as $clang) {
 164              if (!array_key_exists($clang, $md5array)) {
 165                  $this->info[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
 166                  continue;
 167              }
 168              $dest1 = $CFG->dataroot.'/lang/'.$clang;
 169              $dest2 = $CFG->dirroot.'/lang/'.$clang;
 170  
 171              if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')) {
 172                  $updateablelangs[] = $clang;
 173              }
 174          }
 175  
 176          // Filter out packs that have the same md5 key.
 177          $neededlangs = array();
 178          foreach ($updateablelangs as $ulang) {
 179              if (!$this->is_installed_lang($ulang, $md5array[$ulang])) {
 180                  $neededlangs[] = $ulang;
 181              }
 182          }
 183  
 184          try {
 185              $updated = $this->install_languagepacks($neededlangs, true);
 186          } catch (\moodle_exception $e) {
 187              $this->errors[] = 'An exception occurred while installing language packs: ' . $e->getMessage();
 188              return false;
 189          }
 190  
 191          if ($updated) {
 192              $this->info[] = get_string('langupdatecomplete', 'tool_langimport');
 193              // The strings have been changed so we need to purge their cache to ensure users see the changes.
 194              get_string_manager()->reset_caches();
 195          } else {
 196              $this->info[] = get_string('nolangupdateneeded', 'tool_langimport');
 197          }
 198  
 199          return true;
 200      }
 201  
 202      /**
 203       * checks the md5 of the zip file, grabbed from download.moodle.org,
 204       * against the md5 of the local language file from last update
 205       * @param string $lang language code
 206       * @param string $md5check md5 to check
 207       * @return bool true if installed
 208       */
 209      public function is_installed_lang($lang, $md5check) {
 210          global $CFG;
 211          $md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
 212          if (file_exists($md5file)) {
 213              return (file_get_contents($md5file) == $md5check);
 214          }
 215          return false;
 216      }
 217  
 218      /**
 219       * Returns the URL where a given language pack can be downloaded
 220       *
 221       * Alternatively, if the parameter is empty, returns URL of the page with the
 222       * list of all available language packs.
 223       *
 224       * @param string $langcode language code like 'cs' or empty for unknown
 225       * @return string URL
 226       */
 227      public function lang_pack_url($langcode = '') {
 228          return $this->installer->lang_pack_url($langcode);
 229      }
 230  
 231      /**
 232       * Schedule installation of the given language packs asynchronously via ad hoc task.
 233       *
 234       * @param string|array $langs array of langcodes or individual langcodes
 235       */
 236      public function schedule_languagepacks_installation($langs): void {
 237          global $USER;
 238  
 239          $task = new \tool_langimport\task\install_langpacks();
 240          $task->set_userid($USER->id);
 241          $task->set_custom_data([
 242              'langs' => $langs,
 243          ]);
 244  
 245          \core\task\manager::queue_adhoc_task($task, true);
 246  
 247          $this->info[] = get_string('installscheduled', 'tool_langimport');
 248      }
 249  }