i18n

Internationalisation d'une application Android

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Les magasins avec les applications sont disponibles en plusieurs langues. Les développeurs des applications peuvent donc multiplier leurs revenus par des miliers de personnes. Sauf que leurs applications doivent fonctionner en plusieurs langues.

Notre application n'est pas une exception à la régle. Elle va également fonctionner pour des utilisateurs connaissant un des 3 langues : français, polonais ou anglais. Ce sera d'ailleurs une bonne occasion d'aborder la gestion de l'internationalisation (i18n) d'une application Android. A travers cet article on verra comment elle est gérée par le système ainsi que comment on peut la gérer manuellement.

Implémenter i18n sous Android

La traduction du contenu d'une application est gérée automatiquement par Android. Le système vérifie l'existence des répertoires avec le contenu correspondant à la valeur de la Locale de l'utilisateur.

Dans le répertoire /res on retrouve un sous-répertoire qui par défaut porte le nom "values". Le contenu de ce sous-répertoire regroupe toutes les données utilisées par défaut par l'application. Supposons qu'icontient un fichier strings.xml qui définit le message "goodMorningMsg" par la chaîne de caractères "Good morning". L'autre sous-répertoire du /res s'appelle "values-fr". Il contient également un fichier strings.xml avec "Bonjour" associé au message "goodMorningMsg".

Maintenant, si la langue de l'application est français, Android va aller chercher le code "goodMorningMsg" dans le fichier /res/values-fr/strings.xml. Quand la langue sera modifiée en anglais, il va tenter de récupérer le message "goodMorningMsg" dans /res/values-en/strings.xml. Cependant, ce fichier n'existe pas et la ressource demandée pour cette langue est indisponible. Dans cette situation, Android ira regarder du côté des valeurs par défaut, stockées dans /res/valeurs/strings.xml. Voici l'exemple concret de ce propos issu de notre application :

< -- /res/values/strings.xml -->
    <string name="label_account">My account
    <string name="label_books">Books
    <string name="label_webapp">Consult the website
    <string name="label_contact">Contact us
    <string name="label_personnalize">Customize book page
< -- /res/values-fr/strings.xml -->
    <string name="label_account">Mon compte
    <string name="label_books">Livres
    <string name="label_webapp">Voir le site
    <string name="label_contact">Contactez-nous
    <string name="label_personnalize">Personnaliser la page "livre"

Et le code du layout qui récupérera ces message :

    <Button
        android:id="@+id/buttonAccount"
        android:layout_width="150dp"
        android:layout_height="75dp"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/buttonBooks"
        android:layout_below="@id/mainWelcomeText"
        android:text="@string/label_account"
        android:onClick="goToMyAccount"
    />
    <Button 
        android:id="@+id/buttonBooks"
        android:layout_width="150dp"
        android:layout_height="75dp" 
        android:layout_alignParentRight="true"
        android:layout_below="@id/mainWelcomeText"
        android:text="@string/label_books"
        android:onClick="goToBooksList"
    />
    <Button
        android:id="@+id/buttonWebapp"
        android:layout_width="150dp"
        android:layout_height="75dp"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/buttonContact"
        android:text="@string/label_webapp"
        android:layout_below="@id/buttonAccount"
        android:onClick="goToWebapp"
    />
    <Button
        android:id="@+id/buttonContact"
        android:layout_width="150dp"
        android:layout_height="75dp"
        android:layout_alignParentRight="true"
        android:text="@string/label_contact"
        android:layout_below="@id/buttonBooks"
        android:onClick="goToContactForm"
    />
    <Button
        android:id="@+id/buttonCustomize"
        android:layout_width="139dp"
        android:layout_height="75dp"
        android:layout_alignParentLeft="true"
        android:text="@string/label_personnalize"
        android:layout_below="@id/buttonContact"
        android:onClick="goToCustomize"
    />

Dans ce cas, la récupération du message se fait automatiquement, via le code spécifié à la suite du @string/. Cependant, il est possible d'effectuer cette récupération manuellement :

defaultDemandType = getResources().getString(R.string.contact_select_item);

Cette récupération se base sur les ressources. La gestion des ressources sous Android sera expliquée plus loin.

Non seulement des ressources textuelles sont "internationalisables". Les autres (drawable, anim, layout) le sont aussi.

Comment changer la langue de l'application Android ?

Malgré beaucoup d'automatismes dans la fonctionnalité de traduction, Android permet également de manipuler la langue utilisée manuellement. Le changement manuel se base sur l'appel de la méthode updateConfiguration() de la classe Resources. Cette fonction s'occupe de mettre à jour l'instance de la classe Configuration qui contient tous les paramètres utilisés par l'application. On y retrouve le type du clavier, les dimensions de l'écran ainsi que la Locale currante de l'application. Voici le code qui permet de modifier cette dernière explicitement :

public class BaseActivity extends FragmentActivity {
    // ...
    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
        // ...
                alertDialogBuilder
               .setMessage(resources.getString(R.string.lang_select))
                .setCancelable(true)
                .setPositiveButton(resources.getString(R.string.form_submit),new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int id) {    
                        dialog.cancel();
                        Locale locale = new Locale(locales[langPosition]);
                        Locale.setDefault(locale);
                        Configuration config = new Configuration();
                        config.locale = locale;
                        globalContext.getResources().updateConfiguration(config, globalContext.getResources().getDisplayMetrics());
                        refreshActivity();
                    }
                })
        // ...
    }
}

Le code commence par la définition d'une nouvelle Locale. Ensuite elle est passée à l'objet config qui, par la suite, est transmis en paramètre dans la méthode updateConfiguration(). L'appel de la fonction refreshActivity() a pour but de refraîchir l'écran sur lequel se trouve l'utilisateur au moment du changement de la langue.

Bartosz KONIECZNY Internationalisation

Une question ? Une remarque ?

*

*

Un conseil Zend Framework

Comment faciliter le travail entre notre application et l'Ajax ?

L'un des moyens est l'utilisation du ContextSwitch. Il permet de définir le type de réponse renvoyé.