MDL-22084 making a clear distinction between list of our translations and list of...
[moodle.git] / admin / langimport.php
1 <?php
2 ///This file only manages the installation of 2.0 lang packs.
3 ///in downloads.moodle.org, they are store in separate directory /lang20
4 ///in local server, they are stored in $CFG->dataroot/lang
5 ///This helps to avoid confusion.
7 die('Work in progress, to be replaced by the new language update interface...');
9     require_once('../config.php');
10     require_once($CFG->libdir.'/adminlib.php');
11     require_once($CFG->libdir.'/filelib.php');
12     require_once($CFG->libdir.'/componentlib.class.php');
14     admin_externalpage_setup('langimport');
16     if (!empty($CFG->skiplangupgrade)) {
17         echo $OUTPUT->header();
18         echo $OUTPUT->box(get_string('langimportdisabled', 'admin'));
19         echo $OUTPUT->footer();
20         die;
21     }
23     $mode          = optional_param('mode', 0, PARAM_INT);     //phase
24     $pack          = optional_param('pack', array(), PARAM_FILE);   //pack to install
25     $displaylang   = $pack;
26     $uninstalllang = optional_param('uninstalllang', '', PARAM_FILE);
27     $confirm       = optional_param('confirm', 0, PARAM_BOOL);
28     $sitelang      = optional_param('sitelangconfig', '', PARAM_FILE);
30     define('INSTALLATION_OF_SELECTED_LANG', 2);
31     define('DELETION_OF_SELECTED_LANG', 4);
32     define('UPDATE_ALL_LANG', 5);
34     $strlang         = get_string('langimport','admin');
35     $strlanguage     = get_string('language');
36     $strthislanguage = get_string('thislanguage', 'langconfig');
37     $title           = $strlang;
39     //reset and diagnose lang cache permissions
40     @unlink($CFG->dataroot.'/cache/languages');
41     if (file_exists($CFG->dataroot.'/cache/languages')) {
42         print_error('cannotdeletelangcache', 'error');
43     }
44     //TODO: refresh lang cache
46     $notice_ok     = array();
47     $notice_error = array();
49     switch ($mode){
51         case INSTALLATION_OF_SELECTED_LANG:    ///installation of selected language pack
53             if (confirm_sesskey() and !empty($pack)) {
54                 set_time_limit(0);
55                 @mkdir ($CFG->dataroot.'/temp/', $CFG->directorypermissions);    //make it in case it's a fresh install, it might not be there
56                 @mkdir ($CFG->dataroot.'/lang/', $CFG->directorypermissions);
58                 if (is_array($pack)) {
59                     $packs = $pack;
60                 } else {
61                     $packs = array($pack);
62                 }
64                 foreach ($packs as $pack) {
65                     if ($cd = new component_installer('http://download.moodle.org', 'lang20',
66                                                         $pack.'.zip', 'languages.md5', 'lang')) {
67                         $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
68                         switch ($status) {
70                             case COMPONENT_ERROR:
71                                 if ($cd->get_error() == 'remotedownloaderror') {
72                                     $a = new object();
73                                     $a->url = 'http://download.moodle.org/lang20/'.$pack.'.zip';
74                                     $a->dest= $CFG->dataroot.'/lang';
75                                     print_error($cd->get_error(), 'error', 'langimport.php', $a);
76                                 } else {
77                                     print_error($cd->get_error(), 'error', 'langimport.php');
78                                 }
79                             break;
81                             case COMPONENT_INSTALLED:
82                                 $notice_ok[] = get_string('langpackinstalled','admin',$pack);
83                                 if ($parentlang = get_parent_language($pack)) {
84                                     // install also parent pack if specified
85                                     if ($cd = new component_installer('http://download.moodle.org', 'lang20', $parentlang.'.zip', 'languages.md5', 'lang')) {
86                                         $cd->install();
87                                     }
88                                 }
89                             break;
91                             case COMPONENT_UPTODATE:
92                             break;
94                         }
95                     } else {
96                         echo $OUTPUT->notification('Had an unspecified error with the component installer, sorry.');
97                     }
98                 }
99             }
100         break;
102         case DELETION_OF_SELECTED_LANG:    //delete a directory(ies) containing a lang pack completely
104             if ($uninstalllang == 'en') {
105                 $notice_error[] = 'en can not be uninstalled!';
107             } else if (!$confirm && confirm_sesskey()) {
108                 echo $OUTPUT->header();
109                 echo $OUTPUT->confirm(get_string('uninstallconfirm', 'admin', $uninstalllang),
110                              'langimport.php?mode='.DELETION_OF_SELECTED_LANG.'&uninstalllang='.$uninstalllang.'&confirm=1',
111                              'langimport.php');
112                 echo $OUTPUT->footer();
113                 die;
115             } else if (confirm_sesskey()) {
116                 $dest1 = $CFG->dataroot.'/lang/'.$uninstalllang;
117                 $dest2 = $CFG->dirroot.'/lang/'.$uninstalllang;
118                 $rm1 = false;
119                 $rm2 = false;
120                 if (file_exists($dest1)){
121                     $rm1 = remove_dir($dest1);
122                 }
123                 if (file_exists($dest2)){
124                     $rm2 = remove_dir($dest2);
125                 }
126                 //TODO: refresh lang cache
127                 //delete the direcotries
128                 if ($rm1 or $rm2) {
129                     $notice_ok[] = get_string('langpackremoved','admin');
130                 } else {    //nothing deleted, possibly due to permission error
131                     $notice_error[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
132                 }
133             }
134         break;
136         case UPDATE_ALL_LANG:    //1 click update for all updatable language packs
137             set_time_limit(0);
139             //0th pull a list from download.moodle.org,
140             //key = langname, value = md5
141             $md5array = array();
142             $updated = 0;    //any packs updated?
143             $alllangs = array_keys(get_string_manager()->get_list_of_translations(true)); //get all available langs
144             $lang20 = array();   //all the Moodle 1.6 unicode lang packs (updated and not updated)
145             $packs = array();    //all the packs that needs updating
148             if (!$availablelangs = get_remote_list_of_languages()) {
149                 print_error('cannotdownloadlanguageupdatelist', 'error');
150             }
152             //and build an associative array
153             foreach ($availablelangs as $alang) {
154                 $md5array[$alang[0]] = $alang[1];
155             }
157             //filtering out non-16 and unofficial packs
158             foreach ($alllangs as $clang) {
159                 if (!array_key_exists($clang, $md5array)) {
160                     $notice_ok[] = get_string('langpackupdateskipped', 'admin', $clang);
161                     continue;
162                 }
163                 $dest1 = $CFG->dataroot.'/lang/'.$clang;
164                 $dest2 = $CFG->dirroot.'/lang/'.$clang;
166                 if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')){
167                     $lang20[] = $clang;
168                 }
169             }
171             //then filter out packs that have the same md5 key
172             foreach ($lang20 as $clang) {
173                 if (!is_installed_lang($clang, $md5array[$clang])){
174                     $packs[] = $clang;
175                 }
176             }
178             @mkdir ($CFG->dataroot.'/temp/', $CFG->directorypermissions);
179             @mkdir ($CFG->dataroot.'/lang/', $CFG->directorypermissions);
180             foreach ($packs as $pack){    //for each of the remaining in the list, we
181                 if ($pack == 'en') {    // no update for en
182                     continue;
183                 }
185                 //1. delete old director(ies)
187                 $dest1 = $CFG->dataroot.'/lang/'.$pack;
188                 $dest2 = $CFG->dirroot.'/lang/'.$pack;
189                 $rm1 = false;
190                 $rm2 = false;
191                 if (file_exists($dest1)) {
192                     if (!remove_dir($dest1)) {
193                         $notice_error[] = 'Could not delete old directory '.$dest1.', update of '.$pack.' failed, please check permissions.';
194                         continue;
195                     }
196                 }
197                 if (file_exists($dest2)) {
198                     if (!remove_dir($dest2)) {
199                         $notice_error[] = 'Could not delete old directory '.$dest2.', update of '.$pack.' failed, please check permissions.';
200                         continue;
201                     }
202                 }
204                 //2. copy & unzip into new
206                 if ($cd = new component_installer('http://download.moodle.org', 'lang20',
207                                        $pack.'.zip', 'languages.md5', 'lang')) {
208                 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
209                 switch ($status) {
211                     case COMPONENT_ERROR:
212                         if ($cd->get_error() == 'remotedownloaderror') {
213                             $a = new stdClass();
214                             $a->url = 'http://download.moodle.org/lang20/'.$pack.'.zip';
215                             $a->dest= $CFG->dataroot.'/lang';
216                             print_error($cd->get_error(), 'error', "", $a); // not probable
217                         } else {
218                             print_error($cd->get_error(), 'error'); // not probable
219                         }
220                     break;
221                     case COMPONENT_UPTODATE:
222                         //Print error string or whatever you want to do
223                     break;
224                     case COMPONENT_INSTALLED:
225                         $notice_ok[] = get_string('langpackupdated', 'admin', $pack);
226                         $updated = true;
227                         //Print/do whatever you want
228                     break;
229                     default:
230                     }
231                 } else {
233                 }
234             }
236             if ($updated) {
237                 $notice_ok[] = get_string('langupdatecomplete','admin');
238             } else {
239                 $notice_ok[] = get_string('nolangupdateneeded','admin');
240             }
242         break;
243     }    //close of main switch
246     echo $OUTPUT->header();
248     $installedlangs = get_string_manager()->get_list_of_translations(true);
250     $missingparents = array();
251     $oldlang = isset($SESSION->lang) ? $SESSION->lang : null; // override current lang
253     foreach($installedlangs as $l=>$unused) {
254         $SESSION->lang = $l;
255         $parent = get_string('parentlanguage', 'langconfig');
256         if ($parent === 'en') {
257             continue;
258         }
259         if (!isset($installedlangs[$parent])) {
260             $missingparents[$l] = $parent;
261         }
262     }
263     if (isset($oldlang)) {
264         $SESSION->lang = $oldlang;
265     } else {
266         unset($SESSION->lang);
267     }
269     if ($availablelangs = get_remote_list_of_languages()) {
270         $remote = 1;
271     } else {
272         $remote = 0;    //flag for reading from remote or local
273         $availablelangs = get_local_list_of_languages();
274     }
276     if (!$remote) {
277         echo $OUTPUT->box_start();
278         print_string('remotelangnotavailable', 'admin', $CFG->dataroot.'/lang/');
279         echo $OUTPUT->box_end();
280     }
282     if ($notice_ok) {
283         $info = implode('<br />', $notice_ok);
284         echo $OUTPUT->notification($info, 'notifysuccess');
285     }
287     if ($notice_error) {
288         $info = implode('<br />', $notice_error);
289         echo $OUTPUT->notification($info, 'notifyproblem');
290     }
292     if ($missingparents) {
293         foreach ($missingparents as $l=>$parent) {
294             $a = new object();
295             $a->lang   = $installedlangs[$l];
296             $a->parent = $parent;
297             foreach ($availablelangs as $alang) {
298                 if ($alang[0] == $parent) {
299                     $shortlang = $alang[0];
300                     $a->parent = $alang[2].' ('.$shortlang.')';
301                 }
302             }
303             $info = get_string('missinglangparent', 'admin', $a);
304             echo $OUTPUT->notification($info, 'notifyproblem');
305         }
306     }
308     echo $OUTPUT->box_start();
309     echo '<table summary="">';
310     echo '<tr><td align="center" valign="top">';
311     echo '<form id="uninstallform" action="langimport.php?mode='.DELETION_OF_SELECTED_LANG.'" method="post">';
312     echo '<fieldset class="invisiblefieldset">';
313     echo '<input name="sesskey" type="hidden" value="'.sesskey().'" />';
315     /// display installed langs here
317     echo '<label for="uninstalllang">'.get_string('installedlangs','admin')."</label><br />\n";
318     echo '<select name="uninstalllang" id="uninstalllang" size="15">';
319     foreach ($installedlangs as $clang =>$ilang){
320         echo '<option value="'.$clang.'">'.$ilang.'</option>';
321     }
322     echo '</select>';
323     echo '<br /><input type="submit" value="'.get_string('uninstall','admin').'" />';
324     echo '</fieldset>';
325     echo '</form>';
327     if ($remote) {
328         echo '<form id="updateform" action="langimport.php?mode='.UPDATE_ALL_LANG.'" method="post">';
329         echo '<div>';
330         echo '<br /><input type="submit" value="'.get_string('updatelangs','admin').'" />';
331         echo '</div>';
332         echo '</form>';
333     }
335     /// Display option to change site language
337     /// display to be installed langs here
339     echo '</td><td align="center" valign="top">';
340     //availabe langs table
341     $empty = 1;    //something to pring
343     /// if this language pack is not already installed, then we allow installation
345     echo '<form id="installform" method="post" action="langimport.php?mode='.INSTALLATION_OF_SELECTED_LANG.'">';
346     echo '<fieldset class="invisiblefieldset">';
347     echo '<input name="sesskey" type="hidden" value="'.sesskey().'" />';
348     echo '<label for="pack">'.get_string('availablelangs','admin')."</label><br />\n";
349     if ($remote) {
350         echo '<select name="pack[]" id="pack" size="15" multiple="multiple">';
351     }
353     foreach ($availablelangs as $alang) {
354         if ($alang[0] == '') {
355             continue;
356         }
357         if (trim($alang[0]) != "en") {
358             if ($remote) {
359                 $shortlang = $alang[0];
360                 if (!is_installed_lang($alang[0], $alang[1])){    //if not already installed
361                     echo '<option value="'.$alang[0].'">'.$alang[2].' ('.$shortlang.')</option>';
362                 }
363             } else {    //print list in local format, and instruction to install
364                 echo '<tr><td>'.$alang[2].'</td><td><a href="http://download.moodle.org/lang20/'.$alang[0].'.zip">'.get_string('download','admin').'</a></td></tr>';
365             }
366             $empty = 0;
367         }
368     }
369     if ($remote) {
370         echo '</select>';
371         echo '<br /><input type="submit" value="'.$OUTPUT->larrow().' '.get_string('install','admin').'" />';
372     }
373     echo '</fieldset>';
374     echo '</form>';
376     if ($empty) {
377         echo '<br />';
378         print_string('nolanguagetodownload','admin');
379     }
381     //close available langs table
382     echo '</td></tr></table>';
383     echo $OUTPUT->box_end();
385     echo $OUTPUT->footer();
387     /**
388      * Returns a list of available language packs from a
389      * local copy shipped with standard moodle distro
390      * this is for site that can't download components.
391      * @return array
392      */
393     function get_local_list_of_languages() {
394         global $CFG;
395         $source = $CFG->dirroot.'/lib/languages.md5';
396         $availablelangs = array();
397         if ($fp = fopen($source, 'r')) {
398             while(!feof ($fp)) {
399                 $availablelangs[] = split(',', fgets($fp,1024));
400             }
401         }
402         return $availablelangs;
403     }
405     /**
406      * checks the md5 of the zip file, grabbed from download.moodle.org,
407      * against the md5 of the local language file from last update
408      * @param string $lang
409      * @param string $md5check
410      * @return bool
411      */
412     function is_installed_lang($lang, $md5check) {
413         global $CFG;
414         $md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
415         if (file_exists($md5file)){
416             return (file_get_contents($md5file) == $md5check);
417         }
418         return false;
419     }
421     /**
422      * Returns the latest list of available language packs from
423      * moodle.org
424      * @return array or false if can not download
425      */
426     function get_remote_list_of_languages() {
427         $source = 'http://download.moodle.org/lang20/languages.md5';
428         $availablelangs = array();
430         if ($content = download_file_content($source)) {
431             $alllines = split("\n", $content);
432             foreach($alllines as $line) {
433                 if (!empty($line)){
434                     $availablelangs[] = split(',', $line);
435                 }
436             }
437             return $availablelangs;
439         } else {
440             return false;
441         }
442     }