diff --git a/ecrire/balise/formulaire_.php b/ecrire/balise/formulaire_.php
index 5f6e8fedd16f6879ddd689c981358155437fc7b2..023ac20ab1f2e4a89f62b1d641f97001c22e1fd0 100644
--- a/ecrire/balise/formulaire_.php
+++ b/ecrire/balise/formulaire_.php
@@ -35,7 +35,7 @@ function existe_formulaire($form)
 
 	if (!$form) return ''; // on ne sait pas, le nom du formulaire n'est pas fourni ici
 
-	return find_in_path($form.'.' . _EXTENSION_SQUELETTES, 'formulaires/') ? $form : false;
+	return trouve_modele($form, 'formulaires/') ? $form : false;
 }
 
 
diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index 49f0ec205cd94196a3bedd6a878a5f9fb51dff1c..c726e0e76bebd3855bc66f766e6bf6294c5d74bd 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -846,18 +846,6 @@ function autoriser_sans_cookie($nom)
   return in_array($nom, $autsanscookie);
 }
 
-function tester_url_ecrire($nom){
-	// tester si c'est une page en squelette
-	if (find_in_path('prive/squelettes/contenu/' . $nom . '.' . _EXTENSION_SQUELETTES))
-		return 'fond';
-	// compat skels orthogonaux version precedente
-	elseif (find_in_path('prive/exec/' . $nom . '.' . _EXTENSION_SQUELETTES))
-		return 'fond_monobloc';
-	// attention, il ne faut pas inclure l'exec ici car sinon on modifie l'environnement
-	// par un simple #URL_ECRIRE dans un squelette (cas d'un define en debut d'exec/nom )
-	return (find_in_path("{$nom}.php",'exec/') OR charger_fonction($nom,'exec',true))?$nom:'';
-}
-
 // Fonction codant et decodant les URLS des objets SQL mis en page par SPIP
 // $id = numero de la cle primaire si nombre, URL a decoder si pas numerique
 // $entite = surnom de la table SQL (donne acces au nom de cle primaire)
@@ -1810,7 +1798,7 @@ function recuperer_fond($fond, $contexte=array(), $options = array(), $connect='
 		$page = evaluer_fond($f, $contexte, $connect);
 		if ($page === '') {
 			$c = isset($options['compil']) ? $options['compil'] :'';
-			$a = array('fichier'=>$fond.'.'._EXTENSION_SQUELETTES);
+			$a = array('fichier'=>$fond);
 			erreur_squelette(_T('info_erreur_squelette2', $a), $c);
 		}
 					 
@@ -1837,9 +1825,23 @@ function recuperer_fond($fond, $contexte=array(), $options = array(), $connect='
 		return $options['trim'] ? ltrim($texte) : $texte;
 }
 
-function trouve_modele($nom)
+// Trouve un squelette, par defaut dans le repertoire modeles/
+// Attention, si le 2arg fourni, il doit avoir le / final 
+function trouve_modele($nom, $dir='modeles/')
 {
-	return find_in_path( 'modeles/' . $nom.'.'. _EXTENSION_SQUELETTES);
+	return find_in_path($nom.'.'. _EXTENSION_SQUELETTES, $dir);
+}
+
+function tester_url_ecrire($nom){
+	// tester si c'est une page en squelette
+	if (trouve_modele($nom, 'prive/squelettes/contenu/'))
+		return 'fond';
+	// compat skels orthogonaux version precedente
+	elseif (trouve_modele($nom, 'prive/exec/'))
+		return 'fond_monobloc';
+	// attention, il ne faut pas inclure l'exec ici car sinon on modifie l'environnement
+	// par un simple #URL_ECRIRE dans un squelette (cas d'un define en debut d'exec/nom )
+	return (find_in_path("{$nom}.php",'exec/') OR charger_fonction($nom,'exec',true))?$nom:'';
 }
 
 // Charger dynamiquement une extension php
diff --git a/ecrire/public/compiler.php b/ecrire/public/compiler.php
index 152380a035a1a0fb18abf8fe2aaed42a985822ed..5c77168c40418130d9ec82ff4379a9b5c2a428e0 100644
--- a/ecrire/public/compiler.php
+++ b/ecrire/public/compiler.php
@@ -793,18 +793,34 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect='')
 
 	$squelette = $f($squelette, '', $boucles, $descr);
 
-
-	$a = compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
-
+	$boucles = compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
 	// restituer les echappements
