IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Gestion de messages en plusieurs langues


Sujet :

C#

  1. #1
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut Gestion de messages en plusieurs langues
    Bonjour !

    Moi petit belge et moi ya avoir souvent probleme de traduction pour etre compris dans les multiples communautés dont les langues se partagent le conffeti du territoire !

    Néanmoins la gestion d'une application multi-lingue est une excellente expérience !

    Les resx apportent deja une solution a la traduction de tous les texte des controls

    MAIS !
    Souvent il faut gerer des textes ou messages indépendant d'une form
    Existe-il une solution magique +/- pour cela ?

    Ou bien faut-il tout faire a la main ?
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Points : 253
    Points
    253
    Par défaut
    Citation Envoyé par olibara Voir le message
    [...]
    MAIS !
    Souvent il faut gerer des textes ou messages indépendant d'une form
    Existe-il une solution magique +/- pour cela ?

    Ou bien faut-il tout faire a la main ?
    Vous voulez dire dans le cas le plus général ?

    Si oui, ma foi, je dirais qu'il faut continuer, autant que possible, de s'appuyer sur le support des ressources offert par le framework (fichiers .resx, ResourceManager, et consoeurs) en vous créant des classes "helpers" mettant en oeuvre ce support.

    Pour ce qui est de l'implémentation de ce genre de couche technique, vous avez, encore une fois avec .NET, une foule de possibilités :

    a) un mécanisme "statique" qui implémente des design patterns bien connus comme le visiteur, adapté à votre modèle objet (l'ensemble de vos classes "maison" ) ;

    b) un mécanisme plus "dynamique" à base de custom attributes par exemple ;

    c) un mécanisme encore plus dynamique s'appuyant sur System.Reflection uniquement pour inspecter / découvrir / sélectionner les propriétés à localiser ;

    d) un mix de (a) et (b), ou (a) et (c), ou (b) et (c) ;

    e) des techniques dynamiques encore moins intrusives dans le code source comme des toolkits orientés aspects... (injection MSIL à l'exécution)

    f) autres ?

    Mais le choix d'un mécanisme particulier dépend sutout de la portée / de l'étendue de l'opération à travers votre modèle objet ; je dirais, grossierement, plus la portée de l'opération est grande, plus vous chercherez un mécanisme "générique", le moins intrusif possible sur le code source / sur votre système de classes / types statiques (connus à la compilation) => ce qui signifie que des techniques qui interviennent moins à la compilation qu'à l'exécution (p.ex, c, d, e) auront votre préférence.

    'HTH

  3. #3
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci

    Mais mon besoin n'est pas de débattre des differentes techniques possibles !
    (Avec VS 6.0 je faisais des fichier type .ini contenant toutes les traduction nécéssaire Y COMPRIS les texte des controls) l'app se constituait dynamiquement un dico des langues disponibles, il n'etait meme pas nécessaire de recompiler pour ajouter une langue)
    La partie fastidieuse etait de maintenir pendant le developpement la table de reference des des differentes textes.

    Avec VS .NET j'aimerais connaitre ta technique la plus "courante" avant d'en inventer une nouvelle, sachant que les resx font deja une partie du boulot pour les forms.
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  4. #4
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 387
    Points : 2 999
    Points
    2 999
    Par défaut
    les fichiers resx ne peuvant pas contenir des chaînes définies utilisables directement comme des ressources ? il me semble que si pourtant

    http://msdn.microsoft.com/fr-fr/library/y99d1cd3.aspx

  5. #5
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Points : 253
    Points
    253
    Par défaut
    Citation Envoyé par olibara Voir le message
    Mais mon besoin n'est pas de débattre des differentes techniques possibles !
    J'avais bien compris. C'est pourquoi je n'ai fait que lister les principales stratégies, qui toutes ont leur intérêt dans un contexte donné, pour éviter justement de lancer le genre de débat infertile : "la meilleure technique, c'est... etc, etc"

    Avec VS .NET j'aimerais connaitre ta technique la plus "courante" avant d'en inventer une nouvelle, sachant que les resx font deja une partie du boulot pour les forms.
    "La plus courante" ? Je dirais qu'il n'y en a pas réellement... (à moins d'être omniscient et d'avoir à disposition le code source de tous ceux qui ont résolu le problème, pour faire des statistiques sur leurs techniques... )

    Cela dit, je peux vous donner des exemples courts en C# pour au moins a) b) c) assez rapidement, ne serait ce que pour illustrer le propos... vous vous ferez votre avis, je suppose.

    Je vous communique ça bientôt, dans un ordre de grandeur de quelques dizaines de lignes pour chacune. Toutes iront chercher les chaines dans une ressource .resx de l'application, en utilisant ResourceManager, mais elles resteront largement valables dans leur principe pour d'autres sources de localisation, comme vos "anciens" fichiers .ini, ou une BDD, etc.

    A bientôt.

  6. #6
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci Lysiandad, j'apprécie beaucoup ta proposition

    Quand je parlais de methode "courrante" c'est que sachant que le mecanisme de traductions des form est prévu de maniere standard via les resx, j'avais pensé qu'un mecanisme similaire etait prevu pour la gestion des ressource sémantiques "communes" a l'app et non spécifique a chaque form
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  7. #7
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Merci Papy214

    Il semble que tu a mis le doigt sur une bonne piste : un resx commun !
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  8. #8
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut Attention PIEGE !
    Il serait tentant d'utiliser le resx d'une form pour y strocker certaines message non relatif a un control mais pouvant etre traduit !

    Ce n'est pas une bonne idée : a chaque modification de la form, ces message seront suprimés

    Solution :
    A) dissimuler ces messages dans un controle caché un textlistbox par exemple mais ca sent le brico !
    B) Suivre la solutio de papy et placer tout ces messahe dans le ressource global mais le défaut c'est que si on a beaucoup de forms et plusieurs messages il peut etre fastidieux de les identifier dans le ressource global
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  9. #9
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 387
    Points : 2 999
    Points
    2 999

  10. #10
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Bonjour Papy214

    Je ne comprends pas le lien que tu viens d'envoyer ?
    Qu'apporte-t-il par rapport a ce qui a déja été dit ?

    La solution du ressources.(LG).resx global de de l'app est la plus facile a mettre en oeuvre, mais la plus fastidieuse a maintenir

    - Pas de synchro aisée entre les langues
    - Pas de hierarchisation des élements
    - Edition malaisée
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  11. #11
    Membre émérite

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 387
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 387
    Points : 2 999
    Points
    2 999
    Par défaut
    ce n'est qu'un autre système de localisation,une solution alternative découplée du système standard de C#. On peut l'utiliser avec quelques dll. LE système est basé sur l'utilisation de chaînes de caractères en anglais. En changeant la culture, on récupère les chaînes traduites automatiquement. Voilà un exemple de code:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
            [DllImport("D:\\Applications\\Programmation\\GnuWin32\\bin\\libintl3.dll")]
            static extern String gettext(String A);
     
            [DllImport("D:\\Applications\\Programmation\\GnuWin32\\bin\\libintl3.dll")]
            static extern String bindtextdomain(String A, String B);
     
            [DllImport("D:\\Applications\\Programmation\\GnuWin32\\bin\\libintl3.dll")]
            static extern String textdomain(String A);
     
            public Form1()
            {
                InitializeComponent();
                comboBox1.SelectedIndex = 3;
            }
     
            private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
            {
                bindtextdomain("default", System.IO.Path.Combine(Application.StartupPath, "locale"));
                textdomain("default");
                System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(comboBox1.Items[comboBox1.SelectedIndex].ToString());
                Text = String.Format("{0} : {1}", gettext("Hello world"), gettext("Good bye"));
            }



  12. #12
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2008
    Messages : 217
    Points : 253
    Points
    253
    Par défaut
    Citation Envoyé par olibara Voir le message
    Merci Lysiandad, j'apprécie beaucoup ta proposition
    [...]
    Voici donc les quelques techniques que j'évoquais, à travers quatre stratégies démontrées en un seul programme, dont une non contextuelle (typiquement pour des messages d'info dans des message box ou message d'erreur), et les trois autres context-bound (pour localiser des props de type string d'un modèle objet).

    Notes en vrac (je m'efforcerai de répondre aux questions/critiques/remarques/suggestions d'amelioration) :

    * ce code est surtout là pour illustrer les principes ; le style / les noms des interfaces et classes ne sont peut etre pas extraordinairement bien choisis...

    * pour faire court, j'ai réutilisé les classes Vehicle/Car "sujets" pour les 3 strategies context-bound

    * il n'y a pas de gestion d'erreur digne de ce nom ; il convient donc de "blinder" le code un peu plus a certains endroits (preconditions, tests contre null, etc)

    * BaseLocalizer pourrait bien sûr aller chercher la chaine translatée depuis le jeton (token) depuis d'autres sources (BDD, fichiers XML proprietaires non-resx, fichiers .ini, etc) ; pour faire court (bis repetita), j'ai simplement introduit un ResourceBasedLocalizer concret sur lequel s'appuient les localizers mis en oeuvre par les 4 strategies

    * notez l'attribut LocalizedAttribute, utilisée par la strategie ByAttribute

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
     
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Reflection;
    using System.Resources;
    using System.Text;
    using System.Threading;
     
    /*
     * Avec ces deux resx (Strings.en.resx et Strings.resx) :
     * 
      <data name="Blue" xml:space="preserve">
        <value>blue</value>
      </data>
      <data name="Red" xml:space="preserve">
        <value>red</value>
      </data>
      <data name="Sedan" xml:space="preserve">
        <value>sedan</value>
      </data>
      <data name="SportsCar" xml:space="preserve">
        <value>sports car</value>
      </data>
      <data name="This_is_a" xml:space="preserve">
        <value>This is a</value>
      </data>
      <data name="UtilityCar" xml:space="preserve">
        <value>utility car</value>
      </data>
     *
      <data name="Blue" xml:space="preserve">
        <value>bleue</value>
      </data>
      <data name="Red" xml:space="preserve">
        <value>rouge</value>
      </data>
      <data name="Sedan" xml:space="preserve">
        <value>berline</value>
      </data>
      <data name="SportsCar" xml:space="preserve">
        <value>sportive</value>
      </data>
      <data name="This_is_a" xml:space="preserve">
        <value>Ceci est une</value>
      </data>
      <data name="UtilityCar" xml:space="preserve">
        <value>voiture utilitaire</value>
      </data>
     * 
     * ... ce programme affiche sur la sortie de la console :
     * 
    This_is_a UtilityCar Blue.
    Ceci est une voiture utilitaire bleue.
    Ceci est une voiture utilitaire bleue.
    Ceci est une voiture utilitaire bleue.
     
    This_is_a Blue UtilityCar.
    This is a blue utility car.
    This is a blue utility car.
    This is a blue utility car.
     
    This_is_a Red SportsCar.
    This is a red sports car.
    This is a red sports car.
    This is a red sports car.
     * 
     */
     
    namespace CSharp.LocalizeStrategies
    {
        public abstract class LocalizeStrategy
        {
            private static Dictionary<Type, LocalizeStrategy> _strategies = new Dictionary<Type, LocalizeStrategy>();
            public static LocalizeStrategy GetInstance<S>() where S : LocalizeStrategy
            {
                if (!_strategies.ContainsKey(typeof(S)))
                    _strategies.Add(typeof(S), Activator.CreateInstance<S>());
                return _strategies[typeof(S)];
            }
            public abstract ILocalizer GetLocalizer(params object[] args);
        }
     
        public interface ILocalizer
        {
            LocalizeStrategy Strategy { get; }
            string Localize(string token);
            string Localize(ILocalizable subject, string token);
        }
     
        public abstract class BaseLocalizer : ILocalizer
        {
            public abstract LocalizeStrategy Strategy { get; }
            public abstract string Localize(string token);
            public abstract string Localize(ILocalizable subject, string token);
        }
     
        public class NullLocalizer : BaseLocalizer
        {
            private LocalizeStrategy _strategy = null;
            public NullLocalizer(LocalizeStrategy strategy)
            {
                _strategy = strategy;
            }
            public override LocalizeStrategy Strategy { get { return _strategy; } }
            public override string Localize(string token)
            {
                return token;
            }
            public override string Localize(ILocalizable subject, string token)
            {
                return token;
            }
        }
     
        public class ResourceBasedLocalizer : NullLocalizer
        {
            private static ResourceManager _resMan = new ResourceManager(typeof(Strings));
            public ResourceBasedLocalizer(LocalizeStrategy strategy)
                : base(strategy)
            {
            }
            public override string Localize(string token)
            {
                return _resMan.GetString(token, Thread.CurrentThread.CurrentCulture);
            }
        }
     
        public class VehicleLocalizer : ResourceBasedLocalizer
        {
            public VehicleLocalizer(LocalizeStrategy strategy) : base(strategy)
            {
            }
            public override string Localize(ILocalizable subject, string token)
            {
                return base.Localize(token);
            }
        }
     
        [AttributeUsage(AttributeTargets.Property, Inherited = true)]
        public class LocalizedAttribute : Attribute
        {
            private string _token = null;
            public LocalizedAttribute() : this(String.Empty)
            {
            }
            public LocalizedAttribute(string token)
            {
                _token = token;
            }
            public string Token { get { return _token; } }
        }
     
        public class AttributeBasedLocalizer : ResourceBasedLocalizer
        {
            public AttributeBasedLocalizer(LocalizeStrategy strategy)
                : base(strategy)
            {
            }
            public override string Localize(ILocalizable subject, string token)
            {
                string actualToken = token;
                PropertyInfo[] props = subject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty);
                foreach (PropertyInfo prop in props)
                {
                    LocalizedAttribute attr = Attribute.GetCustomAttribute(prop, typeof(LocalizedAttribute), true) as LocalizedAttribute;
                    if (attr.Token == token)
                    {
                        actualToken = prop.GetValue(subject, null) as string;
                        break;
                    }
                }
                return base.Localize(actualToken);
            }
        }
     
        public class ReflectionBasedLocalizer : ResourceBasedLocalizer
        {
            public ReflectionBasedLocalizer(LocalizeStrategy strategy)
                : base(strategy)
            {
            }
            public override string Localize(ILocalizable subject, string token)
            {
                string actualToken = token;
                PropertyInfo prop = subject.GetType().GetProperty(token);
                if (prop != null)
                    actualToken = prop.GetValue(subject, null) as string;
                return base.Localize(actualToken);
            }
        }
     
        public interface ILocalizable
        {
        }
     
        public abstract class Vehicle : ILocalizable
        {
            [Localized("Vehicle.Kind")]
            public abstract string Kind { get; }
        }
     
        public class Car : Vehicle
        {
            private string _kind = String.Empty;
            private string _colour = String.Empty;
            public Car(string kind)
            {
                _kind = kind;
            }
            public override string Kind { get { return _kind; } }
            [Localized("Car.Colour")]
            public virtual string Colour { get { return _colour; } set { _colour = value; } }
        }
     
        public sealed class ContextFree : LocalizeStrategy
        {
            public static readonly ILocalizer NullLocalizer = new NullLocalizer(null);
            public static readonly ILocalizer ResourceBasedLocalizer = new ResourceBasedLocalizer(null);
            public override ILocalizer GetLocalizer(params object[] args)
            {
                if (args.Length < 1)
                    return NullLocalizer;
                string key = args[0] as string;
                switch (key)
                {
                    case "resx":
                        return ResourceBasedLocalizer;
                    default:
                        return NullLocalizer;
                }
            }
        }
     
        public sealed class ByType : LocalizeStrategy
        {
            private Dictionary<Type, ILocalizer> _localizers = new Dictionary<Type, ILocalizer>();
            public ByType()
            {
                _localizers.Add(typeof(Vehicle), new VehicleLocalizer(this));
            }
            public override ILocalizer GetLocalizer(params object[] args)
            {
                ILocalizer localizer = null;
                foreach(Type type in _localizers.Keys)
                    if (type.IsInstanceOfType(args[0]))
                    {
                        localizer = _localizers[type];
                        break;
                    }
                return localizer;
            }
        }
     
        public sealed class ByAttribute : LocalizeStrategy
        {
            private static AttributeBasedLocalizer _localizer = null;
            public override ILocalizer GetLocalizer(params object[] args)
            {
                if (_localizer == null)
                    _localizer = new AttributeBasedLocalizer(this);
                return _localizer;
            }
        }
     
        public sealed class ByReflection : LocalizeStrategy
        {
            private static ReflectionBasedLocalizer _localizer = null;
            public override ILocalizer GetLocalizer(params object[] args)
            {
                if (_localizer == null)
                    _localizer = new ReflectionBasedLocalizer(this);
                return _localizer;
            }
        }
     
        class Program
        {
            private static string Localized(string token, bool doLocalize)
            {
                ILocalizer localizer = LocalizeStrategy.GetInstance<ContextFree>().GetLocalizer(doLocalize ? "resx" : "null");
                return localizer.Localize(token);
            }
     
            private static string Localized(string token)
            {
                return Localized(token, true);
            }
     
            private static string NonLocalized(string token)
            {
                return Localized(token, false);
            }
     
            private static string Localized<S>(ILocalizable context, string token) where S : LocalizeStrategy
            {
                ILocalizer localizer = LocalizeStrategy.GetInstance<S>().GetLocalizer(context);
                return localizer.Localize(context, token);
            }
     
            private static string Adjectivate(string adjective, string noun, bool prepend)
            {
                if (prepend)
                    return String.Concat(adjective, " ", noun);
                else
                    return String.Concat(noun, " ", adjective);
            }
     
            private static void ApplyStrategiesOnCar(Car car)
            {
                bool englishMode = (String.Compare(Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName, "en", true) == 0);
                Console.WriteLine("{0} {1}.", NonLocalized("This_is_a"), Adjectivate(NonLocalized(car.Colour), NonLocalized(car.Kind), englishMode));
                Console.WriteLine("{0} {1}.", Localized("This_is_a"), Adjectivate(Localized<ByType>(car, car.Colour), Localized<ByType>(car, car.Kind), englishMode));
                Console.WriteLine("{0} {1}.", Localized("This_is_a"), Adjectivate(Localized<ByAttribute>(car, "Car.Colour"), Localized<ByAttribute>(car, "Vehicle.Kind"), englishMode));
                Console.WriteLine("{0} {1}.", Localized("This_is_a"), Adjectivate(Localized<ByReflection>(car, "Colour"), Localized<ByReflection>(car, "Kind"), englishMode));
            }
     
            static void Main(string[] args)
            {
                Car car = new Car("UtilityCar");
                car.Colour = "Blue";
                ApplyStrategiesOnCar(car);
                Console.WriteLine();
                Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
                ApplyStrategiesOnCar(car);
                Console.WriteLine();
                car = new Car("SportsCar");
                car.Colour = "Red";
                ApplyStrategiesOnCar(car);
                Console.ReadLine();
            }
        }
    }
    'HTH

  13. #13
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Sur 4 softs différents, j'ai vu 4 fois la seule et même technique efficace :

    Un dictionnaire général application --> langue par défaut
    un dictionnaire par user --> langue du user.

    C'est avant tout un problème de conception applicative, pas du tout technique.

    La plupart du temps, il faut partir du princie que quelqu'un va devoir se faire les traductions (c'est génial d'avoir le framework, mais c'est encore mieux d'avoir les traductions)
    Les paramétres locaux de l'OS ne sont pas nécessairemet représentatif de la langue du user (eg. : Anglais US pour un utilisateur parlant Allemand, déjà et souvent vu)
    Les paramétres locaux de l'app server sont rarement ceux du user.

    Solution : persister des dictionnaires.

  14. #14
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Salut BAF

    Oui c'est ce que je pense aussi

    Et les Ressources.resx permettent en partie de gerer cela
    Sauf qu'ils sont un peu fastidieux a maintenir !
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

Discussions similaires

  1. [Débutant] Gestion de plusieurs langues en C++/CLI
    Par robiwoan dans le forum Windows Forms
    Réponses: 1
    Dernier message: 26/03/2013, 11h12
  2. [AC-2003] Gestion de plusieurs langues
    Par basoil dans le forum IHM
    Réponses: 15
    Dernier message: 19/05/2009, 17h53
  3. Gestion de plusieurs langues
    Par emardjean dans le forum Langage
    Réponses: 2
    Dernier message: 09/04/2006, 18h50
  4. Gestion des message windows dans les threads
    Par billyboy dans le forum Windows
    Réponses: 5
    Dernier message: 06/10/2003, 17h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo