How-To : Créer une application ASP.NET multi-culturelle  par la société Magnitude (http://www.magnit.com)

ocaliser une application, c'est la rendre accessible à chacun de ses clients dans sa propre langue. Ce processus est souvent négligé ou repoussé en fin de projet par les équipes de développement. Pourtant, son implémentation devrait être prise en compte dès la phase de design et d'architecture, au même titre que la sécurité : c'est une démarche structurante et l'on risque si l'on n'y prend pas garde assez tôt d'être confronté à de graves impasses.

Le cas des applications Web est encore plus délicat du fait du nombre relativement plus élevé de textes et d'éléments graphiques à localiser. Heureusement, ASP.NET et HTML fournissent aujourd'hui une infrastructure complète permettant la mise au point d'applications et de sites réellement multiculturels.


Une même page ASP.NET peut apparaître dans des langues différentes suivant la culture de l'internaute.

L'étendue du problème

La localisation ne consiste pas simplement à choisir au moment de l'affichage d'une page les bonnes chaînes de caractères. Il convient aussi de choisir le bon jeu de caractères, d'afficher les dates, les heures, les montants monétaires et les nombres dans le format localement accepté, d'adopter les conventions locales de tri des chaînes de caractères, et même d'interpréter correctement les saisies des utilisateurs.

Si on souhaite également s'adresser aussi aux milliards de personnes écrivant de droite à gauche et/ou de haut en bas, c'est toute la structure des pages qui peut être bouleversée.

Tout ceci doit naturellement se faire de manière transparente pour l'utilisateur, qui ne doit à aucun moment percevoir les difficultés de la localisation. Au contraire, le site doit détecter sa culture et s'y adapter au mieux et automatiquement, sans demander d'action de sa part (ne serait-ce qu'un "clic" sur un drapeau).

Les approches les plus courantes

Il existe principalement deux grandes familles de solutions pour concevoir des sites multiculturels : on peut soit dupliquer le site, soit rendre chaque page multiculturelle. Voici une présentation succincte des avantages et inconvénients de chaque approche :

·         Mise en ouvre : La première approche présente l'avantage d'être techniquement d'une grande simplicité : les différentes langues sont pratiquement des sites distincts, et aucun outil particulier n'est nécessaire à la localisation. Dans le cas d'une arborescence unique, c'est au niveau de chaque page qu'il convient de prévoir le support multiculturel, au moyen d'outils adaptés.

·         Maintenance : Multiplier les arborescences signifie immanquablement multiplier d'autant la charge de maintenance du site. Des divergences entre versions viennent en général aggraver le problème. Les techniques de localisation à arborescence unique présentent l'avantage de mieux séparer le contenu de la mise en page et de la logique. Les différentes versions d'un document se trouvant en un même lieu, la maintenance et la traduction sont facilitées.

·         Gestion des liens : Si l'arborescence est unique, la maintenance des liens est simple. On peut communiquer une URL sans se préoccuper de la culture du destinataire.

·         Bascule vers une culture par défaut : Le choix de la culture à afficher est naturel dans le cas d'une arborescence unique, et peut même se faire avec une granularité inférieure à la page. Si on multiplie les arborescences, la bascule vers une culture par défaut nécessite par exemple d'intercepter l'erreur 404.

En définitive, ce qui doit gouverner le choix d'une de ces deux approches est la nature même de la différentiation des différentes versions du site.

Si celles-ci sont des sites distincts, dont la structure est susceptible de diverger fortement, les arborescences doivent être multipliées. C'est typiquement le cas d'un site à forte dominance "contenus" et dont les mises à jour peuvent être effectuées en toute autonomie par des autorités locales.

Si les versions ne sont que des traductions partielles ou complètes d'un site père, l'arborescence ne devrait pas être multipliée. C'est le cas par exemple d'un site applicatif.

Dans le cas d'une arborescence unique, les contenus localisés peuvent soit être mémorisés dans des fichiers de ressources, soit dans les pages elles-mêmes.

Cet article traitera principalement de l'architecture à arborescence unique.

Les standards internationaux

