asp.NET étape par étape - Tome 5 :: Internationalisation d'une application asp.NET

N'hésitez pas à commenter cet article ! Commentez Donner une note à l'article (5)

Article lu   fois.

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Présentation

L'internationalisation consiste à rendre un site utilisable dans différentes langues et selon différentes cultures. Ceci a toute son importance car toutes les cultures n'ont pas la même manière de formater les nombres, la justification du texte diffère d'une zone géographique à l'autre. Il existe d'autres paramètres tels que l'unité monétaire.

Il existe toute une série de solutions pour internationaliser un site. On peut effectivement créer différentes pages en différentes langues et, selon le choix de l'utilisateur, rediriger vers ces pages. Une autre solution est d'utiliser une page dont on modifie le texte selon la langue et la région choisie. Ce texte peut provenir d'une base de données, d'un fichier XML ou d'une toute autre source de données.

Microsoft a instauré dans .NET différentes techniques pour effectuer ces opérations. Ce sont ces techniques qui sont décrites dans ce chapitre.

II. Objets nécessaires pour l'implémentation des solutions Microsoft

Quelque soit la solution adoptée, le namespace à utiliser afin de détecter la culture du client est System.Globalization. On retrouvera ainsi dans notre code :

Namespace à utiliser
Sélectionnez
using System.Globalization ;

Pour détecter la culture du client, on utilise l'objet Request, instancié implicitement lors de toute requête http et qui permet d'accéder aux entêtes http et d'en récupérer les valeurs. Il contient ainsi diverses informations quant au client et à son navigateur comme par exemple sa langue ainsi que son pays d'origine. A l'aide de ces informations, il est possible d'instancier un objet CultureInfo. Cet objet a pour but de retenir la langue ainsi que la culture de l'utilisateur.

Ainsi lors d'une requête au serveur, le client envoie une série d'informations telles que celles présentées dans l'exemple suivant. On notera la présence du paramètre Accept-Language. C'est celui-ci qui est utilisé pour détecter la langue du navigateur qui a effectué la requête.

Exemple d'entête HTTP
Sélectionnez
GET /page.aspx HTTP/1.0
User-Agent : Mozilla/4.0
Accept : image/gif, image/jpg, text/* */*
Accept-Language: fr, en-gb;q=0.8, en;q=0.7

<infos supplémentaires éventuelles - surtout pour POST>

L'instanciation d'un objet CultureInfo est donc à la base de toutes les solutions. Celle-ci s'effectue de la manière suivante :

Détection de la langue et de la culture
Sélectionnez
string Lang = Request.UserLanguages[0]; // Principal Language
CultureInfo CurrentCulture = new CultureInfo(Lang);

III. Solutions possibles pour internationaliser une application web

Il existe diverses solutions afin d'internationaliser une application web qui sont :

  • détection et redirection :
    Cette solution utilise différentes pages, chaque page comportant les textes d'une langue particulière. Il peut également y avoir des séparations de page selon les cultures ou tout autre besoin spécifique.
  • modification à l'exécution :
    Il n'existe qu'une version de la page, le texte étant mis à jour dynamiquement, à l'exécution.
  • utilisation du Web.Config :
    En modifiant la valeur de la langue et de la culture directement dans le Web.Config, les textes, dates et autres sont mis en forme selon cette configuration. Ceci implique que tous les utilisateurs auront le même résultat quelque soit leurs cultures.
  • utilisation de fichiers ressources satellites :
    Cette solution est semblable à la deuxième solution si ce n'est que les fichiers ressources sont optimisés, c'est pourquoi on l'utilise pour de grandes quantités de textes.

III-A. Détection et redirection

La solution la plus simple est la suivante : une page de base détecte la culture à utiliser et redirige vers la page correspondante. Ceci ne doit être utilisé que si il y a beaucoup de texte à traduire (pour des raisons de performances).

Image non disponible

Le désavantage de cette technique est évidemment un nombre accru de pages ainsi qu'un risque d'incohérence entre les pages correspondantes, ce qui peut être très contraignant si cette cohérence a de l'importance.

Par contre, la redirection vers la page correspondante peut se faire vers un site dont la localisation est plus proche du client, diminuant ainsi les temps de réponse.

Il faut également noter qu'un langage peut ne pas être reconnu par .NET. C'est le cas de Kyrgys (cyrillique) par exemple. Il est donc préférable d'utiliser des try/catch pour éviter toute exception non désirée. Dans la gestion de l'exception, on peut simplement spécifier une langue par défaut.

Le code correspondant est le suivant :

Détection et redirection
Sélectionnez
string Lang = Request.UserLanguages[0]; // Principal Language
CultureInfo CurrentCulture = new CultureInfo(Lang);
Response.Redirect("detectAndRedirect" + CurrentCulture.Name.Substring(0, 2) + ".aspx");

III-B. Modifications à l'exécution

La détection de la langue et la réponse se font dans la même page. A l'inverse du point précédent, il est bon d'utiliser cette technique uniquement dans le cas d'un nombre peu élevé de traductions à effectuer.

