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.