Les codes culturels

Plusieurs normes régissent la codification des cultures. La codification utilisée sur le web est décrite par la RFC1766 et code la culture par un code généralement de la forme "xx" ou "xx-YY". xx est un code de langue sur deux lettres minuscules défini par la norme ISO 639-1. Ces codes de langues varient assez peu du fait que même si des pays apparaissent et disparaissent couramment, les langues, elles, restent stables sur notre échelle de temps. YY est un code de pays ou région sur deux ou trois lettres majuscules régi par la norme ISO 3166

Ces codes varient chaque fois qu'un pays apparaît ou disparaît.

Le code "fr-FR" décrit ainsi le français tel qu'il est parlé en France, alors que "fr-CA" définit le français tel qu'il est parlé au Canada.

Cette codification complète permet de définir un mécanisme simple de basculement automatique : les navigateurs récents transmettent presque tous dans le header de chaque requête une liste des codes de culture acceptés par le navigateur. On tente tout d'abord de mettre en correspondance le code de culture complet avec les versions disponibles de la ressource demandée. Si une correspondance exacte n'est pas possible, on recherche une correspondance sur le seul code de langue. Si aucune correspondance n'est trouvée, on bascule sur la culture par défaut.

Bien sûr, on peut mettre en place des mécanismes plus complexes afin de permettre une mise en correspondance quelconque des codes culturels avec les versions disponibles.

La plupart des sites ne poussera toutefois pas le raffinement jusqu'à une différentiation des versions au-delà du simple code de langue : il est déjà suffisamment complexe de mettre à jour un site en cinq langues. Dans le cas où on ne souhaite décrire que la langue, on emploiera un code sur deux caractères tel que "en" ou "fr".

La culture d'une page peut être déclarée dans les attributs Culture et uiCulture de la directive @Page d'un WebForm :

<%@ Page language="c#" Culture="fr" uiCulture="fr"%>

Le sens de l'écriture

Malgré l'étendue de la population mondiale n'écrivant pas de gauche à droite, puis de haut en bas, seuls des navigateurs récents sont capables de modifier leur direction d'écriture (Internet Explorer implémente cette fonctionnalité depuis la version 5.5).

L'attribut de style à employer pour modifier la direction de l'écriture au sein d'un élément HTML est"writing-mode"et fait partie de la proposition de norme CSS3 (voir http://www.w3c.org/TR/css3-text/#Progression):

<div style="writing-mode:tb-rl">
       Ce texte s'affiche de haut en bas, puis de droite à gauche
</div>

A noter que cette fonctionnalité a bien d'autres applications que l'affichage de l'arabe ou du cantonais.

Jeux de caractères

Aux débuts de l'informatique, les ordinateurs ne traitaient pas de texte mais seulement des nombres. Puis, le code ASCII a encodé sur 7 bits les lettres majuscules et minuscules, les chiffres, quelques symboles de ponctuation et des séquences d'échappement. Le monde de l'informatique ne s'adressait encore semble-t-il qu'aux anglo-saxons : pas le moindre caractère accentué n'était disponible en standard. De nombreuses variantes de l'ASCII, codées sur 8 bits, ont permis de rendre utilisables les ordinateurs dans les pays dont l'alphabet ne comporte pas trop de caractères.

Le passage à des caractères codés sur plus de 8 bits selon la norme Unicode autorise l'encodage de pratiquement toutes les langues connues, vivantes ou mortes, avec toutes leurs spécificités, ainsi que de nombreux symboles. Unicode coïncide avec l'ASCII sur les 127 premiers caractères, les autres caractères agissant comme des séquences d'échappement permettant d'exprimer des caractères sur deux, trois ou quatre octets. Le nombre de caractères pouvant être codés en Unicode dépasse aujourd'hui les 90000.

Le jeu de caractères employé doit être déclaré dans la section <head/> d'une page Web :

<HEAD>
       <META http-equiv=Content-Type content="text/html; charset=unicode">
</HEAD>

Configuration du serveur