-	if ($esc) foreach($a as $i=>$boucle) {
-		$a[$i]->return = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return chr($a[1]);'),
+	if ($esc) foreach($boucles as $i=>$boucle) {
+		$boucles[$i]->return = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return chr($a[1]);'),
 			$boucle->return);
-		$a[$i]->descr['squelette'] = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return "\\\\".chr($a[1]);'),
+		$boucles[$i]->descr['squelette'] = preg_replace_callback(",$inerte-(\d+)-,", create_function('$a', 'return "\\\\".chr($a[1]);'),
 			$boucle->descr['squelette']);
 	}
+	
+	$debug = ($boucles AND isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug');
+	if ($debug) {
+		include_spip('public/decompiler');
+		foreach($boucles as $id => $boucle) {
+			if ($id)
+			  $decomp = "\n/* BOUCLE " .
+			    $boucle->type_requete .
+			    " " .
+			    str_replace('*/', '* /', public_decompiler($boucle, $gram, 0, 'criteres')) .
+			    " */\n";
+			else $decomp = ("\n/*\n" . 
+				 str_replace('*/', '* /', public_decompiler($squelette, $gram)) 
+				 . "\n*/");
+			$boucles[$id]->return = $decomp .$boucle->return; 
+			$GLOBALS['debug_objets']['code'][$nom.$id] = $boucle->return;
+		}
+	}
 
-	return $a;
+	return $boucles;
 }
 
 // Point d'entree pour arbre de syntaxe abstraite fourni en premier argument
@@ -933,19 +949,16 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
 	// idem pour la racine
 	$descr['id_mere'] = '';
 	$corps = calculer_liste($squelette, $descr, $boucles);
-	$debug = (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode']=='debug');
 
-	if ($debug) {
-		include_spip('public/decompiler');
-		include_spip('public/format_' . _EXTENSION_SQUELETTES);
-	}
+
+
 	// Calcul du corps de toutes les fonctions PHP,
 	// en particulier les requetes SQL et TOTAL_BOUCLE
 	// de'terminables seulement maintenant
 
 	foreach($boucles as $id => $boucle) {
 		$boucle = $boucles[$id] = pipeline('pre_boucle', $boucle);
-		if ($boucle->return === false) continue;
+		if ($boucle->return === false) {$corps = false; continue;}
 		// appeler la fonction de definition de la boucle
 
 		if ($req = $boucle->type_requete) {
@@ -962,50 +975,17 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
 		} else $req = ("\n\treturn '';");
 
 		$boucles[$id]->return = 
-			"function BOUCLE" . strtr($id,"-","_") . $nom .
+			"\n\nfunction BOUCLE" . strtr($id,"-","_") . $nom .
 			'(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
 			$req .
-			"\n}\n\n";
-
-		if ($debug)
-			$GLOBALS['debug_objets']['code'][$nom.$id] = $boucles[$id]->return;
+			"\n}\n";
 	}
 
 	// Au final, si le corps ou un critere au moins s'est mal compile
 	// retourner False, sinon inserer leur decompilation
 	if (is_bool($corps)) return false;
-	foreach($boucles as $id => $boucle) {
-		if ($boucle->return === false) return false;
-		$boucle->return = "\n\n/* BOUCLE " .
-			$boucle->type_requete .
-			" " .
-			(!$debug ? '' : 
-			str_replace('*/', '* /', 
-				decompiler_criteres($boucle->param, 
-						$boucle->criteres))) .
-			" */\n\n " .
-			$boucle->return;
-	}
-
-	$secondes = spip_timer('calcul_skel');
-	spip_log("COMPIL ($secondes) [$sourcefile] $nom.php");
-
-	// Assimiler la fct principale a une boucle anonyme, c'est plus simple
-	$code = new Boucle;
-	$code->descr = $descr;
-	$code->return = '
-//
-// Fonction principale du squelette ' . 
-	$sourcefile . 
-	($connect ? " pour $connect" : '') . 
-	(!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
-	"\n//" .
-	(!$debug ? '' : ("\n/*\n" . 
-			str_replace('*/', '* /', public_decompiler($squelette)) 
-				      . "\n*/")) . "
-
-function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
 
+	$principal = "\nfunction " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {
 '
 	// reporter de maniere securisee les doublons inclus
 .'
@@ -1024,6 +1004,21 @@ function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0)
 		.", \$Cache, \$page, ".var_export($sourcefile,true).");
 }";
 
+	$secondes = spip_timer('calcul_skel');
+	spip_log("COMPIL ($secondes) [$sourcefile] $nom.php");
+
+	// Assimiler la fct principale a une boucle anonyme, pour retourner un resultat simple
+	$code = new Boucle;
+	$code->descr = $descr;
+	$code->return = '
+//
+// Fonction principale du squelette ' . 
+	$sourcefile . 
+	($connect ? " pour $connect" : '') . 
+	(!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
+	"\n//\n" .
+	$principal;
+
 	$boucles[''] = $code;
 	return $boucles;
 }
diff --git a/ecrire/public/debusquer.php b/ecrire/public/debusquer.php
index c6c2334bc7327fe4085e06f3e58cf8c5aaba355b..29a01ce793ac20f700ce465349d4fa281b316695 100644
--- a/ecrire/public/debusquer.php
+++ b/ecrire/public/debusquer.php
@@ -306,10 +306,10 @@ function trouve_squelette_inclus($script)
       // a defaut on cherche le param 'page'
       if (!preg_match("/'param' => '([^']*)'/", $script, $reg))
 	$reg[1] = "inconnu";
-  $incl = $reg[1] . '.' .  _EXTENSION_SQUELETTES . '$';
+  $incl = ',' . $reg[1] . '[.]\w$,';
 
   foreach($debug_objets['sourcefile'] as $k => $v) {
-    if (preg_match(",$incl,",$v)) return $k;
+    if (preg_match($incl, $v)) return $k;
   }
   return "";
 }
