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++Builder Discussion :

[TUTO]Application multilingue "dynamique" et "automatique"


Sujet :

C++Builder

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2004
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2004
    Messages : 83
    Points : 55
    Points
    55
    Par défaut [TUTO]Application multilingue "dynamique" et "automatique"
    Comment créer une application multilingue

    D'après le sondage, j'ai vu que la plupart voulait un tuto sur ça. Programmeur depuis des nombreuses années,
    je voudrais partager mes connaissances sur ma façon de traduire mes applications.

    1°) Ce qu'il nous faut

    - Borland C++ builder 2005/2006 ou autre.

    2°) Construction des fichiers de langues

    La première étape consiste à créer notre propre fonction qui permettra de traduire l'application. La méthode consiste
    à chercher parmis tous les composants de la "form", les composants qui sont inscrit dans notre fichier de langue.


    Crééons une simple application où on va placer 2 boutons, 2 labels...

    Nous allons maintenant créer un fichier de langue par exemple : fr.lng

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    [Form1_Form]
    Form1=titre en français
     
     
    [Form1_Label]
    Label1=Label en français
    Label2=Label2 en français
     
    [Form1_Button]
    Button1=Français
    Button2=Anglais
    On va sauvegarder ce fichier dans le même répertoire que notre application.

    Ensuite on va créer un deuxième fichier qu'on va nommer : en.lng

    voici son contenu (identique au fr mais traduit)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    [Form1_Form]
    Form1=title in english
     
     
    [Form1_Label]
    Label1=Label in english
    Label2=Label2 in english
     
    [Form1_Button]
    Button1=French
    Button2=English

    Dans ce code, retenons 4 choses :

    [Form1_Form] : Form1 sera le nom de la Form de mon application que je veux traduire
    [Form1_Form] : FOrm est le nom général que je donne pour traduire le titre Form1->Caption
    [Form1_Label] : Label, Button ou d'autres seront des mots pour détecter si les composants sont des TLabels, TButtons etc..
    Label1, Label2, Button1 ,... sont les noms de mes composants de la Form "Form1"


    3°) COnstruction de l'application

    Nous allons maintenant créer une fonction ChargerLangue où on lui passera plusieurs paramètres : le nom de la Form, le nom de fichier de langue


    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
     
     
    void __fastcall TForm::ChargerLangue(TForm *f, AnsiString filename)
    {
      if (FileExists(filename)) // vérifier si le fichier de langue existe
      {
          TIniFile *Ini=new TIniFile (filename);; // 'jouvre le fichier comme si c'était un fichier .ini
            for (int i = 0; i < f->ComponentCount; i++) // je parcours tous les composants de la Form
            {
     
                    if (f->Components[i]->Name!="") // tant que je suis sur un composant
                    {
     
                      if (Ini->ReadString (f->Name+"_Label",AnsiString(f->Components[i]->Name),"***")!="***")
                      {
     
                        ((TLabel *)f->Components[i])->Caption = Ini->ReadString (f->Name+"_Label",AnsiString(f->Components[i]->Name),((TLabel *)f->Components[i])->Caption);
                      }
                      else
                      if (Ini->ReadString (f->Name+"_Button",AnsiString(f->Components[i]->Name),"***")!="***")
                      {
     
                          ((TButton *)f->Components[i])->Caption = Ini->ReadString (f->Name+"_Button",AnsiString(f->Components[i]->Name),((TButton *)f->Components[i])->Caption );
     
                      }
     
                    }
     
            }
     
            if (Ini->ReadString (f->Name+"_Form",AnsiString(f->Name),"***")!="***")
            {
     
              f->Caption = Ini->ReadString (f->Name+"_Form",AnsiString(f->Name),f->Caption);
            }
     
     
     
     
        delete Ini;
      }
     
    }
    N'oublions pas de placer dans le .cpp la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #include "IniFiles.hpp"
    et dans le .h la déclaration de notre fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     void __fastcall ChargerLangue(TForm *f, AnsiString filename);

    maintenant allez dans l'evénement OnClick du Button1
    Ensuite on appelle la fonction ChargerLangue

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"fr.lng");
    Même chose pour Onclick du Button2 mais cette fois-ci pour en.lng
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"en.lng");

    Maintenant on va choisir la langue par défaut de l'application : (ou par vous donner un exemple, ça peut être intéressant pour choisir
    la langue choisie lors de la dernière utilisation)
    Pour cela, on clique sur l'evénement OnCreate de la Form1. Et on écrit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"fr.lng");


    Compilez et exécutez !

    4°) Avantages et inconvénients

    Les avantages sont nombreux :
    - Pas besoin de redémarrer l'application pour la traduire .. traduction rapide et instantanée
    - Modification du fichier langue sans avoir à modifier le code source. (il suffit de mettre tous les composants à scanner dans le code chargerlangue)
    - Possibilité de créer un menu en crééant des sous-menus de façon dynamique (il suffit de parcourir le répertoire et détecter les langues)
    - etc...

    Inconvénients :
    - et bien, je n'en ai pas encore vu.


    5°) code source


    unit1.cpp
    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
     
    //---------------------------------------------------------------------------
     
    #include <vcl.h>
    #pragma hdrstop
     
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    #include "IniFiles.hpp"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
      : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
     
     
    void __fastcall TForm1::ChargerLangue(TForm *f, AnsiString filename)
    {
      if (FileExists(filename)) // vérifier si le fichier de langue existe
      {
     
        TIniFile *Ini=new TIniFile (filename);; // 'jouvre le fichier comme si c'était un fichier .ini
            for (int i = 0; i < f->ComponentCount; i++) // je parcours tous les composants de la Form
            {
     
                    if (f->Components[i]->Name!="") // tant que je suis sur un composant
                    {
     
                      if (Ini->ReadString (f->Name+"_Label",AnsiString(f->Components[i]->Name),"***")!="***")
                      {
     
                        ((TLabel *)f->Components[i])->Caption = Ini->ReadString (f->Name+"_Label",AnsiString(f->Components[i]->Name),((TLabel *)f->Components[i])->Caption);
                      }
                      else
                      if (Ini->ReadString (f->Name+"_Button",AnsiString(f->Components[i]->Name),"***")!="***")
                      {
     
                          ((TButton *)f->Components[i])->Caption = Ini->ReadString (f->Name+"_Button",AnsiString(f->Components[i]->Name),((TButton *)f->Components[i])->Caption );
     
                      }
     
                    }
     
            }
     
            if (Ini->ReadString (f->Name+"_Form",AnsiString(f->Name),"***")!="***")
            {
     
              f->Caption = Ini->ReadString (f->Name+"_Form",AnsiString(f->Name),f->Caption);
            }
     
     
     
     
        delete Ini;
      }
     
    }
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"fr.lng");
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
      ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"en.lng");
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
      ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"fr.lng");
    }
    //---------------------------------------------------------------------------

    Unit1.h

    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
     
    //---------------------------------------------------------------------------
     
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// IDE-managed Components
      TLabel *Label1;
      TLabel *Label2;
      TButton *Button1;
      TButton *Button2;
      void __fastcall Button1Click(TObject *Sender);
      void __fastcall Button2Click(TObject *Sender);
      void __fastcall FormCreate(TObject *Sender);
    private:	// User declarations
    public:		// User declarations
      __fastcall TForm1(TComponent* Owner);
      void __fastcall ChargerLangue(TForm *f, AnsiString filename);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif



    6°) remarques
    Il est possible de "TOUT" traduire de façon dynamique et automatique. pour cela, il suffit de maitriser le composant à traduire.

  2. #2
    Membre chevronné
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Points : 2 189
    Points
    2 189
    Par défaut
    Merci de partager tes connaissances.
    Citation Envoyé par echap2000
    Inconvénients :
    - et bien, je n'en ai pas encore vu.
    • N'importe qui peut écrire ce qu'il veux dans l'application, ce n'est pas pratique pour les applications commerciales.
    • On a besoin de distribuer plusieurs fichiers en plus du fichier exécutable.

    Je comprends que c'est deux problèmes ne touche pas tout les gens, mais dans mon cas c'est un problème. C'est pourquoi j'utilise des fichier ressource (.rc). Ensuite je compresse mon fichier exécutable.
    • Plus un ordinateur possède de RAM, plus vite il peut générer un message d'erreur. - Dave Barry
    • Je n'ai pas peur des ordinateurs. J'ai peur qu'ils viennent à nous manquer. - Isaac Asimov
    • Le code source est comme une belle femme, plus on le regarde, plus on trouve des défauts. - Crayon

  3. #3
    Membre confirmé Avatar de kurul1
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    933
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 933
    Points : 466
    Points
    466
    Par défaut
    Moi j'ai fait la même chose que toi mais avec un fichier XML

  4. #4
    Membre du Club
    Inscrit en
    Juillet 2004
    Messages
    51
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 51
    Points : 53
    Points
    53
    Par défaut
    Merci pour le tuto !

    Crayon tu pourrais donner un p'tit exemple de ta façon de faire stp ?
    Histoire de comparer

  5. #5
    Membre éprouvé
    Avatar de bandit boy
    Profil pro
    Inscrit en
    Février 2006
    Messages
    916
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 916
    Points : 1 007
    Points
    1 007
    Par défaut
    Salut,
    Perso j'ai opté pour une solution un peu similaire sauf que je suis dans un fichier texte.

    Pour remédier aux problèmes décrit par Crayon, ce fichier est placé en ressource de l'exe, ce fichier devient alors invisible par l'utilisateur puiqu'il se trouve dans l'exe. Toutefois, il reste la possibilité de l'extraire de l'exe pour le modifier et le remettre.

    Pour garder un maximum d'assurance, c'est un double qui est modifié et l'original reste bien en ressource.

    Méthode à ajouter aux autres proposés pour la FAQ, messieurs les modérateurs.

    Au passage, encore merci à eux pour le travail qu'ils effectuent ici pour que tout le monde puisse s'y retrouver.

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Février 2004
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2004
    Messages : 83
    Points : 55
    Points
    55
    Par défaut
    N'importe qui peut écrire ce qu'il veux dans l'application, ce n'est pas pratique pour les applications commerciales.
    On a besoin de distribuer plusieurs fichiers en plus du fichier exécutable.
    N'importe qui peut écrire.. mais il suffit de ne pas traduire certains FORM et certains composants. (tant que dans la fonction chargerlangue il n'y a pas tous les composants, et tant que la Form qui doit être traduite n'appellera pas la fonction). Mais si tu ne veux pas que le fichier de traduction soit externe, dans ce cas, il suffit de l'importer comme tu dis..Et puis la traduction d'une application payante peut rester externe. pourquoi c'est si important de l'avoir en interne?

    Pour la distribution des fichiers en plus de l'exécutable... oui c'est normal si tu regardes de ce point de vue.

  7. #7
    Membre chevronné
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Points : 2 189
    Points
    2 189
    Par défaut
    Citation Envoyé par echap2000
    N'importe qui peut écrire.. mais il suffit de ne pas traduire certains FORM et certains composants. (tant que dans la fonction chargerlangue il n'y a pas tous les composants, et tant que la Form qui doit être traduite n'appellera pas la fonction). Mais si tu ne veux pas que le fichier de traduction soit externe, dans ce cas, il suffit de l'importer comme tu dis..Et puis la traduction d'une application payante peut rester externe. pourquoi c'est si important de l'avoir en interne?
    C'est important de l'avoir à l'interne pour être certain que le produit ne soit pas altérer par autrui. Habituellement, lorsque l'on traduit une application on ne fais pas d'exception, donc tout est traduit. Le copyright deviens tout droit réserver, on ne veux que quelqu'un change le nom de la compagnie à cet endroit. Je sais, peut-être que mon exemple est mauvais Le but est surtout de garder le contrôle sur l'application. Par contre pour un freeware se point deviens un avantage car n'importe qui peut faire la traduction du logiciel et en faire bénéficier plus de gens.

    Au lieu d'utiliser une structure comme celle-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [Form1_Form]
    Form1=titre en français
     
    [Form1_Label]
    Label1=Label en français
    Label2=Label2 en français
     
    [Form1_Button]
    Button1=Français
    Button2=Anglais
    J'utilise le champ tag des composants pour y mettre un numéro qui correspond à la ressource. C'est de cette façon que VB fonctionne lorsque que l'on crée un projet multi-langue. Si le tag n'est pas disponible y a toujours le caption ou autre...

    En passant echap2000, je ne critique pas ton travail je veux seulement mentionner d'autre façon de travailler. Chacun à des restrictions qui lui son propre pour le développement d'un logiciel X.
    • Plus un ordinateur possède de RAM, plus vite il peut générer un message d'erreur. - Dave Barry
    • Je n'ai pas peur des ordinateurs. J'ai peur qu'ils viennent à nous manquer. - Isaac Asimov
    • Le code source est comme une belle femme, plus on le regarde, plus on trouve des défauts. - Crayon

  8. #8
    Membre éclairé
    Avatar de Interruption13h
    Inscrit en
    Août 2005
    Messages
    603
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 603
    Points : 786
    Points
    786
    Par défaut
    Avant tout merci pour ce partage
    je voulais juste dire que je croi qu'il existe un outils intégré dans C++Builder (V6 dans mon cas) pour la traduction des application :
    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
     
     
    Borland’s suite of Translation Tools facilitate software localization and
     simultaneous development of applications for different locales. The
     Translation Tools are integrated with the IDE, but can also be used
     externally. 
     
    The Translation Tools suite is made up of the following tools:
     
    The Resource DLL wizard generates resource DLLs for the languages you
     select.
        The Translation Manager provides a grid for viewing and editing forms
     and resource strings. After modifying your translations, you can update all
     of your application’s resource DLLs. The External Translation Manager
     (ETM) is the external version of the Translation Manager, which you can
     set up and use from outside the IDE. The ETM has the same functionality
     as the Translation Manager with some additional toolbars and menus. It
     also includes some of the functionality of the Resource DLL wizard.
     
    The Translation Repository provides a central database for translations that
     can be shared across projects and by different developers.
    L'executable s'appel "etm60.exe" qui se trouve dans le même dossier que "bcb.exe"
    Je signal que je l'ai jamais utilisé

    A+
    Plus tu prends part aux joies et chagrins des gens, plus ils te sont proches et chers. Mais c'est le chagrin et les problèmes qui vous rapprochent le plus.

    (Mark TWAIN)

  9. #9
    Membre chevronné
    Avatar de Crayon
    Inscrit en
    Avril 2005
    Messages
    1 811
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Avril 2005
    Messages : 1 811
    Points : 2 189
    Points
    2 189
    Par défaut
    Dans BCB 2007 il y a etm.exe External Translation Manager

    Moi non plus je ne l'ai jamais utilisé
    • Plus un ordinateur possède de RAM, plus vite il peut générer un message d'erreur. - Dave Barry
    • Je n'ai pas peur des ordinateurs. J'ai peur qu'ils viennent à nous manquer. - Isaac Asimov
    • Le code source est comme une belle femme, plus on le regarde, plus on trouve des défauts. - Crayon

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Février 2004
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2004
    Messages : 83
    Points : 55
    Points
    55
    Par défaut
    En passant echap2000, je ne critique pas ton travail je veux seulement mentionner d'autre façon de travailler. Chacun à des restrictions qui lui son propre pour le développement d'un logiciel X.
    Pas du tout pas du tout. je suis ouvert à tout ta remarque est importante pour les applications "copyrightées".

    Je vais bientôt poster un autre tuto sur ma classe MySQL.. où on pourra facilement jongler avec Query, fetch_row etc.

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