Afin d'appliquer les techniques exposées dans les sections suivantes de cet article, il est nécessaire que clients et serveurs soient configurés pour accepter les différentes cultures utilisées. Côté client, cela ne pose généralement pas de problème puisqu'un utilisateur souhaitant l'affichage d'une page en japonais disposera normalement d'un système d'exploitation et d'un navigateur supportant cette langue. Les postes de travail des développeurs nécessiteront au contraire probablement l'ajout des cultures à tester. Les serveurs, quant à eux, devront être équipés de toutes les polices de caractères correspondant aux langues qu'ils devront mettre à disposition des utilisateurs.

Détection de la culture de l'utilisateur

La plupart des navigateurs récents mentionne dans le paramètre "Accept-Language" du header de toute requête HTTP la liste des cultures admises par l'utilisateur. Ce paramétrage est généralement fait au moment de l'installation du logiciel, et est rarement modifié par la suite.

Afin de tester des sites multiculturels, on peut modifier ce paramétrage sous Internet Explorer dans Outils/Options Internet, puis langues :

ASP.NET fournit la liste des cultures acceptées par le navigateur sous la forme facilement exploitable d'un tableau string[] : Request.UserLanguages.

Pour adapter automatiquement l'affichage des dates et autres paramètres culturels, il suffit d'ajouter un événement au fichier global.asax.cs de votre application :

using System.Web;
using System.Globalization;
using System.Threading;

protected void Application_BeginRequest(Object sender, EventArgs e)
{
    System.Globalization.CultureInfo ci;
    if (HttpContext.Current.Request != null
     && HttpContext.Current.Request.UserLanguages != null
     && HttpContext.Current.Request.UserLanguages.Length > 0)
    {
        ci = CultureInfo.CreateSpecificCulture(
              HttpContext.Current.Request.UserLanguages[0]);
        Thread.CurrentThread.CurrentCulture = ci;
        Thread.CurrentThread.CurrentUICulture = ci;
    }
    else
    {
        ci = new CultureInfo("fr-FR");
        Thread.CurrentThread.CurrentCulture = ci;
        Thread.CurrentThread.CurrentUICulture = ci;
    }
}

L'événement Application_BeginRequest s'exécute avant le traitement de chaque requête, ce qui est nécessaire car chaque thread ASP.NET peut traiter des requêtes provenant de plusieurs utilisateurs.

Le gestionnaire d'événement commence par vérifier que le tableau des cultures existe et comporte au moins un élément. Il se sert ensuite de cet élément pour créer un objet CultureInfo. S'il n'est pas possible de détecter la culture du navigateur, on bascule sur une culture par défaut, ici "fr-FR".

C'est dans cet événement que l'on pourrait implémenter un traitement plus fin, soit en tenant compte de tous les éléments de Request.UserLanguages, soit en basculant sélectivement sur des groupes de cultures par défaut. On peut aussi laisser sur le site la possibilité à l'internaute de choisir une langue différente de celle que le site aura déterminé dynamiquement : il est alors simple de stocker cette langue dans une variable de session qui surchargera le paramétrage du navigateur.

Nous-nous contenterons dans cet article de ce mécanisme simple et laisserons au lecteur l'implémentation d'un mécanisme plus spécifique.

Les fichiers de ressources

Le .NET Framework implémente un mécanisme standard d'adaptation d'une application à la langue de l'utilisateur. Ce mécanisme utilise des fichiers de ressources au format XML et utilisant l'extension ".resx". Au moment de la compilation de l'application, les différentes traductions de ces documents sont incluses dans des assemblées périphériques. Pour installer une nouvelle langue sur un serveur, il suffit d'ajouter une nouvelle assemblée périphérique, sans avoir à recompiler l'assemblée principale. Les assemblées périphériques se trouvent dans un sous répertoire du répertoire /bin portant le nom de la culture utilisée.

