I. Définition▲
Nous pouvons distinguer plusieurs types de ressources :
- les fichiers de ressources de l'application (images, chaînes de caractères, layout, xml) qui dépendent du contexte (langue française, taille de l'écran, mode portrait/paysage…) ;
- les bases de données ;
- les fichiers préférences ;
- les fichiers pour la lecture et la lecture/écriture sans contexte.
Toutes ces ressources se trouvent dans votre application sous res/.
II. Fichiers de ressources▲
Ces types de ressources sont celles utilisées par l'application et interprétées par le système Android. Elles sont de quatre types :
- res\drawable pour les images ;
- res\raw pour les ressources brutes, les fichiers sans contexte dont nous parlerons au chapitre suivant ;
- res\values pour les chaînes de caractères, les couleurs, les tableaux et les dimensions ;
- res\xml pour les fichiers XML.
II-A. Gestion des chaînes de caractères : l'internationalisation▲
Pour la gestion de l'internationalisation, la convention veut que le dossier contienne la langue associée : res\values-fr pour le français, res\values-en pour l'anglais et ainsi de suite. « en » et « fr » sont, respectivement, les valeurs usuelles des langues anglaise et française lors de l'internationalisation. Sa gestion devient alors transparente au développeur.
Il y a cinq types de chaînes, les normales, celles avec paramètres, celles au singulier/pluriel, celles en tableaux et celles au format HTML dont nous ne parlerons pas.
Ainsi le fichier suivant présente les quatre types de chaînes qui nous intéressent :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--Simple string-->
<string
name
=
"hello"
>
Hello World, ResourcesTuto!</string>
<string
name
=
"app_name"
>
ResourcesTuto</string>
<string
name
=
"simpleString"
>
Good Morning My name is Bond, James Bond</string>
<!--String with parameters ($s for string, $d for decimal (any decimal: integer, double, float...)-->
<string
name
=
"param_message"
>
Hello, i love %1$s, i hate %2$s, i am %3$d years old</string>
<!--String array-->
<string-array
name
=
"i_like_array"
>
<item>
chocolate</item>
<item>
television</item>
<item>
internet</item>
<item>
nicotine</item>
<item>
hug</item>
<item>
Santa Claus</item>
</string-array>
<!--Plurals String-->
<plurals
name
=
"singleOrPlural"
>
<item
quantity
=
"one"
>
I am alone on moon</item>
<item
quantity
=
"other"
>
I am 6 900 000 000 on earth</item>
</plurals>
</resources>
Les chaînes simples s'utilisent, soit dans le code :
getString
(
R.string.simpleString)
soit dans le layout.xml pour déclarer un composant en utilisant son identifiant :
<TextView
android
:
id
=
"@+id/simpleStringTV"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/hello"
/>
Les chaînes avec paramètres s'utilisent avec un formateur.
Dans le fichier strings.xml, nous avons déclaré la chaîne :
<!--String with parameters ($s for string, $d for decimal (any decimal:integer, double, float...)-->
<string
name
=
"param_message"
>
Hello, i love %1$s, i hate %2$s, i am %3$d years old</string>
Nous la manipulons ainsi en Java :
// Then instanciate a string with paremeter
String parameterString=
String.format
(
getString
(
R.string.param_message),"peace"
,"war"
,2
);
// And set the text view
TextView textViewWithParam=(
TextView)findViewById
(
R.id.parameterStringTV);
textViewWithParam.setText
(
parameterString);
Les chaînes peuvent être regroupées sous forme de tableaux :
<!--String array-->
<string-array
name
=
"i_like_array"
>
<item>
chocolate</item>
<item>
television</item>
<item>
internet</item>
<item>
nicotine</item>
<item>
hug</item>
<item>
Santa Claus</item>
</string-array>
Dans le code, celui-ci se manipule ainsi :
// Instanciate the resources object:
Resources resources=
getResources
(
);
String[] planets =
resources.getStringArray
(
R.array.i_like_array);
Les chaînes peuvent aussi posséder un genre singulier ou pluriel :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals
name
=
"numberOfSongsAvailable"
>
<item
quantity
=
"one"
>
One song found.</item>
<item
quantity
=
"other"
>
%d songs found.</item>
</plurals>
</resources>
et s'utilisent dans le code ainsi :
int
count =
getNumberOfHuman
(
);
Resources res =
getResources
(
);
String humans =
res.getQuantityString
(
R.plurals.singleOrPlural, count);
Il faut faire attention aux signes ‘ et "
<string
name
=
"good_example"
>
"This'll work"</string>
<string
name
=
"good_example_2"
>
This\'ll also work</string>
<string
name
=
"bad_example"
>
This doesn't work</string>
II-A-1. Le cas des chaînes de caractères HTML▲
Celui-ci est un cas particulier, car le code HTML est du texte à balises, ce qui perturbe le parser XML et empêche la compilation de votre code.
Une manière de contourner le problème est de mettre la balise < en lieu et place du <.
Un exemple, dans votre fichier string.xml :
<string
name
=
"html_head"
>
<
html><
body><
table><
tr><
th width=\"50%\">Jour<
/th><
th>Basse<
/th><
th>Haute<
/th><
th>Tendance<
/th><
/tr></string>
<string
name
=
"html_loop"
>
<
tr><
td align=\"center\">%1$s<
/td><
td align=\"center\">%2$s<
/td><
/td><
td align=\"center\">%3$s<
/td><
td><
img src=\"%4$s\"><
/td><
/tr></string>
<string
name
=
"html_foot"
>
<
/table><
/body><
/html></string>
Le code Java pour utiliser cette chaîne :
StringBuffer bufResult =
new
StringBuffer
(
getResources
(
).getString
(
R.string.html_head));
String tempLine;
for
(
Forecast forecast : forecasts) {
tempLine=
String.format
(
getResources
(
).getString
(
R.string.html_loop),
forecast.getDay
(
),forecast.getLowTemp
(
),forecast.getHighTemp
(
),
forecast.getIcon
(
));
bufResult.append
(
tempLine);
}
bufResult.append
(
getResources
(
).getString
(
R.string.html_foot));
browser.loadDataWithBaseURL
(
null
, bufResult.toString
(
), "text/html"
, "UTF-8"
, null
);
Noter l'absence de l'appel aux méthodes fromHtml et toHtml qui ne nous ont pas paru efficientes.
II-B. Les images▲
Les formats acceptés sont PNG et JPEG (GIF n'est pas recommandé).
Il suffit de déposer les fichiers image dans res\drawable pour qu'ils soient référencés par le système.
Ainsi l'image res/drawable/myimage.png peut être utilisée,
soit dans le code :
Resources res =
getResources
(
);
Drawable drawable =
res.getDrawable
(
R.drawable.myimage);
soit dans la description des IHM dans le fichier de layout :
<ImageView
android
:
layout_height
=
"wrap_content"
android
:
layout_width
=
"wrap_content"
android
:
src
=
"@drawable/myimage"
/>
II-B-1. Exemple d'utilisation des ressources▲
Cet exemple possède quatre fichiers, le code, le fichier des chaînes de caractères, le fichier de layout et enfin un fichier selector qui n'est là que pour le plaisir et qui choisit une image en fonction de l'état de l'objet sur lequel il est.
Cet exemple montre des TextView, une scroll et deux ImageButton instanciés, soit directement dans leur déclaration XML, soit dans le code Java.
Le fichier des strings (res\values\strings.xml) :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--Simple string-->
<string
name
=
"hello"
>
Hello World, ResourcesTuto!</string>
<string
name
=
"app_name"
>
ResourcesTuto</string>
<string
name
=
"simpleString"
>
Good Morning My name is Bond, James Bond</string>
<!--String with parameters ($s for string, $d for decimal (any decimal:integer, double, float...)-->
<string
name
=
"param_message"
>
Hello, i love %1$s, i hate %2$s, i am %3$d years old</string>
<string
name
=
"spinner"
>
Do you like: </string>
<!--String array-->
<string-array
name
=
"i_like_array"
>
<item>
chocolate</item>
<item>
television</item>
<item>
internet</item>
<item>
nicotine</item>
<item>
hug</item>
<item>
Santa Claus</item>
</string-array>
<!--Plurals String-->
<plurals
name
=
"singleOrPlural"
>
<item
quantity
=
"one"
>
I am alone on moon</item>
<item
quantity
=
"other"
>
I am 6 900 000 000 on earth</item>
</plurals>
<string
name
=
"button"
>
An image on the button</string>
</resources>
Le fichier de déclaration des layouts :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
orientation
=
"vertical"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
>
<TextView
android
:
id
=
"@+id/simpleStringTV"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/hello"
>
</TextView>
<TextView
android
:
id
=
"@+id/simpleStringToSetTV"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
>
</TextView>
<TextView
android
:
id
=
"@+id/parameterStringTV"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
>
</TextView>
<TextView
android
:
id
=
"@+id/pluralsTV"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
>
</TextView>
<Spinner
android
:
id
=
"@+id/Spinner01"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
prompt
=
"@string/spinner"
>
</Spinner>
<ImageButton
android
:
id
=
"@+id/ImageButtonXmlInstanciatedIB"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
src
=
"@drawable/icon"
>
</ImageButton>
<ImageButton
android
:
id
=
"@+id/ImageButtonToInstanciateIB"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
>
</ImageButton>
</LinearLayout>
Le fichier Java :
public
class
ResourcesTuto extends
Activity {
@Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.main);
// Instanciate the resources object:
Resources resources=
getResources
(
);
// Then instanciate the textView @+id/simpleStringToSetTV
TextView textViewSimple=(
TextView)findViewById
(
R.id.simpleStringToSetTV);
textViewSimple.setText
(
getString
(
R.string.simpleString));
// Then instanciate a string with paremeter
String parameterString=
String.format
(
getString
(
R.string.param_message),"peace"
,"war"
,2
);
// And set the text view
TextView textViewWithParam=(
TextView)findViewById
(
R.id.parameterStringTV);
textViewWithParam.setText
(
parameterString);
// Then instanciate a string with plurals or not
int
number=
0
;
if
(
Math.random
(
)<
0.5
d) {
number=
1
;
}
else
{
number=
2
;
}
String pluralsString=
resources.getQuantityString
(
R.plurals.singleOrPlural, number);
// And its associated textView
TextView textViewPlurals=(
TextView)findViewById
(
R.id.pluralsTV);
textViewPlurals.setText
(
pluralsString);
String[] planets =
resources.getStringArray
(
R.array.i_like_array);
// Then instanciate the spinner using the array string
Spinner spinner =
(
Spinner) findViewById
(
R.id.Spinner01);
ArrayAdapter<
CharSequence>
adapter =
ArrayAdapter.createFromResource
(
this
, R.array.i_like_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource
(
android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter
(
adapter);
// Then find a ressource for the ImageButton
Drawable drawableBck=
resources.getDrawable
(
R.drawable.selector);
Drawable drawable=
resources.getDrawable
(
R.drawable.icon);
// And set it:
ImageButton imageButton=(
ImageButton)findViewById
(
R.id.ImageButtonToInstanciateIB);
imageButton.setBackgroundDrawable
(
drawableBck);
imageButton.setImageDrawable
(
drawable);
}
}
Et enfin le fichier de sélection d'une image (res\drawable\selector.xml) :
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
>
<!-- when focused -->
<item
android
:
state_focused
=
"true"
android
:
drawable
=
"@drawable/sky"
/>
<!-- when pressed -->
<item
android
:
state_pressed
=
"true"
android
:
drawable
=
"@drawable/coffee"
/>
<!-- when normal -->
<item
android
:
drawable
=
"@drawable/icon"
/>
</selector>
Vous remarquerez qu'en fonction de l'état, le fichier pointe sur une ressource différente. Ces ressources sont des fichiers png stockés sous res\drawable et nommés coffee.png et sky.png. Il est à remarquer que les états, pour un ImageButton quand il a le focus, passent de focused à normal puis à pressed. Les valeurs possibles pour un tel fichier sont :
<selector
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
constantSize
=
[
"true"
|
"false"
]
android
:
dither
=
[
"true"
|
"false"
]
android
:
variablePadding
=
[
"true"
|
"false"
] >
<item
android
:
drawable
=
"@[package:]drawable/drawable_resource"
android
:
state_pressed
=
[
"true"
|
"false"
]
android
:
state_focused
=
[
"true"
|
"false"
]
android
:
state_selected
=
[
"true"
|
"false"
]
android
:
state_checkable
=
[
"true"
|
"false"
]
android
:
state_checked
=
[
"true"
|
"false"
]
android
:
state_enabled
=
[
"true"
|
"false"
]
android
:
state_window_focused
=
[
"true"
|
"false"
]>
</item>
</selector>
II-B-2. Pour aller au-delà▲
http://developer.android.com/guide/topics/resources/drawable-resource.html
En fait il existe neuf types d'images différentes pour Android :
- Bitmap File sont les fichiers .png, .jpeg et .gif présentés ci-dessus ;
- Nine-Patch file est un fichier png avec des régions étirables pour permettre le redimensionnement de l'image ;
- Layer List est un tableau d'images ;
- StateList est un fichier XML qui référence des images pour des états différents (typiquement pour un bouton qui possède plusieurs états focus, pressed, released). Nous venons de le voir au sein du fichier selector.xml ;
- LevelList est un fichier XML qui référence des images pour des niveaux différents, chaque image est associée à une valeur numérique maximale ;
- TransitionDrawable est un fichier XML qui référence deux images réalisant une morphose de l'une à l'autre ;
- ClipDrawable est un fichier XML qui décrit une image se dévoilant petit à petit (via du code) ;
- ScaleDrawable est un fichier XML décrivant une image qui pourra être zoomée ;
- ShapeDrawable est un fichier XML qui décrit une forme géométrique (ovale, rectangle…). C'est une image dessinée de manière informatique comme un graphique 2D.
Enfin, pour aller encore plus loin, il faut aller voir 2D Graphics :
http://developer.android.com/guide/topics/graphics/2d-graphics.html
II-C. Les fichiers XML▲
Ils se trouvent sous res\xml\ et on y accède par getResources().getXml(R.xml.nomDuFichier) qui retourne un XmlPullParser sur le fichier.
try
{
XmlPullParser xpp =
getResources
(
).getXml
(
R.xml.words);
while
(
xpp.getEventType
(
) !=
XmlPullParser.END_DOCUMENT) {
if
(
xpp.getEventType
(
) ==
XmlPullParser.START_TAG) {
if
(
xpp.getName
(
).equals
(
"word"
)) {
items.add
(
xpp.getAttributeValue
(
0
));
}
}
xpp.next
(
);
}
}
catch
(
Throwable t) {
Toast.makeText
(
this
, "Request failed: "
+
t.toString
(
), 4000
).show
(
);
}
Le XmlPullParser est assez simpliste comme parseur, il ne connaît que les méthodes :
- next qui renvoie la ligne suivante ;
- getName qui renvoie le nom de la balise ;
- getValue qui renvoie la valeur contenue au sein de la balise ;
-
et getEventType qui renvoie :
- End_Document quand le document est fini,
- Start_Tag quand il rencontre une balise ouvrante,
- End_Tag quand il en rencontre une fermante.
Autant dire que pour la manipulation de fichier XML, il vaut mieux rester humble.
II-D. Les couleurs▲
Elles se placent sous res\values et peuvent se nommer color.xml :
<resources>
<color
name
=
"opaque_red"
>
#f00</color>
<color
name
=
"translucent_red"
>
#80ff0000</color>
</resources>
Chaque couleur est décrite par son nom et son code RGB hexadécimal.
Dans le code, elles s'utilisent comme ça :
Resources res =
getResources
(
);
int
color =
res.getColor
(
R.color.opaque_red);
et dans un fichier de ressources :
<TextView
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
textColor
=
"@color/translucent_red"
android
:
text
=
"Hello"
/>
II-E. Les styles et thèmes▲
La convention souhaite que ce fichier soit enregistré sous res\values\styles.xml, il peut alors être référencé dans votre application par la balise @style/MonStyle.
Les styles et les thèmes d'une application peuvent être surchargés ou définis :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style
name
=
"ToDoTheme"
parent
=
"@android:style/Theme.Black"
>
<item
name
=
"android:textSize"
>
12sp</item>
</style>
</resources>
ou bien :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style
name
=
"MyTheme"
>
<item
name
=
"android:textSize"
>
12sp</item>
<item
name
=
"android:textColor"
>
#111</item>
</style>
<style
name
=
"MySubTheme"
parent
=
"MyTheme"
; >
<item
name
=
"android:textSize"
>
8sp</item>
</style>
</resources>
Et il sera utilisé dans le descripteur de ressources (le layout.xml) de la manière suivante :
<TextView
style
=
"@style/CodeFont"
android
:
text
=
"@string/hello"
/>
De plus, un style peut être appliqué à un ensemble de composants ayant spécifié un inputType, ou plus exactement la notion d'inputType peut être incluse dans le style. Ainsi, au lieu d'écrire :
<EditText
android
:
inputType
=
"number"
... />
on écrira un style spécifique pour les éléments graphiques de type inputType=number :
<style
name
=
"Numbers"
>
<item
name
=
"android:inputType"
>
number</item>
...
</style>
que l'on associera à cet élément (et à tous ceux qui sont de type inputType number) :
<EditText
style
=
"@style/Numbers"
... />
Lorsque l'on affecte à l'ensemble de l'activité ou de l'application un style, cela s'appelle un thème. Ce thème se spécifie dans le fichier manifest.xml (et non plus dans le layout.xml).
Pour l'application :
<application
android
:
theme
=
"@style/CustomTheme"
>
Pour une activité de l'application :
<activity
android
:
theme
=
"@android:style/Theme.Dialog"
>
Cela marche de manière identique aux styles, on peut les spécifier et déclarer les nôtres (on les appelle par @style/MonTheme)
<style
name
=
"CustomDialogTheme"
parent
=
"@android:style/Theme.Dialog"
>
<item
name
=
"android:windowBackground"
>
@drawable/custom_dialog_background</item>
</style>
et on l'applique :
<activity
android
:
theme
=
"@style/CustomDialogTheme"
>
La liste des styles Android se trouve ici : http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/res/res/values/styles.xml;h=d7b654e49809cb97a35682754b1394af5c8bc88b;hb=HEAD
et celles des thèmes sous : http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/res/res/values/themes.xml;h=6b3d7407d1c895a3c297e60d5beac98e2d34c271;hb=HEAD
Pour utiliser ces thèmes et ces styles afin de les surcharger, il suffit de remplacer l'underscore par un point :« @android:style/Theme.NoTitleBar ».
II-F. La localisation des ressources▲
Ou, comment Android décide quel est le fichier de ressources à utiliser. Cela se comprend bien dans le cas de l'internationalisation, mais ce concept est étendu à l'arbre des devices Android. Cette liste de paramètres pris en compte par Android est la suivante :
- code réseau et code mobile du pays (le pays et le réseau de la carte SIM) dit code MCC (Mobile Country Code) et MNC (Mobile Network Code);http://en.wikipedia.org/wiki/Mobile_Network_Code;
- langue et région (internationalisation usuelle) ;
- taille de l'écran (small, medium et large) ;
- le rapport largeur/longueur (long ou not long) de l'écran ;
- l'orientation de l'écran (port pour portrait, land pour landscape ou square pour carré) ;
- densité de l'écran en pixel (ldpi pour low dpi, mdpi pour medium dpi et hdpi pour high dpi) ;
- type d'écran tactile (notouch pour non sensitif, stylus pour le stylet et finger pour sensitif) ;
- visibilité du clavier (keyexposed pour clavier physique apparent, keyshidden pour clavier physique caché ou keysoft pour un clavier logiciel) ;
- type de clavier (nokeys, qwerty ou 12Key) ;
- type de navigation (nonav pour pas de navigation, dpad pour le pad, trackball pour trackball et wheel pour la roue de la souris) ;
Ainsi, pour définir la branche dans laquelle se trouve votre ressource, il faut spécifier son chemin :
- il faut définir dans l'ordre des paramètres ci-dessus listés ;
- on peut omettre des éléments ;
- il faut un unique qualificateur par type de paramètre ;
- il faut les séparer par un trait d'union.
Ainsi mcc234-mcn20-en-rUK-small-long-port-ldpi-finger-keysoft-qwerty-dpad spécifie le chemin pour le Royaume-Uni, pour l'opérateur « Hutchison 3G UK Ltd », en langue anglaise pour le Royaume-Uni, pour un petit portable au format 16/9, en mode portrait, avec peu de densité de points par inch, qui est sensitif au toucher, avec un clavier logiciel de type qwerty dont la navigation se fait au pad.
Maintenant que nous avons bien conscience du délire complet d'établir une application Android pour l'arbre complet des choix, il faut comprendre la stratégie d'Android pour choisir quelles ressources il va utiliser et comment minimiser le nombre de ressources spécifiques que nous allons implémenter.
Android choisira le dossier contenant le nombre de qualificateurs qui correspondent le plus avec ceux du portable utilisateur, et dans la négative, il choisira celui dont la locale est identique. Cela permet une épuration drastique de cet arbre : n'utiliser que ce qui vous paraît vraiment pertinent. Ensuite si Android ne trouve pas de correspondance, il enverra une exception, donc il faut toujours définir, pour toutes les ressources , le dossier par défaut, celui qui ne contient pas de qualificateur. Donc toujours avoir un dossier res\values\, res\drawable, de même pour vos ressources layout, anim, raw, xml et tutti quanti.
Lorsqu'Android détecte un changement sur le matériel de l'une de ces valeurs, il détruit et reconstruit l'application. Pour tempérer ce comportement, il faut rajouter dans la description de votre activité la ligne android :configChanges= « orientation|keyboardhidden ». Cela supprime ce comportement pour les paramètres spécifiés et déclenche la méthode onConfigurationChanged de votre activité. Les valeurs possibles sont orientation, keyboardhidden, fontscale, locale, keyboard, touchscreen et navigation. Dans le code, il suffit d'évaluer _newConfig.orientation dans la méthode OnConfigChanged pour retrouver la nouvelle orientation et associer le traitement qui s'ensuit, de même pour les autres paramètres.
Les consignes d'Android concernant ce sujet sont :
- concevez votre application pour qu'elle marche pour toutes les locales (res\values doit toujours exister) ;
- concevez avec des layouts flexibles qui s'adaptent à la taille de l'écran, pas de taille en dur ;
- ne créez pas plus de ressources que nécessaire ;
- utilisez le contexte Android pour avoir un « look-up » manuel : context.getResources().getConfiguration().locale.getDisplayName();
- testez vos applications avec différentes configurations ;
- définissez la liste des paramètres que vous prenez en compte, gravez la dans le marbre, testez toutes ces configurations et publiez cette liste quand vous déposez votre application sur l'Android market
III. Remerciements▲
Nous tenons à remercier FRANOUCH pour la relecture orthographique de cet article et Mickael Baron pour la mise au format Developpez.com.