From f0488ae6100cdefb8cae462af7b748d9dfb36e26 Mon Sep 17 00:00:00 2001
From: Fil <fil@rezo.net>
Date: Fri, 20 Jul 2007 05:14:23 +0000
Subject: [PATCH] integration du chargeur/activateur de toggg, permet
 d'installer des plugins en trois clics

---
 .gitattributes                   |   2 +
 ecrire/action/charger_plugin.php | 103 ++++++++++
 ecrire/exec/admin_plugin.php     |  54 ++++--
 ecrire/inc/boutons.php           |   6 +-
 ecrire/inc/charger_plugin.php    | 312 +++++++++++++++++++++++++++++++
 ecrire/inc/commencer_page.php    |  25 +--
 ecrire/inc/plugin.php            |   9 +-
 7 files changed, 478 insertions(+), 33 deletions(-)
 create mode 100644 ecrire/action/charger_plugin.php
 create mode 100644 ecrire/inc/charger_plugin.php

diff --git a/.gitattributes b/.gitattributes
index e74b6b09fa..6737ffe1f4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -347,6 +347,7 @@ dist/vignettes/zip.png -text
 dist/win_width.htc -text
 ecrire/action/acceder_document.php -text
 ecrire/action/activer_plugins.php -text
+ecrire/action/charger_plugin.php -text
 ecrire/action/configurer.php -text
 ecrire/action/configurer_relayeur.php -text
 ecrire/action/converser.php -text
@@ -541,6 +542,7 @@ ecrire/inc/article_select.php -text
 ecrire/inc/auteur_infos.php -text
 ecrire/inc/autoriser.php -text
 ecrire/inc/boutons.php -text
+ecrire/inc/charger_plugin.php -text
 ecrire/inc/chercher_logo.php -text
 ecrire/inc/chercher_rubrique.php -text
 ecrire/inc/class.JavaScriptPacker.php -text