Si vous développez sous Visual Studio.NET, ajoutez à votre projet un élément de type "fichier de ressources d'assemblée". Nommez-le par exemple "resources.resx". Visual Studio créera alors pour vous un squelette de fichier de ressources contenant le schéma utilisé. Ce fichier contiendra les chaînes de caractères utilisées par votre application, dans la langue par défaut du site. Créez ensuite autant de fichiers que vous désirez supporter de langues, en employant la convention de nommage "resources.[Code de culture].resx". Par exemple, si la culture par défaut de votre application est le français et si vous souhaitez supporter l'anglais et l'allemand, créez "resources.resx", puis "resources.en.resx" et "resources.de.resx".

Resources.resx :
<?xml version="1.0" encoding="utf-8" ?>
<root>
    ... Schéma ...
    <data name="Bonjour"><value>Bonjour</value></data>
    <data name="AuRevoir"><value>Au revoir</value></data>
</root>

Resources.en.resx :
<?xml version="1.0" encoding="utf-8" ?>
<root>
    ... Schéma ...
    <data name="Bonjour"><value>Hello</value></data>
    <data name="AuRevoir"><value>Goodbye</value></data>
</root>

Resources.de.resx :
<?xml version="1.0" encoding="utf-8" ?>
<root>
    ... Schéma ...
    <data name="Bonjour"><value>Guten tag</value></data>
    <data name="AuRevoir"><value>Auf wiedersehen</value></data>
</root>

Si vous ne disposez pas de Visual Studio.NET, vous pouvez tout de même inclure les ressources dans votre assemblée et créer les assemblées périphériques en suivant le processus suivant :

1.  Compilez les fichiers .resx au moyen de resgen.exe :
resgen Resources.resx Resources.resources
resgen Resources.en.resx Resources.en.resources
resgen Resources.de.resx Resources.de.resources

2.  Compilez l'assemblée principale en spécifiant l'option de compilation /res:Resources.resources

3.  Générez les assemblées périphériques en utilisant al.exe et copiez-les dans des sous-dossiers "de" et "en" du répertoire /bin de votre application :
al /t:lib /embed:Resources.en.resources /culture:en
    /template:MonAssembly.dll
    /out:MonAssembly.resources.dll
al /t:lib /embed:Resources.de.resources /culture:de
    /template:MonAssembly.dll
    /out:MonAssembly.resources.dll

Le ResourceManager