Les avantages de cette technique sont qu'il n'existe qu'une seule version du code compilé et déployé et qu'il n'y a aucune redirection rendant l'application centralisée. Suivant les besoins, on peut également y trouver d'autres avantages.

Il existe deux types principaux de modifications dynamiques : les traductions et la modification de la langue sur laquelle se baser.

Traductions

À l'aide de la langue préalablement récupérée, il suffit de différencier les cas comme dans l'exemple suivant :

Détection et traduction
Sélectionnez
string Lang = Request.UserLanguages[0]; // Principal Language
CultureInfo CurrentCulture = new CultureInfo(Lang);

switch (CurrentCulture.Name.Substring(0, 2).ToUpper())
{
    case "FR":
        LaText.Text = "Texte en français...";
        break;
    case "EN":
    default:
        LaText.Text = "Text written in English...";
        break;
}

Cependant, cela peut être assez lourd dans le cas où beaucoup d'informations doivent être traduites. Si le nombre d'informations est élevé, il serait préférable d'utiliser les satellites. Cette technique est présentée dans la suite du document.

Modification de la langue de l'utilisateur

Il est possible, de manière dynamique, de mettre à jour la culture à utiliser en utilisant la propriété statique CurrentCulture de la classe Thread.

 
Sélectionnez
string lang = Request.UserLanguages(0) ;
Thread.CurrentThread.CurrentCulture = new CultureInfo(lang) ;

Cependant, il est nécessaire de se souvenir la langue d'un appel de page à l'autre. Effectivement, la modification de la culture du thread courant n'est active que pour la durée du thread. A chaque requête étant associé un thread, le thread est arrêté dès l'affichage de la page en question. On utilisera une variable de session à cet effet.

Cette technique sera souvent associée à un choix dans une liste déroulante.

Changement dynamique de la langue de l'utilisateur
Sélectionnez
private void Page_Load(object sender, System.EventArgs e)
{
    if (!Page.IsPostBack || Session["User-Language"] == null)
    {
        CultureInfo CurrentCulture = new CultureInfo(Request.UserLanguages[0]);
        Session["User-Language"] = Request.UserLanguages[0];
    }
    LaText.Text = CurrentCulture.Name;
}

private void BuChangeLanguage_Click(object sender, EventArgs e)
{
    Thread.CurrentThread.CurrentCulture = new CultureInfo(DdlLanguage.SelectedValue);
    LaText.Text = Thread.CurrentThread.CurrentCulture.Name;
    Session["User-Language"] = Thread.CurrentThread.CurrentCulture.Name;
}

III-C. Utilisation du Web.Config

Lorsque le serveur asp.NET, qui est généralement IIS mais cela pourrait être Apache ou n'importe quel autre serveur web, doit formater des dates par exemple, il vérifie la configuration de l'application dans le Web.Config. Si il trouve l'information sur la langue et la culture à utiliser, il formate les divers éléments selon cette information.

Ainsi, il s'agit d'utiliser l'attribut culture de l'élément globalization qui se trouve dans ce fichier Web.Config.

Extrait du Web.Config
Sélectionnez
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="FR-BE">

Dans le cas d'un Web.Config non-existant, le serveur se servira de la valeur présente dans le machine.Config, le fichier de configuration générale du serveur. Généralement, la valeur est neutral. Avec cette configuration, le formatage dépendra de la langue installé sur le système hôte du serveur.

III-D. Utilisation de fichiers ressources satellites

Les fichiers .dll sont des fichiers que l'on retrouve dans la plupart des applications .NET (il peut être encapsulé dans le fichier .exe). Le but principal de ces fichiers est de contenir le code MSIL (Microsoft Intermediate Language) de l'application mais ils peuvent également contenir des ressources telles que :

  • les traductions de textes
  • des images
  • des fichiers textes
  • tout autre élément nécessaire au bon fonctionnement de l'application.

Cette encapsulation de fichiers permet d'éviter tout risque de suppression ou de modification du fichier.