diff --git a/ecrire/action/charger_plugin.php b/ecrire/action/charger_plugin.php
new file mode 100644
index 0000000000..1ff949e6e9
--- /dev/null
+++ b/ecrire/action/charger_plugin.php
@@ -0,0 +1,103 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2007                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+
+/*
+ * Ce fichier est extrait du plugin charge : action charger decompresser
+ *
+ * Auteur : bertrand@toggg.com
+ * © 2007 - Distribue sous licence LGPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_charger_plugin_dist() {
+	include_spip('inc/minipres');
+	include_spip('inc/charger_plugin');
+
+	// droits : il faut avoir le droit de choisir les plugins,
+	// mais aussi d'en ajouter -- a voir
+	include_spip('inc/autoriser');
+	if (!autoriser('configurer', 'plugins')
+	OR !autoriser('webmestre')) {
+		echo minipres();
+		exit;
+	}
+
+	if (!preg_match(',^(https?|ftp)://.*\.zip,',
+		$zip = _request('url_zip_plugin2'))
+	AND !preg_match(',^(https?|ftp)://.*\.zip,',
+		$zip = _request('url_zip_plugin')))
+	{
+		include_spip('inc/headers');
+		redirige_par_entete(generer_url_ecrire('admin_plugin'));
+	}
+
+	# destination des fichiers
+	$dest = _DIR_PLUGINS_AUTO;
+
+	# eliminer plugins/ du chemin indique
+	$remove = 'plugins';
+
+	$status = chargeur_charger_zip(
+		array(
+			'zip' => $zip,
+			'remove' => $remove,
+			'dest' => $dest,
+			'keep' => false // conserver le .zip ?
+		)
+	);
+
+	if (is_array($status)) {
+		$retour = _L('Plugin charg&#233;');
+		$texte = '<p>'._L('Le fichier '.$zip.' a &#233;t&#233; t&#233;l&#233;charg&#233; et install&#233;').'</p>';
+		$texte .= liste_fichiers_pclzip($status);
+		$texte .= _L("<h2 style='text-align:center;'>Vous pouvez maintenant l'activer.</h2>");
+	} else if ($status < 0) {
+		$retour = _T('erreur');
+		$texte = _L("echec pclzip : erreur ").$status;
+	} else if ($status == 0) {
+		$retour = _T('erreur');
+		$texte = _L('erreur : impossible de charger '.$zip);
+	}
+
+	include_spip('exec/install'); // pour bouton_suivant()
+	echo minipres($retour,
+		generer_form_ecrire('admin_plugin&plug='.$status['dirname'], $texte . bouton_suivant())
+	);
+	exit;
+
+
+	// 0 = rien, pas charge
+	// liste de fichiers = retour gagnant
+	// < 0 = erreur pclzip 
+	// ----- Error codes
+	//   -1 : Unable to open file in binary write mode
+	//   -2 : Unable to open file in binary read mode
+	//   -3 : Invalid parameters
+	//   -4 : File does not exist
+	//   -5 : Filename is too long (max. 255)
+	//   -6 : Not a valid zip file
+	//   -7 : Invalid extracted file size
+	//   -8 : Unable to create directory
+	//   -9 : Invalid archive extension
+	//  -10 : Invalid archive format
+	//  -11 : Unable to delete file (unlink)
+	//  -12 : Unable to rename file (rename)
+	//  -13 : Invalid header checksum
+	//  -14 : Invalid archive size
+
+#	redirige_par_entete($url_retour);
+}
+
+?>
diff --git a/ecrire/exec/admin_plugin.php b/ecrire/exec/admin_plugin.php
index 6e40c28c43..b6169cddd3 100644
--- a/ecrire/exec/admin_plugin.php
+++ b/ecrire/exec/admin_plugin.php
@@ -20,8 +20,7 @@ include_spip('inc/actions');
 include_spip('inc/securiser_action');
 
 // http://doc.spip.org/@exec_admin_plugin_dist
-function exec_admin_plugin_dist() {
-	global $spip_lang_right;
+function exec_admin_plugin_dist($retour='') {
 
 	if (!autoriser('configurer', 'plugins')) {
 		include_spip('inc/minipres');
@@ -36,7 +35,9 @@ function exec_admin_plugin_dist() {
 	echo "<br/><br/><br/>";
 	
 	echo gros_titre(_T('icone_admin_plugin'),'',false);
-	// barre_onglets("configuration", "plugin"); // a creer dynamiquement en fonction des plugin charges qui utilisent une page admin ?
+
+
+	// barre_onglets("configuration", "plugin"); // a creer dynamiquement en fonction des plugin charges qui utilisent une page admin ? // cfg
 	
 	echo debut_gauche('plugin',true);
 	echo debut_boite_info(true);
@@ -52,32 +53,55 @@ function exec_admin_plugin_dist() {
 	// on fait l'installation ici, cela permet aux scripts d'install de faire des affichages ...
 	installe_plugins();
 
-	echo debut_droite('plugin',true);
-	if (isset($GLOBALS['meta']['plugin_erreur_activation'])){
-		echo $GLOBALS['meta']['plugin_erreur_activation'];
-		effacer_meta('plugin_erreur_activation');
-	}
+	echo debut_droite('plugin', true);
 
-	echo debut_cadre_trait_couleur('',true,'',_T('plugins_liste'),'liste_plugins');
+
+	echo debut_cadre_trait_couleur('',true,'',_T('plugins_liste'),
+		'liste_plugins');
 	echo _T('texte_presente_plugin');
 
 	$lpf = liste_plugin_files();
 	$lcpa = liste_chemin_plugin_actifs();
 
-	$sub = "\n<div style='text-align:$spip_lang_right'>"
+
+	$sub = "\n<div style='text-align:".$GLOBALS['spip_lang_right']."'>"
 	.  "<input type='submit' value='"._T('bouton_valider')."' class='fondo' />"
 	. "</div>";
 
-	$corps = $sub
-	. affiche_arbre_plugins($lpf, $lcpa)
-	. "\n<br />"
-	. $sub;
+
+	// S'il y a plus de 10 plugins pas installes, les signaler a part ;
+	// mais on affiche tous les plugins mis a la racine
+	if (count($lpf) - count($lcpa) > 9
+	AND _request('afficher_tous_plugins') != 'oui') {
+		$lcpaffiche = array();
+		foreach ($lpf as $f)
+			if (!strpos($f, '/') OR in_array($f, $lcpa))
+				$lcpaffiche[] = $f;
+		$corps = "<p>"._L(count($lcpa).' plugins activ&#233;s.')."</p>\n"
+			. "<p><a href='". parametre_url(self(),'afficher_tous_plugins', 'oui') ."'>"._L(count($lpf).' plugins disponibles.')."</a></p>\n"
+			. affiche_arbre_plugins($lcpaffiche, $lcpa);
+
+	} else {
+		$corps = 
+			"<p>"._L(count($lcpa).' plugins activ&#233;s')."</p>\n"
+			. "<p>"._L(count($lpf).' plugins disponibles.')."</p>\n"
+			. (count($lpf)>20 ? $sub : '')
+			. affiche_arbre_plugins($lpf, $lcpa);
+	}
+
+
+	$corps .= "\n<br />" . $sub;
 
 	echo redirige_action_auteur('activer_plugins','activer','admin_plugin','', $corps, " method='post'");
 
+	if (include_spip('inc/charger_plugin')) {
+		echo formulaire_charger_plugin($retour);
+	}
+
 	echo fin_cadre_trait_couleur(true);
 	echo fin_gauche(), fin_page();
 
+
 }
 
 // http://doc.spip.org/@tree_open_close_dir
@@ -172,7 +196,7 @@ function affiche_arbre_plugins($liste_plugins,$liste_plugins_actifs){
 			var prefix = jQuery(this).parent().prev().attr('name');
 			if (!jQuery(this).siblings('div.info').html()) {
 				jQuery(this).siblings('div.info').prepend(ajax_image_searching).load(
-					jQuery(this).attr('href').replace(/admin_plugin/, 'info_plugin'), {},
+					jQuery(this).attr('href').replace(/admin_plugin|plugins/, 'info_plugin'), {},
 					function() {
 						document.location = '#' + prefix;
 					}
diff --git a/ecrire/inc/boutons.php b/ecrire/inc/boutons.php
index e75e5d3f05..67161a92ad 100644
--- a/ecrire/inc/boutons.php
+++ b/ecrire/inc/boutons.php
@@ -197,10 +197,10 @@ function definir_barre_boutons() {
 			new Bouton("cache-24.gif", "onglet_vider_cache");
 	}
 
-	if (@file_exists(_DIR_PLUGINS)
+	if (/*@file_exists(_DIR_PLUGINS)
 	AND is_dir(_DIR_PLUGINS)
-	AND autoriser('configurer', 'admin_plugins')
-	) {
+	AND */
+	autoriser('configurer', 'admin_plugin')) {
 		$sousmenu['admin_plugin']=
 			new Bouton("plugin-24.gif", "icone_admin_plugin");
 	}