Pour utiliser ces chaînes de caractères, .NET fournit l'objet ResourceManager, qui présente une méthode GetString qui sélectionne parmi les ressources disponibles la version d'une chaîne de caractères qui correspond le mieux à la culture du thread en cours (que nous avons mise en conformité avec les choix de l'utilisateur dans Application_BeginRequest).

Afin de faciliter l'utilisation du ResourceManager et d'optimiser les accès, on pourra utiliser la classe statique suivante :

using System;
using System.Resources;

namespace Localisation
{
    public class EasyResourceManager
    {
        private static ResourceManager _RM = null;
        static EasyResourceManager() {}

        private static void LoadResources()
        {
            if (_RM == null)
            {
                try
                {
                    _RM = new ResourceManager("Resources",
                        typeof(EasyResourceManager).Assembly);
                }
                catch {}
            }
        }

        public static string getString(string name)
        {
            LoadResources();
            return _RM.GetString(name);
        }
    }
}

Cette classe stocke dans une variable statique l'objet ResourceManager la première fois que getString est appelée afin de minimiser et d'optimiser ses instantiations. Pour inclure dans une page une chaîne tirée du fichier de ressources, par exemple "Bonjour", il suffira d'y écrire :

<%=Localisation.EasyResourceManager.getString("Bonjour")%>

pour obtenir "Hello" sur un navigateur de langue anglaise, "Guten tag" sur un navigateur de langue allemande, et "Bonjour" dans tous les autres cas.

Localiser dans le corps de la page

La méthode de localisation que nous venons de décrire convient parfaitement à un développeur, mais est beaucoup trop complexe pour un utilisateur de profil moins technique comme par exemple un webmestre : on ne peut pas attendre de tous les intervenants sur un site qu'ils séparent la structure des pages HTML du contenu à localiser, et surtout qu'ils compilent les assemblées périphériques.

De plus, les exigences de mise à jour simple et rapide des sites modernes sont incompatibles avec une telle démarche, qu'on limitera à la localisation d'une application plus orientée "métier" que "contenu", et dans laquelle les ressources ne sont pas trop fréquemment modifiées.

Nous avons donc besoin d'une méthode de localisation plus simple à mettre en ouvre, de préférence basée sur une grammaire de marqueurs proches de l'HTML.

ASP.NET nous offre justement la possibilité d'étendre HTML avec de nouveaux marqueurs, qui ne sont en fait que la représentation de classes dérivant de System.Web.UI.Control, et qui génèrent de l'HTML standard compréhensible par tous les navigateurs.

Le type de syntaxe que nous désirons obtenir est le suivant :

<%@ Register
    TagPrefix="loc"
    Assembly="MonAssembly"
    NameSpace="Localisation" %>
...
<loc:multiculture runat=server>
    <version>
        <img src="icon.gif"> Prénom:
        <asp:Label runat=server Text="<%
#FirstName%>"/>
    </version>
    <version culture="en">
        <img src="icon.en.gif"> First name:
        <asp:Label runat=server Text="<%#FirstName%>" BackColor=AliceBlue/>
    </version>
    <version culture="de">
        <img src="icon.de.gif"> Vorname:
        <asp:Label runat=server Text="<%#FirstName%>" BackColor=Beige/>
    </version>
</loc:multiculture>

Notre contrôle doit donc pouvoir comporter un nombre quelconque de sous-marqueurs "version", qui eux-mêmes doivent pouvoir accepter n'importe quel type de contenu HTML, des contrôles serveur, et du "data-binding".

Le Framework .NET nous apporte la possibilité de modifier l'interprétation habituelle du code inclus dans un contrôle, ce qui va nous permettre de définir l'interprétation de "version".

L'attribut ControlBuilderAttribute permet de spécifier une classe dérivant de ControlBuilder, LocalizableControlBuilder, qui va nous permettre d'établir la correspondance entre les marqueurs détectés et des classes .NET. En l'occurrence, "version" va être mis en correspondance avec le type d'un autre contrôle, "Version". Dans tous les autres cas, on appelle la méthode de la classe de base.

ASP.NET va donc appeler notre classe au moment d'interpréter le code situé sous un contrôle MultiCulture. La classe renverra le type Version chaque fois qu'un marqueur "version" sera rencontré.

La deuxième partie du mécanisme est la surcharge de la méthode AddParsedSubObject. Cette méthode teste le type de chaque sous contrôle à ajouter, et ne conserve que ceux qui sont de type Version. L'interprétation de l'attribut "culture" comme devant remplir la propriété publique Culture du contrôle Version est automatique.

Toutes ces facilités font que dans le cas de notre exemple, nous avons maintenant dans la collection Controls de notre contrôle trois objets Version, qui eux-mêmes ont un contenu quelconque sans même que nous ayons eu à nous en préoccuper : la classe de base Control a fait tout le travail d'intégration pour nous.

Il nous suffit ensuite de surcharger la méthode Render pour n'afficher que le contenu du marqueur "version" le plus approprié, en commençant par chercher une version en correspondance exacte avec la culture courante du thread, puis en acceptant une correspondance seulement au niveau du code de langue, et enfin en basculant vers la culture par défaut (pour laquelle on n'a pas spécifié d'attribut Culture, ou alors Culture="default").

using System;
using System.Collections;
using System.Globalization;
using System.Threading;
using System.Web;
using System.Web.UI;

namespace Localisation
{
    [ControlBuilderAttribute(
        typeof(MultiCulture.LocalizableControlBuilder))]
    public class MultiCulture : Control
    {
        public class LocalizableControlBuilder : ControlBuilder
        {
            public override Type GetChildControlType(
                string tagName,
                IDictionary attributes)
            {
                if (System.String.Compare(tagName, "version", true) == 0)
                {
                    return typeof (MultiCulture.Version);
                }
                return base.GetChildControlType(tagName, attributes);
            }
        }

        public class Version : Control
        {
            private String _culture;

            public string Culture
            {
                get {return _culture;}
                set {_culture = value;}
            }
        }

        protected override void AddParsedSubObject(Object obj)
        {
            if (obj is Version)
            {
                Controls.Add((Control)obj);
            }
        }

        protected override void Render(HtmlTextWriter output)
        {
            CultureInfo ci = Thread.CurrentThread.CurrentCulture;
            foreach(Version ctrl in Controls)
            {
                if (ctrl.Culture == ci.ToString())
                {
                    ctrl.RenderControl(output);
                    return;
                }
            }
            foreach(Version ctrl in Controls)
            {
                if (ctrl.Culture == ci.TwoLetterISOLanguageName)
                {
                    ctrl.RenderControl(output);
                    return;
                }
            }
            foreach (Version ctrl in Controls)
            {
                if (ctrl.Culture == null
                || System.String.Compare(ctrl.Culture, "default", true) == 0)
                {
                    ctrl.RenderControl(output);
                    return;
                }
            }
        }
    }
}

Ce contrôle très simple permet de mettre en place des pages multiculturelles lisibles et faciles à maintenir. Il peut être mis en ouvre par un intégrateur HTML sans compétence particulière en programmation.

Il permet également de mettre en place dans une même page des organisations radicalement différentes des mêmes éléments, par exemple en mettant dans une version japonaise les labels à droite des champs d'édition.

Mais il y a tout de même un cas où ce contrôle est inefficace : si on désire localiser un attribut d'un contrôle serveur. Par exemple, l'infobulle de l'image suivante ne peut être localisée avec notre contrôle, à moins de démultiplier l'image (ce que nous avons fait pour le contrôle Label de l'exemple précédent) :

<img runat=server src="images/photo.jpg" alt="Légende"/>

Nous avons besoin pour régler ce problème d'une simple méthode statique permettant de choisir une chaîne parmi celles fournies. Ajoutons donc une telle méthode à notre contrôle :

public static string String(string[] Cultures, string[] StringVersions)
{
    if (Cultures.Length+1!=StringVersions.Length)
        throw new Exception("Le nombre de cultures spécifié doit être le
                                nombre de chaînes, moins un");

    CultureInfo ci = Thread.CurrentThread.CurrentCulture;
    for(int i = 0; i < Cultures.GetLength(0); i++)
    {
        if (Cultures[i] == ci.ToString())
            return StringVersions[i+1];
    }
    for(int i = 0; i < Cultures.GetLength(0); i++)
    {
        if (Cultures[i] == ci.TwoLetterISOLanguageName)
            return StringVersions[i+1];
    }
    return StringVersions[0];
}

Il nous suffit alors, pour localiser notre image, d'écrire :

<img runat=server src="images/photo.jpg" alt='<%#
    Localisation.MultiCulture.String(
        new string[] {"en", "de"},
        new string[] {"Légende", "Caption", "Untertitel"})%>'/>

pour qu'elle adapte sa légende à la culture de l'internaute.

Bien sûr, la syntaxe est ici un peu moins claire que dans le cas où on peut utiliser le contrôle lui-même.

Le contrôle présenté dans cet article peut être amélioré de bien des manières. Il en existe d'ailleurs une version plus élaborée, dotée d'un Designer qui rend beaucoup plus simple son utilisation dans des environnements de développement visuel tels que Visual Studio.NET ou WebMatrix. La version complète présente également une documentation localisée, ce qui est la moindre des choses pour un tel composant.

Adaptation de la mise en page

Les développeurs qui ont déjà eu à localiser une application Windows se demandent certainement à ce point de l'exposé comment .NET résout le problème de l'adaptation de la mise en page à la culture. En effet, certaines langues sont plus concises que d'autres, et même entre des langues qui partagent à peu près le même alphabet, des problèmes de taille de composants peuvent survenir. Par exemple, un bouton dont le texte en anglais serait "bye" serait probablement dimensionné trop justement pour accueillir la traduction allemande, "auf wiedersehen". En programmation Windows Forms, ce problème existe effectivement, et est résolu par une version limitée de Visual Studio, distribuable gratuitement, et qui permet de traduire les formulaires directement dans le designer visuel, en adaptant éventuellement la taille des éléments. Les fichiers de ressources localisées contiennent non seulement la traduction des chaînes de caractères, mais aussi la mise en page adaptée.

En développement WebForms, en réalité, le problème n'existe pas. En effet, en HTML, une chaîne de caractères ne sera jamais tronquée par un conteneur trop petit : tous les éléments HTML s'adaptent automatiquement à leur contenu. C'est d'ailleurs une des difficultés du montage HTML : il ne faut jamais tenir pour acquise la taille d'un texte (l'utilisateur peut très bien être mal-voyant et avoir réglé la taille des caractères au maximum), et il est impératif que la mise en page puisse résister à tout changement de dimensions sans trop de dégâts.

Dans le cas de la localisation, il est donc plus que jamais important de concevoir des structures de pages souples.

Localisation d'une base de données

Si l'application Web tire son contenu d'une base de données, la localisation ne peut se faire qu'au prix de celle de la base, qui peut se révéler assez complexe.

L'approche qui consiste à multiplier les champs textuels en base est à éliminer d'emblée : l'ajout d'une nouvelle langue est alors trop complexe car il implique une intervention sur une multitude de champs, et de nombreux problèmes de maintenance ne manqueront pas d'émerger à plus ou moins court terme.

Nous proposons ici une structure de base proche de ce que proposent les fichiers de ressource, en présentant de plus l'avantage de fournir un stockage homogène de l'information.

Toutes les chaînes de caractères localisables seront stockées dans une ou plusieurs tables spécialisées, dont la structure peut être déterminée sur le modèle suivant :

Dans les autres tables, chaque colonne représentant un texte localisable sera du même type que ID (ici, char(20)). Au moment d'afficher une valeur, on mettra en relation l'identifiant contenu dans la table avec d'une part l'identifiant des chaînes de ressource, et d'autre part avec la culture en cours.

Dans une base de données telle que celle-ci, l'ajout d'une nouvelle langue ne nécessite aucun changement de structure.

Pour finir, signalons qu'il n'est nul besoin ici de se préoccuper de jeux de caractères lorsque la base de données est SQL Server 2000, à condition de n'utiliser que des types Unicode (nchar, nvarchar et ntext) pour les colonnes localisables. Dans ce cas, en effet, les données restent en Unicode au moins jusqu'au moment où elles seront envoyées au navigateur : SQL Server stocke et transmet ses données en Unicode, et ADO.NET, comme tout le Framework .NET, utilise Unicode comme format interne de stockage du type string.

Notons que SQL Server 2000 permet une gestion très fine des jeux de caractères grâce au mot-clé COLLATE, mais cela ne concerne que les applications ne gérant pas Unicode ou utilisant des colonnes ASCII.

Puisqu'il est si simple en .NET d'utiliser Unicode, et que les éventuels transcodages sont transparents et se font au dernier moment, il est préférable de ne pas s'encombrer de ces complications.

Conclusions

La localisation d'une application est un sujet délicat, qui doit être envisagé très en amont d'un projet, afin de mettre en place une architecture robuste et pérenne. Les standards internationaux, exploités au sein d'une infrastructure moderne telle que .NET, permettent la mise en place de sites et d'applications répondant aux exigences légitimes d'utilisateurs ne résidant "pas tous" aux Etats-Unis.

Il reste malgré tout à faire entrer dans les moeurs que cette étape est tout aussi structurante pour un site Web que la sécurité.

Auteur : Bertrand Le Roy de la société Magnitude (www.magnit.com

A propos de Magnitude : 
"Totalement dédiée aux technologies Internet depuis sa création en 1995, MAGNITUDE a su réunir autour d'un noyau d'ingénieurs et d'universitaires de haut niveau, une équipe pluridisciplinaire de consultants, journalistes et Web designers, spécialisés dans la conception, la réalisation et l'hébergement de sites Web et Intranet à forte valeur ajoutée technique."

DotNetGuru - Décembre 2002