Bien entendu, plusieurs fichiers .dll satellites (c'est-à-dire qui ne contiennent pas le point d'entrée de l'application) peuvent cohabiter au sein d'une même application, ce qui permet le principe de la réutilisabilité.

Dans le cadre de ce chapitre, les ressources qui nous intéressent sont les traductions. Celles-ci se trouvent dans des fichiers .resources.

Le principe de cette technique est de détecter la culture à utiliser et de charger le satellite correspondant. Cette technique doit être utilisée pour des applications générant le contenu à l'exécution ou qui ont un nombre élevé de composants exécutables.

Les avantages sont semblables à ceux du paragraphe sur la modification à l'exécution si ce n'est que la mise en place est plus aisée.

C'est grâce à la valeur de CurrentUICulture de la classe Thread que .NET est capable de déterminer quel fichier .resources est à utiliser. C'est donc cette propriété qui doit être modifiée si l'on souhaite modifier la langue à utiliser.

Schématiquement, voici le principe :

Image non disponible

Pour utiliser cette technique, il est nécessaire que tous les éléments asp.NET de la page .aspx à traduire possèdent les attributs « runat » (dont la valeur est « server ») et « id ». Il en va de même pour les HTMLControls dont le contenu doit être traduit sans quoi il sera impossible au serveur de modifier les valeurs correspondantes.

  • Les étapes du développement sont alors :
    Création d'un fichier ressource contenant les valeurs par défaut dans le cas où la culture ne serait pas reconnue ou non supportée. Ce fichier a une extension .resx, par exemple developpez.resx. Les valeurs de ce fichier auront la forme :
Correspondance clé / valeur
Sélectionnez
nomPage.nomControle = valeurDeLaLangue

Pour être précis, il suffit que la clé soit unique. Le fait de prendre nomPage.nomControle comme clé est une convention et permet de retrouver plus facilement les valeurs dans les fichiers ressources.

La création de ce fichier ne se fait pas « à la dure » mais bien dans l'environnement de développement. Prenons l'exemple de Visual Studio .NET 2003 :

Image non disponible
  • Création d'un fichier ressource par culture supportée. Ceci donnera, par exemple, les fichiers developpez.en.resx et developpez.fr.resx
  • Création d'un fichier ressource pour la région si l'on souhaite être plus précis (en France, le « GSM » belge s'appelle « portable » et en Suisse « Natel »), il est possible de créer des fichiers ressources dont les noms seront developpez.fr-FR.resx et developpez.fr-BE.resx
  • Écriture du code permettant le chargement à l'aide de la classe ResourceManager. Celle-ci se trouve dans le namespace Resources. On trouvera donc dans notre code :
Chargement d'un satellite
Sélectionnez
using System.Resources ;protected ResourceManager manager = new ResourceManager(" NomDuNamespace.developpez ", typeof(Satellite).Assembly) ;
  • « developpez » est le nom du satellite dans cet exemple. Le fait de passer comme argument le nom du namespace permet de pointer le fichier .dll qui contient le fichier ressources.

Cette classe peut avoir d'autres arguments. Pour de plus amples informations, je vous conseille de lire la documentation MSDN :

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemresourcesresourcemanagermemberstopic.asp

Écriture du code permettant de détecter la culture de l'utilisateur afin d'assigner la propriété CurrentCulture de la classe Thread, propriété qui est utilisée pour déterminer le formatage des dates et autres…

Nous ne reviendrons pas dessus, ceci a déjà été présenté dans les paragraphes précédents.

  • Écriture du code permettant de récupérer les valeurs des différents satellites afin de les afficher dans la page Web
Chargement d'une valeur à partir d'un satellite
Sélectionnez
manager.GetString(" nomPage.nomControle ") ;

Il est préférable de lire « Best Practices for Developping World-Ready Applications » sur MSDN Online à l'adresse

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemresourcesresourcemanagermemberstopic.asp

Utilisation d'un fichier satellite
Sélectionnez
protected Label LaText;

protected ResourceManager manager = new ResourceManager("Tests_Globalization.TestsGlobalization", typeof(satellite).Assembly);

private void Page_Load(object sender, System.EventArgs e)
{
	if (Session["User-Language"] != null)
		Thread.CurrentThread.CurrentUICulture = new CultureInfo(Session["User-Language"].ToString());

	LaText.Text = manager.GetString("satellite2.LaText");
}

III-E. Inconvient du système

Les fichiers ressources créés se trouvent dans les fichiers dll comme nous l'avons vu. Il est donc nécessaire de recompiler l'application, ou tout du moins une partie de celle-ci, lorsque l'on souhaite modifier le contenu de ces fichiers.

En fait, lorsque l'on récupère des informations dans ces fichiers ressources, .NET récupère au préalable le fichier correspondant et qui est encapsulé dans la dll.

Pour éviter cette recompilation, il suffit donc de spécifier au manager qu'il doit utiliser un fichier .resources qui n'est pas inclus dans une dll. Cela se fait par :

Utiliser un fichier .resources non inclus dans une dll
Sélectionnez
ResourceManager manager = ResourceManager.CreateFileBasedResourceManager(value, path, null);

Il est possible de générer dynamiquement ce fichier, ce qui peut avoir diverses utilités comme nous le verrons dans le paragraphe suivant.

Cette génération se fait à l'aide des lignes de code suivantes :

Génération dynamique d'un fichier .resources
Sélectionnez
FileStream fs = new FileStream(" items.resources " , FileMode.OpenOrCreate, FileAccess.Write);
IResourceWriter writer = new ResourceWriter(fs);

writer.AddResource(" clé ", " valeur ");
writer.Generate();
writer.Close();

Pour pouvoir utiliser les différentes classes présentes dans le code précédent, il est nécessaire d'utiliser

Inclusions nécessaire pour la génération dynamique d'un fichier .resources
Sélectionnez
using System.IO ;
using System.Resources ;

Il est également possible de générer des fichiers .resources à partir de fichiers texte ou de fichiers XML. Pour cela, je vous renvoie vers MSDN :

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconresourcesintextfileformat.asp

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2005 Didier Danse. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.