@@ -456,7 +456,7 @@ function debusquer_navigation_squelettes($self)
 	$t_skel = _T('squelette');
 	foreach ($debug_objets['sourcefile'] as $nom => $sourcefile) {
 		$self2 = parametre_url($self,'var_mode_objet', $nom);
-		$nav = !$boucles ? '' : debusquer_navigation_boucles($boucles, $nom, $self);
+		$nav = !$boucles ? '' : debusquer_navigation_boucles($boucles, $nom, $self, $sourcefile);
 		$temps = !isset($debug_objets['profile'][$sourcefile]) ? '' : _T('zbug_profile', array('time'=>$debug_objets['profile'][$sourcefile]));
 
 		$res .= "<fieldset><legend>"
@@ -482,17 +482,19 @@ function debusquer_navigation_squelettes($self)
 	return $res;
 }
 
-function debusquer_navigation_boucles($boucles, $nom_skel, $self)
+function debusquer_navigation_boucles($boucles, $nom_skel, $self, $nom_source)
 {
 	$i = 0;
 	$res = '';
 	$var_mode_objet = _request('var_mode_objet');
+	$gram = preg_match('/[.](\w+)$/', $nom_source, $r) ? $r[1] : '';
+
 	foreach ($boucles as $objet => $boucle) {
 		if (substr($objet, 0, strlen($nom_skel)) == $nom_skel) {
 			$i++;
 			$nom = $boucle->id_boucle;
 			$req = $boucle->type_requete;
-			$crit = decompiler_criteres($boucle->param, $boucle->criteres);
+			$crit = public_decompiler($boucle, $gram, 0, 'criteres');
 			$self2 = $self .  "&amp;var_mode_objet=" .  $objet;
 
 			$res .= "\n<tr style='background-color: " .
@@ -575,7 +577,9 @@ function debusquer_source($objet, $affiche)
 		$res = ancre_texte("<"."?php\n".$quoi."\n?".">");
 	} else if ($affiche == 'boucle') {
 		$legend = _T('boucle') . ' ' .  $nom;
-		$res = ancre_texte(decompiler_boucle($quoi));
+		// Le compilateur prefixe le nom des boucles par l'extension du fichier source.
+		$gram = preg_match('/^([^_]+)_/', $objet, $r) ? $r[1] : '';
+		$res = ancre_texte(public_decompiler($quoi, '', 0, 'boucle'));
 	} else if ($affiche == 'squelette') {
 		$legend = $GLOBALS['debug_objets']['sourcefile'][$objet];
 		$res = ancre_texte($GLOBALS['debug_objets']['squelette'][$objet]);
diff --git a/ecrire/public/decompiler.php b/ecrire/public/decompiler.php
index 6c0c10c3b1dba054f3ffec9dc6c6a63f93d6d978..c5594d6d6899ca301f1571816a305995d526998d 100644
--- a/ecrire/public/decompiler.php
+++ b/ecrire/public/decompiler.php
@@ -17,10 +17,10 @@ if (!defined("_ECRIRE_INC_VERSION")) return;
 function decompiler_boucle($struct, $fmt='', $prof=0)
 {
 	$nom = $struct->id_boucle;
-	$avant = public_decompiler($struct->avant, $fmt, $prof);
-	$apres = public_decompiler($struct->apres, $fmt, $prof);
-	$altern = public_decompiler($struct->altern, $fmt, $prof);
-	$milieu = public_decompiler($struct->milieu, $fmt, $prof);
+	$avant = decompiler_($struct->avant, $fmt, $prof);
+	$apres = decompiler_($struct->apres, $fmt, $prof);
+	$altern = decompiler_($struct->altern, $fmt, $prof);
+	$milieu = decompiler_($struct->milieu, $fmt, $prof);
 
 	$type = $struct->sql_serveur ? "$struct->sql_serveur:" : '';
 	$type .= ($struct->type_requete ? $struct->type_requete :
@@ -36,9 +36,9 @@ function decompiler_boucle($struct, $fmt='', $prof=0)
 	if ($crit AND !is_array($crit[0])) {
 		$type = strtolower($type) . array_shift($crit);
 	}
-	$crit = decompiler_criteres($crit, $struct->criteres, $fmt, $prof) ;
+	$crit = decompiler_criteres($struct, $fmt, $prof) ;
 
-	$f = 'format_boucle_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_boucle_' . $fmt;
 	return $f($avant, $nom, $type, $crit, $milieu, $apres, $altern, $prof);
 }
 	
@@ -48,24 +48,24 @@ function decompiler_include($struct, $fmt='', $prof=0)
 	foreach($struct->param ? $struct->param : array() as $couple) {
 		array_shift($couple);
 		foreach($couple as $v) {
-			$res[]= public_decompiler($v, $fmt, $prof);
+			$res[]= decompiler_($v, $fmt, $prof);
 		}
 	}
 	$file = is_string($struct->texte) ? $struct->texte :
-		public_decompiler($struct->texte, $fmt, $prof);
-	$f = 'format_inclure_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+		decompiler_($struct->texte, $fmt, $prof);
+	$f = 'format_inclure_' . $fmt;
 	return $f($file, $res, $prof);
 }
 
 function decompiler_texte($struct, $fmt='', $prof=0)
 {
-	$f = 'format_texte_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_texte_' . $fmt;
 	return strlen($struct->texte) ? $f($struct->texte, $prof) : '';
 }
 
 function decompiler_polyglotte($struct, $fmt='', $prof=0)
 {
-	$f = 'format_polyglotte_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_polyglotte_' . $fmt;
 	return $f($struct->traductions, $prof);
 }
 
@@ -76,32 +76,32 @@ function decompiler_idiome($struct, $fmt='', $prof=0)
 
 	$args = array();
 	foreach ($struct->arg as $k => $v) {
-		if ($k) $args[$k]= public_decompiler($v, $fmt, $prof);
+		if ($k) $args[$k]= decompiler_($v, $fmt, $prof);
 	}
 
 	$filtres =  decompiler_liste($struct->param, $fmt, $prof);
 
-	$f = 'format_idiome_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_idiome_' . $fmt;
 	return $f($struct->nom_champ, $module, $args, $filtres, $prof);
 }
 
 function decompiler_champ($struct, $fmt='', $prof=0)
 {
-	$avant = public_decompiler($struct->avant, $fmt, $prof);
-	$apres = public_decompiler($struct->apres, $fmt, $prof);
+	$avant = decompiler_($struct->avant, $fmt, $prof);
+	$apres = decompiler_($struct->apres, $fmt, $prof);
 	$args = $filtres = '';
 	if ($p = $struct->param) {
 		if ($p[0][0]==='')
 		  $args = decompiler_liste(array(array_shift($p)), $fmt, $prof);
 		$filtres = decompiler_liste($p, $fmt, $prof);
 	}
-	$f = 'format_champ_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_champ_' . $fmt;
 	return $f($struct->nom_champ, $struct->nom_boucle, $struct->etoile, $avant, $apres, $args, $filtres, $prof);
 }
 
 function decompiler_liste($sources, $fmt='', $prof=0) {
 	if (!is_array($sources)) return '';
-	$f = 'format_liste_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_liste_' . $fmt;
 	$res = '';
 	foreach($sources as $arg) {
 		if (!is_array($arg))  {
@@ -115,7 +115,7 @@ function decompiler_liste($sources, $fmt='', $prof=0) {
 			AND (strlen($v[0]->apres) == 1)
 			AND $v[0]->apres == $v[0]->avant)
 			  $args[]= $v[0]->avant . $v[0]->texte . $v[0]->apres;
-			else $args[]= public_decompiler($v, $fmt, 0-$prof);
+			else $args[]= decompiler_($v, $fmt, 0-$prof);
 		}
 		if (($r!=='') OR $args) $res .= $f($r, $args, $prof);
 	}
@@ -126,11 +126,11 @@ function decompiler_liste($sources, $fmt='', $prof=0) {
 // - le phraseur fournit un bout du source en plus de la compil
 // - le champ apres signale le critere {"separateur"} ou {'separateur'}
 // - les champs sont implicitement etendus (crochets implicites mais interdits)
-function decompiler_criteres($sources, $comp, $fmt='', $prof=0) {
+function decompiler_criteres($boucle, $fmt='', $prof=0) {
+	$sources = $boucle->param;
 	if (!is_array($sources)) return '';
 	$res = '';
-	$f = 'format_critere_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
-	include_spip('public/format_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES));
+	$f = 'format_critere_' . $fmt;
 	foreach($sources as $crit) {
 		if (!is_array($crit)) continue; // boucle recursive
 		array_shift($crit);
@@ -158,10 +158,9 @@ function decompiler_criteres($sources, $comp, $fmt='', $prof=0) {
 }
 
 
-function public_decompiler($liste, $fmt='', $prof=0)
+function decompiler_($liste, $fmt='', $prof=0)
 {
 	if (!is_array($liste))  return '';
-	include_spip('public/format_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES));
 	$prof2 = ($prof < 0) ? ($prof-1) : ($prof+1);
 	$contenu = array();
 	foreach($liste as $k => $p) {
@@ -190,7 +189,14 @@ function public_decompiler($liste, $fmt='', $prof=0)
 	    $contenu[] = array($d($p, $fmt, $prof2), $p->type);
 
 	}
-	$f = 'format_suite_' . ($fmt ? $fmt : _EXTENSION_SQUELETTES);
+	$f = 'format_suite_' . $fmt;
 	return $f($contenu);
 }
+
+function public_decompiler($liste, $fmt='', $prof=0, $quoi='') 
+{
+	if (!include_spip('public/format_' . $fmt)) return "'$fmt'?";
+	$f = 'decompiler_' . $quoi;
+	return $f($liste, $fmt, $prof);
+}
 ?>
diff --git a/ecrire/public/parametrer.php b/ecrire/public/parametrer.php
index fa782cd1cf7a0f1d2869b88a4c272bd469818fde..2f567f084c36fb946ddfdde33aaf5587d524b5d2 100644
--- a/ecrire/public/parametrer.php
+++ b/ecrire/public/parametrer.php
@@ -59,7 +59,7 @@ function public_parametrer_dist($fond, $contexte='', $cache='', $connect='')  {
 
 	$styliser = charger_fonction('styliser', 'public');
 	list($skel,$mime_type, $gram, $sourcefile) =
-		$styliser($fond, $contexte, $GLOBALS['spip_lang'], $connect, _EXTENSION_SQUELETTES);
+		$styliser($fond, $contexte, $GLOBALS['spip_lang'], $connect);
 
 	if ($skel) {
 
diff --git a/ecrire/public/styliser.php b/ecrire/public/styliser.php
index 0acd8abfb86b0b2ad966037eea16877199da8d75..46ab4e2715f431a87d35112d92cf761efbfe8db4 100644
--- a/ecrire/public/styliser.php
+++ b/ecrire/public/styliser.php
@@ -31,7 +31,7 @@ if (!defined("_ECRIRE_INC_VERSION")) return;
  *
  * http://doc.spip.org/@public_styliser_dist
  */
-function public_styliser_dist($fond, $contexte, $lang='', $connect='', $ext='html') {
+function public_styliser_dist($fond, $contexte, $lang='', $connect='') {
 
 	// Choisir entre $fond-dist.html, $fond=7.html, etc?
 	$id_rubrique = 0;
@@ -42,10 +42,13 @@ function public_styliser_dist($fond, $contexte, $lang='', $connect='', $ext='htm
 	// trouver un squelette du nom demande
 	// ne rien dire si on ne trouve pas, 
 	// c'est l'appelant qui sait comment gerer la situation
-	$base = find_in_path("$fond.$ext");
+	$squelette = trouve_modele($fond,"");
 	
-	// supprimer le ".html" pour pouvoir affiner par id_rubrique ou par langue
-	$squelette = substr($base, 0, - strlen(".$ext"));
+	// supprimer l'extension pour pouvoir affiner par id_rubrique ou par langue
+	if ($squelette AND preg_match('/^(.*)[.](\w+)$/', $squelette, $r)) {
+		list(, $squelette, $ext) = $r;
+	} else $ext = '';
+		
 	$flux = array(
 		'args' => array(
 			'id_rubrique' => $id_rubrique,