Cyril Mottier

“It’s the little details that are vital. Little things make big things happen.” – John Wooden

Maîtriser Les Ressources De Type "String" Et "Plurals"

Voici maintenant un petit moment que je rédige des articles en anglais. Ces derniers traitent d'un travail sur lequel je passe pas mal de temps et qui, je pense, est nécessaire pour essayer d'uniformiser les applications Android tout en facilitant la vie du développeur : ce projet c'est GreenDroid. Cette fois, j'ai envie de revenir aux origines ! C'est donc avec plaisir que j'écris ces lignes en français, pour les francophones aussi bien débutants qu'expérimentés.

Je ne vais rien vous apprendre en affirmant que le développement sous Android repose principalement sur 2 entités distinctes :

  • Le code source (contenu dans le répertoire src sous Eclipse) écrit en Java et intégrant la logique sous-jacente d'une application

  • Les ressources (contenues dans le répertoire res dans une arborescence classique) qui ont des formes variées (XML, images, etc.). Les ressources n'ont pas de notion de logique mais représentent plus le contenu et la “forme” de l'application

Il existe un très grand nombre de ressources disponibles sous Android. J'ai déjà largement traité de nombreuses d'entre-elles comme les Drawables (dans une présentation que j'ai donné aux Android Developers Labs de Paris - présentation disponible sur SlideShare et code source téléchargeable sur GitHub) ou les layouts (dans presque tous les articles de ce blog : si vous n'avez jamais remarqué, honte à vous !). Il existe énormément d'autres types de ressources sur Android (couleurs, styles, thèmes, etc.) mais nous allons ici nous attarder sur une ressource rarement abordée mais pourtant essentielle : les chaines de caractères et le fichier strings.xml.

Les chaines de caractères simples

Lorsqu'on souhaite utiliser des chaines de caractères dans une application, il suffit d'inclure la chaine dans les ressources de type “string” comme montré ci-dessous :

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="application_name">My Application</string>
    <string name="application_description">This is my first Android application!</string>

</resources>

La récupération d'une chaine de caractères s'effectue ensuite grâce à son nom (ou name). Le code ci-dessous est extrait d'une Activity (et donc d'un Context) et montre comment récupérer de façon efficace et rapide la valeur d'une chaine de caractères :

1
final String appName = getString(R.string.application_name);

Lorsque vous ne disposez que du Context (dans une View par exemple), il est nécessaire de d'abord récupérer les ressources :

1
final String appName = context.getResources().getString(R.string.application_name);

Les chaines de caractères formatées

Il est parfois utile de créer des chaines un peu plus développées que de simple chaines fixes. Imaginons par exemple que nous souhaitions avoir une chaine de caractères décrivant un album de musique et contenant le nombre de chansons ainsi que le titre de l'album. Concaténer manuellement les différentes parties de la chaine de caractères est un travail long est inutile. En effet, Android gère parfaitement les chaines formatées et autorise donc une syntaxe comme montré ci-dessous. Pour une documentation complète sur les possibilités des chaines de caractère formatées, n'hésitez pas à vous reporter à la documentation de Formatter

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="album_description">%1$s contains %2$d songs</string>

</resources>

Pour utiliser la chaine de caractères, il suffit alors d'utiliser le code suivant (dans le contexte d'une Activity):

1
final String albumDescription = String.format(getString(R.string.album_description), albumName, songCount);

C'est simple non ? Eh bien, comme à son habitude, le framework Android vous facilite encore plus la vie ! La méthode getString(int) a, en effet, été surchargée et accepte un nombre illimité de paramètres :

1
final String albumDescription = getString(R.string.album_description, albumName, songCount);

Le type plurals

Dans l'exemple précédent, il est possible de rencontrer un problème assez gênant. Lorsque qu'il n'y a qu'une seule chanson dans l'album, l'application va bêtement afficher “Banana contains 1 songs”. Dommage … mais cela peut être géré assez facilement grâce à Android et l'utilisation du type de ressource “plurals” !

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <plurals name="album_description">
        <item quantity="one">%1$s contains %2$d song</item>
        <item quantity="other">%1$s contains %2$d songs</item>
    </plurals>

</resources>

Grâce au fichier ressource ci dessous, nous venons de déclarer une chaine formatée qui se comporte différemment suivant que la quantité affichée a une valeur de un (one) ou plus (other). Dans votre code, rien de plus simple :

1
final String albumDescription = getQuantityString(R.plurals.album_description, songCount, albumName, songCount);

Note : Mon seul regret avec l'utilisation des ressources de type “plurals” et l'absence d'un item de quantité “zero”. Dans de tel cas, le framework utilise la valeur de other et affiche donc “0 songs”. Je ne comprends pas pourquoi cette valeur a été évincée du framework par Google. Un oubli (j'en doute), une raison particulière (surement mais laquelle ???) ? Vous devrez donc gérer ce cas à la main.

L'internationalisation des chaines de caractères - i18n

Regrouper l'intégralité des chaines de caractères dans les fichiers ressources permet de séparer efficacement le code source et le design des ressources textuelles. Ainsi, lorsque vous devez traduire ou faire traduire votre application, il vous suffit simplement de dupliquer le fichier strings.xml original et de modifier les valeurs de chaque chaines. L'externalisation de l'intégralité des chaines présentes dans votre application (layouts, code source, etc.) et donc vital à l'évolution de votre application. Le code suivant est donc totalement à proscrire de vos applications :

1
2
3
4
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="This is a TextView" />

Pour finir, il est également possible de faciliter le travail des traducteurs en utilisant le format XLIFF dans vos chaines de caractères. Cette spécification dont la description détaillée est disponible ici permet de laisser le traducteur se concentrer sur le texte à traduire. Personnellement, je trouve cette spécification sympa mais je doute de son utilité dans une application à taille réduite comme c'est le cas pour beaucoup d'applications mobiles.

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <plurals name="found_contact">
        <item quantity="one">Found 1 contact</item>
        <item quantity="other">Found <xliff:g id="count">%1$d</xliff:g> contacts</item>
    </plurals>

</resources>