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
On va sauvegarder ce fichier dans le même répertoire que notre application.
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
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
N'oublions pas de placer dans le .cpp la ligne :
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; } }
et dans le .h la déclaration de notre fonction :
Code : Sélectionner tout - Visualiser dans une fenêtre à part #include "IniFiles.hpp"
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
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)+"fr.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.
Partager