diff --git a/ecrire/inc/charger_plugin.php b/ecrire/inc/charger_plugin.php
new file mode 100644
index 0000000000..efad6948b6
--- /dev/null
+++ b/ecrire/inc/charger_plugin.php
@@ -0,0 +1,312 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2007                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+
+/*
+ * Ce fichier est extrait du plugin charge : action charger decompresser
+ *
+ * Auteur : bertrand@toggg.com
+ * © 2007 - Distribue sous licence LGPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+# l'adresse du repertoire de telechargement et de decompactage des plugins
+#define('_DIR_PLUGINS_AUTO', _DIR_PLUGINS.'auto/');
+define('_DIR_PLUGINS_AUTO', _DIR_PLUGINS);
+
+include_spip('inc/plugin');
+
+
+function formulaire_charger_plugin($retour='') {
+	global $spip_lang_left, $spip_lang_right;
+
+	include_spip('inc/filtres');
+	include_spip('inc/actions');
+	include_spip('inc/presentation');
+
+
+	$message = _L("Vous pouvez installer des plugins dans le r&#233;pertoire <code>".joli_repertoire(_DIR_PLUGINS)."</code>.");
+
+
+	if (!is_dir(_DIR_PLUGINS_AUTO)
+	OR !is_writeable(_DIR_PLUGINS_AUTO)) {
+		$erreur = _L("Pour permettre l'installation automatique des plugins, veuillez cr&#233;er le r&#233;pertoire <code>".joli_repertoire(_DIR_PLUGINS_AUTO)."</code> et v&#233;rifier que le serveur est autoris&#233; &#224; y &#233;crire.").aide("droits");
+	}
+
+
+	if ($erreur) {
+		return debut_cadre_trait_couleur("spip-pack-24.png", true, "", _L('Ajouter des plugins'))
+		. "<p>".$message."</p>\n"
+		. "<p>".$erreur."</p>\n"
+		. fin_cadre_trait_couleur(true);
+	}
+
+
+	$res = "<table border='0' cellspacing='1' cellpadding='3' width=\"100%\">";
+
+	if ($retour) {
+		$res .= "<tr><td class='verdana2'>";
+		$res .= $retour;
+		$res .= "</td></tr>\n";
+	}
+
+
+	$res .= "<tr><td class='verdana2'>";
+
+	// TODO une liste multilingue a telecharger
+	$liste = array(
+		'http://files.spip.org/spip-zone/crayons.zip' => 'Les Crayons',
+		'http://files.spip.org/spip-zone/forms_et_tables_1_9_1.zip' => 'Forms &amp; tables',
+		'http://files.spip.org/spip-zone/autorite.zip' => 'Autorit&#233;',
+		'http://files.spip.org/spip-zone/cfg.zip' => 'CFG, outil de configuration',
+		'http://files.spip.org/spip-zone/ortho.zip' => 'Correcteur d\'orthographe'
+	);
+
+
+	$res .= _L('<p>S&#233;lectionnez ci-dessous un plugin ; SPIP le t&#233;l&#233;chargera et l\'installera dans le r&#233;pertoire <code>'.joli_repertoire(_DIR_PLUGINS_AUTO).'</code></p>
+	<p>Si ce plugin existe d&#233;j&#224;, il sera mis &#224; jour.</p>');
+
+	if ($liste) {
+		$menu = '';
+		foreach ($liste as $url => $titre)
+		$menu .= '<option value="'.entites_html($url).'">'.$titre."</option>\n";
+		$res .= "<p><select name='url_zip_plugin'>\n"
+			."<option>"._L('choisir...')."</option>"
+			.$menu."\n</select></p>\n";
+
+		$res .= _L("<p><label>... ou entrez l'adresse URL du fichier ZIP du plugin &#224; t&#233;l&#233;charger :");
+	} else
+		$res .= _L("<p><label>entrez l'adresse URL du fichier ZIP du plugin &#224; t&#233;l&#233;charger");
+
+	// TODO: OU l'adresse d'une liste de plugins
+	// TODO: OU uploadez un fichier ZIP ou une liste de plugins
+
+	$res .= "<br /><input type='text' name='url_zip_plugin2' value='http://files.spip.org/spip-zone/' size='50' /></label></p>\n";
+
+	$res .= "</td></tr>";
+	$res .= "</table>\n";
+
+	$res = ajax_action_post('charger_plugin', '', 'admin_plugin', '', $res);
+
+
+	$res = debut_cadre_trait_couleur("spip-pack-24.png", true, "", _L('Ajouter un plugin'))
+	. $res
+	. fin_cadre_trait_couleur(true);
+
+	return $res;
+
+}
+
+
+function chargeur_charger_zip($quoi = array())
+{
+	if (!$quoi) {
+		return true;
+	}
+	if (is_scalar($quoi)) {
+		$quoi = array('zip' => $quoi);
+	}
+	if (isset($quoi['depot']) || isset($quoi['nom'])) {
+		$quoi['zip'] = $quoi['depot'] . $quoi['nom'] . '.zip';
+	}
+	foreach (array(	'remove' => 'spip',
+					'dest' => _DIR_RACINE,
+					'plugin' => null,
+					'cache_cache' => null,
+					'rename' => array(),
+					'keep' => false, # keep a copy
+					'edit' => array())
+				as $opt=>$def) {
+		isset($quoi[$opt]) || ($quoi[$opt] = $def);
+	}
+
+	include_spip('inc/distant');
+	$contenu = recuperer_page($quoi['zip'], false, false,
+		8000000 /* taille max */);
+
+	$fichier = $quoi['dest'].basename($quoi['zip']);
+	if (!$contenu || !ecrire_fichier($fichier, $contenu)) {
+		spip_log('charger_decompresser impossible de charger ' . $quoi['zip']);
+		return 0;
+	}
+
+	include_spip('inc/pclzip');
+	$zip = new PclZip($fichier);
+	$list = $zip->listContent();
+	$i = count($list) - 1;
+	$path = explode('/', $list[$i]['filename']);
+	while ($i--) {
+		$act = explode('/', $list[$i]['filename']);
+		for ($j = 0; $j < count($path); ++$j) {
+			if ($j >= count($path) || $act[$j] != $path[$j]) {
+				break;
+			}
+		}
+		for ( ; $j < count($path); ++$j) {
+			unset($path[$j]);
+		}
+	}
+	$aremove = explode('/', $quoi['remove']);
+	$jmax = count($path);
+	for ($j = 0; $j < $jmax; ++$j) {
+		if ($j >= count($aremove) || $path[$j] != $aremove[$j]) {
+			break;
+		}
+		unset($path[$j]);
+	}
+	$adest = explode('/', $quoi['dest']);
+	$kmax = count($adest);
+	for ($k = 0 ; $k < $kmax && $j < $jmax; ++$j, ++$k) {
+		if ($path[$j] != $adest[$k]) {
+			break;
+		}
+		unset($adest[$k]);
+	}
+	$quoi['dest'] = implode('/', $adest);
+
+	$ok = $zip->extract(
+		PCLZIP_OPT_PATH, $quoi['dest'],
+		PCLZIP_OPT_SET_CHMOD, _SPIP_CHMOD,
+		PCLZIP_OPT_REPLACE_NEWER,
+		PCLZIP_OPT_REMOVE_PATH, $quoi['remove'] . "/");
+	if ($zip->error_code < 0) {
+		spip_log('charger_decompresser erreur zip ' . $zip->error_code .
+					' pour paquet: ' . $quoi['zip']);
+		return $zip->error_code;
+	}
+
+	# supprimer le fichier zip source ?
+	if (!$quoi['keep'])
+		@unlink($fichier);
+
+	if (!$quoi['cache_cache']) {
+		chargeur_montre_tout($quoi);
+	}
+	if ($quoi['rename']) {
+		chargeur_rename($quoi);
+	}
+	if ($quoi['edit']) {
+		chargeur_edit($quoi['dest'], $quoi['edit']);
+	}
+
+	if ($quoi['plugin']) {
+		chargeur_activer_plugin($quoi['plugin']);
+	}
+
+	spip_log('charger_decompresser OK pour paquet: ' . $quoi['zip']);
+
+	$sub = ',^'.preg_quote($quoi['remove'], ',') . '/,';
+	$size = $compressed_size = 0;
+	foreach ($list as $a => $f) {
+		$size += $f['size'];
+		$compressed_size += $f['compressed_size'];
+		$list[$a] = preg_replace($sub,'',$f['filename']);
+	}
+
+	return array(
+		'files' => $list,
+		'size' => $size,
+		'compressed_size' => $compressed_size,
+		'dirname' => preg_replace(',/.*,', '', $list[0])
+	);
+}
+
+// pas de fichiers caches et preg_files() les ignore (*sigh*)
+function chargeur_montre_tout($quoi)
+{
+	# echo($quoi['dest']);
+	if (!($d = @opendir($quoi['dest']))) {
+		return;
+	}
+	while (($f = readdir($d)) !== false) {
+		if ($f == '.' || $f == '..' || $f[0] != '.') {
+			continue;
+		}
+		rename($quoi['dest'] . '/' . $f, $quoi['dest'] . '/'. substr($f, 1));
+	}
+}
+
+// renommer des morceaux
+function chargeur_edit($dir, $edit)
+{
+	if (!($d = @opendir($dir))) {
+		return;
+	}
+	while (($f = readdir($d)) !== false) {
+		if ($f == '.' || $f == '..') {
+			continue;
+		}
+		if (is_dir($f = $dir . '/' . $f)) {
+			chargeur_edit($f, $edit);
+		}
+		$contenu = 	file_get_contents($f);
+		if (($change = preg_replace(
+				array_keys($edit), array_values($edit), $contenu)) == $contenu) {
+			continue;
+		}
+		$fw = fopen($f, 'w');
+		fwrite($fw, $change);
+		fclose($fw);
+	}
+}
+
+// renommer des morceaux
+function chargeur_rename($quoi)
+{
+/*
+ preg_files() est deficiante pour les fichiers caches, ca aurait pu etre bien pourtant ...
+*/
+	spip_log($quoi);
+	foreach ($quoi['rename'] as $old => $new) {
+		!is_writable($file = $quoi['dest'] . '/' . $old) ||
+			rename($file, $quoi['dest'] . '/'. $new);
+	}
+}
+
+// juste activer le plugin du repertoire $plugin
+function chargeur_activer_plugin($plugin)
+{
+	spip_log('charger_decompresser activer plugin: ' . $plugin);
+	include_spip('inc/plugin');
+	ecrire_plugin_actifs(array($plugin), false, 'ajoute');
+	ecrire_metas();
+}
+
+
+function liste_fichiers_pclzip($status) {
+	$list = $status['files'];
+	$ret = '<b>'._L((count($list)-1)." fichiers ("
+		.taille_en_octets($status['size']).') install&#233;s dans '._DIR_PLUGINS_AUTO.$list[0]).'</b>';
+
+	$l .= "<ul style='font-size:x-small;'>\n";
+	foreach ($list as $f) {
+		if (basename($f) == 'svn.revision')
+			lire_fichier(_DIR_PLUGINS_AUTO.$f,$svn);
+		if ($joli = preg_replace(',^(.*/)([^/]+/?)$,', '<span style="visibility:hidden">\1</span>\2',
+			substr($f, strlen($list[0]))))
+			$l .= "<li>".$joli."</li>\n";
+	}
+	$l .= "</ul>\n";
+
+	include_spip('inc/filtres');
+	if (preg_match(',<revision>([^<]+)<,', $svn, $t))
+		$rev = '<div>revision '.$t[1].'</div>';
+	if (preg_match(',<commit>([^<]+),', $svn, $t))
+		$date = '<div>' . affdate($t[1]) .'</div>';
+
+	return $ret . $rev . $date . $l;
+}
+
+?>
diff --git a/ecrire/inc/commencer_page.php b/ecrire/inc/commencer_page.php
index 03ca574fd0..48b5f3519f 100644
--- a/ecrire/inc/commencer_page.php
+++ b/ecrire/inc/commencer_page.php
@@ -202,18 +202,19 @@ function avertissement_messagerie() {
 // http://doc.spip.org/@alertes_auteur
 function alertes_auteur() {
 
-	if (autoriser('detruire')
-	AND (
-		@$GLOBALS['meta']['message_crash_tables']
-		OR false // autres alertes administrateur
-	)) {
-		$alertes = array();
-
-		if (@$GLOBALS['meta']['message_crash_tables']) {
-			include_spip('inc/maintenance');
-			if ($msg = message_crash_tables())
-				$alertes[] = $msg;
-		}
+	$alertes = array();
+
+	if (isset($GLOBALS['meta']['message_crash_tables'])
+	AND autoriser('detruire')) {
+		include_spip('inc/maintenance');
+		if ($msg = message_crash_tables())
+			$alertes[] = $msg;
+	}
+
+	if (isset($GLOBALS['meta']['plugin_erreur_activation'])
+	AND autoriser('configurer', 'plugins')) {
+		$alertes[] = $GLOBALS['meta']['plugin_erreur_activation'];
+		effacer_meta('plugin_erreur_activation'); // pas normal que ce soit ici
 	}
 
 	$alertes[] = avertissement_messagerie();
diff --git a/ecrire/inc/plugin.php b/ecrire/inc/plugin.php
index c2528f4fd9..5fee4d5ca6 100644
--- a/ecrire/inc/plugin.php
+++ b/ecrire/inc/plugin.php
@@ -57,6 +57,7 @@ function plugin_version_compatible($intervalle,$version){
 function liste_plugin_valides($liste_plug,&$infos, $force = false){
 	$liste = array();
 	$infos = array();
+
 	foreach($liste_plug as $plug)
 		$infos[$plug] = plugin_get_infos($plug,$force);
 	
@@ -101,7 +102,9 @@ function liste_plugin_valides($liste_plug,&$infos, $force = false){
 				}
 			}
 		}
-		if (count($liste_plug)){
+		if (count($liste_plug)) {
+			include_spip('inc/lang');
+			utiliser_langue_visiteur();
 			$erreurs = "";
 			foreach($liste_plug as $plug){
 				$necessite = "";
@@ -128,7 +131,8 @@ function liste_plugin_valides($liste_plug,&$infos, $force = false){
 					array('plugin' => $plug)
 				)."</li>";
 			}
-			ecrire_meta('plugin_erreur_activation',"<ul>$erreurs</ul>");
+			ecrire_meta('plugin_erreur_activation',
+				"<ul>$erreurs</ul>$necessite");
 		}
 	}
 	return $liste;
@@ -740,5 +744,4 @@ function plugin_propre($texte) {
 	return $texte;
 }
 
-
 ?>
-- 
GitLab