[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:
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:
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:
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:
#include "IniFiles.hpp"
et dans le .h la déclaration de notre fonction :
Code:
void __fastcall ChargerLangue(TForm *f, AnsiString filename);
maintenant allez dans l'evénement OnClick du Button1
Ensuite on appelle la fonction ChargerLangue
Code:
ChargerLangue(Form1,ExtractFilePath(Application->ExeName)+"fr.lng");
Même chose pour Onclick du Button2 mais cette fois-ci pour en.lng
Code:
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:
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:
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:
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.