[Plan du site]
Vous êtes ici ---
> Le Site du Zéro
> Les tutoriels
> Officiels
> Programmation
> Apprenez à programmer en C++ ! > [Pratique] Créez vos propres fenêtres avec Qt > Traduire son programme avec Qt Linguist
> Lecture du tutoriel
Traduire son programme avec Qt Linguist
Si vous avez de l'ambition pour vos programmes, vous aurez peut-être envie un jour de les traduire dans d'autres langues. En effet, ce serait dommage de limiter votre programme seulement aux francophones, il y a certainement de nombreuses autres personnes qui aimeraient pouvoir en profiter !
La traduction d'applications n'est normalement pas une chose facile. D'ailleurs, il ne s'agit pas seulement de traduire des mots ou des phrases. Il ne suffit pas toujours de dire "Ouvrir" = "Open".
En effet, on parle des milliers de langues et dialectes différents sur notre bonne vieille planète. Certaines ressemblent au français, certaines écrivent de droite à gauche (l'arabe par exemple), d'autres ont des accents très particuliers que nous n'avons l'habitude d'utiliser (le ñ espagnol par exemple). Et je vous parle même pas des caractères hébraïques et japonais.
On ne parle donc pas seulement de traduction mais de
localisation. Il faut que notre programme puisse s'adapter avec les habitudes de chaque langue. Il faut que les phrases soient écrites de droite à gauche si nécessaire.
C'est là que Qt excelle et vous simplifie littéralement la tâche. Tout est prévu. Tous les outils pour traduire au mieux vos applications sont installés de base.
Comment ça fonctionne ? Nous allons voir ça.
La traduction de programmes Qt est un processus bien pensé... mais encore faut-il comprendre comment ça fonctionne.
Qt suppose que les développeurs (vous) ne sont pas des traducteurs. Il suppose donc que ce sont 2 personnes différentes.
Tout a été fait pour que les traducteurs, même si ce ne sont pas des informaticiens, soient capables de traduire votre programme.
Dans la pratique, si c'est un petit projet personnel, vous serez peut-être aussi le traducteur de votre programme. Mais nous allons supposer ici que le traducteur est une autre personne.
Je vous propose de regarder ce schéma de mon crû qui résume grosso modo les étapes de la traduction :

- Tout d'abord, il y a le développeur. C'est vous. Vous écrivez normalement votre programme, en rédigeant les messages dans le code source dans votre langue maternelle (le français). Bref, rien ne change, à part un ou deux petits détails dont on reparlera dans la prochaine sous-partie.
- Puis, vous générez un fichier contenant les chaînes à traduire. Un programme livré avec Qt le fait automatiquement pour vous. Ce fichier porte l'extension .ts, et est généralement de la forme : nomduprogramme_langue.ts.
Par exemple, pour le ZeroClassGenerator, ça donne quelque chose comme zeroclassgenerator_en.ts pour la traduction anglaise, zeroclassgenerator_es.ts pour la traduction espagnole, etc. Il faut connaître le symbole à 2 lettres de la langue de destination pour donner un nom correct au fichier .ts. Généralement c'est la même chose que les extensions des noms de domaine : fr (français), pl (polonais), ru (russe)...
- Le traducteur récupère le ou les fichiers .ts à traduire (un par langue). Il les traduit via le programme Qt Linguist qu'on découvrira dans quelques minutes.
- Une fois que le traducteur a fini, il retourne les fichiers .ts traduits au développeur, qui les "compile" en fichiers .qm binaires. La différence entre un .ts et un .qm, c'est un peu comme la différence entre un .cpp (la source) et un .exe (le programme binaire final).
Le .qm contenant les traductions au format binaire, Qt pourra le charger et le lire très rapidement lors de l'exécution du programme, ce qui fait qu'on ne sentira pas de ralentissement si on charge une version traduite du programme.
Je vous propose de découvrir pas à pas chacune de ces étapes dans ce chapitre.

Nous allons commencer par vous, le développeur. Que faut-il faire de spécial lorsque vous écrivez le code source du programme ?
La toute première étape de la traduction consiste a écrire son code de manière adaptée, afin que des traducteurs puissent ensuite récupérer tous les messages à traduire.
Utilisez QString pour manipuler des chaînes de caractères
Comme vous le savez déjà, Qt utilise exclusivement sa classe
QString pour gérer les chaînes de caractères. Cette classe, très complète, gère nativement l'Unicode.
QString n'a donc aucun problème pour gérer des alphabets cyrilliques ou arabes.
C'est pourquoi il est recommandé, si votre application est susceptible d'être traduite, d'utiliser toujours des QString pour manipuler des chaînes de caractères.
Code : C++1
2 | QString chaine = "Bonjour"; // Bon : adapté pour la traduction
char chaine[] = "Bonjour"; // Mauvais : inadapté pour la traduction
|
Voilà, c'est juste un conseil que je vous donne là : de manière générale, utilisez autant que possible des QString. Evitez les tableaux de char.
Faites passer les chaînes à traduire par la méthode tr()
Utilisation basique
La méthode tr() permet d'indiquer qu'une chaîne devra être traduite. Par exemple, avant vous faisiez :
Code : C++1 | quitter = new QPushButton("&Quitter");
|
Cela ne permettra pas de traduire le texte du bouton. En revanche, si vous faites d'abord appel à la méthode tr() :
Code : C++1 | quitter = new QPushButton(tr("&Quitter"));
|
... alors le texte pourra être traduit ensuite.

Vous rédigez donc les textes de votre programme dans votre langue maternelle (ici le français) en les entourant d'un tr().
La méthode tr() est définie dans QObject. C'est donc une méthode statique dont héritent toutes les classes de Qt, puisqu'elles dérivent de QObject. Dans la plupart des cas, écrire tr() devrait donc fonctionner. Si toutefois vous n'êtes pas dans une classe qui hérite de QObject, il faudra faire précéder tr() de QObject::, comme ceci :
quitter = new QPushButton(QObject::tr("&Quitter"));
Facultatif : ajouter un message de contexte
Parfois, il arrivera que le texte à traduire ne soit pas suffisamment explicite à lui tout seul, ce qui rendra difficile sa traduction pour le traducteur qui ne le verra pas dans son contexte.
Vous pouvez ajouter en second paramètre un message pour expliquer le contexte au traducteur.
Code : C++1 | quitter = new QPushButton(tr("&Quitter", "Utilisé pour le bouton de fermeture"));
|
Ce message ne sera pas affiché dans votre programme : il aidera juste le traducteur à comprendre ce qu'il doit traduire. En effet, dans certaines langues "Quitter" se traduit peut-être de plusieurs manières différentes. Avec le message de contexte, le traducteur saura comment bien traduire le mot.
En général, le message de contexte n'est pas obligatoire.
Parfois cependant, il devient vraiment indispensable. Par exemple quand on doit traduire un raccourci clavier (eh oui !) :
Code : C++1 | actionQuitter->setShortcut(QKeySequence(tr("Ctrl+Q", "Raccourci clavier pour quitter")));
|
Le traducteur pourra ainsi traduire la chaîne en "Ctrl+S" si c'est le raccourci adapté dans la langue de destination.
Facultatif : gestion des pluriels
Parfois, une chaîne doit être écrite différemment selon le nombre d'éléments.
Imaginons un programme qui lit le nombre de fichiers dans un répertoire. Il affiche le message "
Il y a X fichier(s)". Comment traduire ça correctement ?
En fait, ça dépend vraiment des langues. Le pluriel est géré différemment en anglais et en français par exemple :
| Nombre | Français | Anglais |
|---|
0 |
Il y a 0 fichier. |
There are 0 files. |
1 |
Il y a 1 fichier. |
There is 1 file. |
2 |
Il y a 2 fichiers. |
There are 2 files. |
Comme vous pouvez le voir, en français on dit "
Il y a 0 fichier.", et en anglais "
There are 0 files.". Les anglais mettent du pluriel quand le nombre d'éléments est à 0 !
Et encore, je vous parle pas des russes, qui ont un pluriel pour quand il y a 2 éléments et un autre pluriel pour quand il y en a 3 !
(je simplifie parce qu'en fait c'est même un peu plus compliqué que ça encore)
J'vais jamais m'en sortir avec tous ces cas à gérer !

Eh bien si, rassurez-vous. Qt est capable de gérer tous les pluriels pour chacune des langues.
Ce sera bien entendu le rôle du traducteur ensuite de traduire ces pluriels correctement.
Comment faire ? Utilisez le 3ème paramètre facultatif qui indique la cardinalité (le nombre d'éléments).
Exemple :
Code : C++1 | tr("Il y a %n fichier(s)", "", nombreFichiers);
|
Si on ne veut pas indiquer de contexte comme moi dans ce cas, on est quand même obligé d'envoyer une chaîne vide pour utiliser le 3ème paramètre (c'est la règle des paramètres facultatifs en C++).
Qt utilisera automatiquement la bonne version du texte traduit selon la langue de destination et le nombre d'éléments.
Par ailleurs, le %n sera remplacé par le nombre indiqué en 3ème paramètre.
Bon, avec tout ça, votre programme est codé de manière à pouvoir être traduit.
Maintenant, comment se passe l'étape de la traduction ?
Nous avons maintenant un programme qui fait appel à la méthode tr() pour désigner toutes les chaînes de caractères qui doivent être traduites.
On va prendre l'exemple de notre TP ZeroClassGenerator. Je l'ai adapté pour qu'il utilise des tr().
On souhaite que ZeroClassGenerator soit traduit dans les langues suivantes :
Nous devons générer 2 fichiers de traduction :
- zeroclassgenerator_en.ts pour l'anglais
- zeroclassgenerator_es.ts pour l'espagnol
Il va falloir éditer le fichier .pro. Celui-ci se trouve dans le dossier de votre projet et a normalement été généré automatiquement lorsque vous avez fait
qmake -project.
Ouvrez ce fichier (dans mon cas ZeroClassGenerator.pro) avec un éditeur de texte comme Bloc-Notes, ou Notepad++, ou ce que vous voulez.
Pour le moment il devrait contenir quelque chose comme ça :
Code : Autre1
2
3
4
5
6
7
8
9
10
11
12
| ######################################################################
# Automatically generated by qmake (2.01a) ven. 23. mai 16:31:10 2008
######################################################################
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += FenCodeGenere.h FenPrincipale.h
SOURCES += FenCodeGenere.cpp FenPrincipale.cpp main.cpp |
Rajoutez à la fin une directive TRANSLATIONS en indiquant les noms des fichiers de traduction à générer. Ici, nous rajoutons un fichier pour la traduction anglaise, et un autre pour la traduction espagnole :
Code : Autre1
2
3
4
5
6
7
8
9
10
11
12
13
| ######################################################################
# Automatically generated by qmake (2.01a) ven. 23. mai 16:31:10 2008
######################################################################
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += FenCodeGenere.h FenPrincipale.h
SOURCES += FenCodeGenere.cpp FenPrincipale.cpp main.cpp
TRANSLATIONS = zeroclassgenerator_en.ts zeroclassgenerator_es.ts |
Bien. Maintenant, nous allons faire appel à un programme en console de Qt qui permet de générer automatiquement les fichiers .ts.
Ouvrez une console (sous Windows, utilisez le raccourci Qt Command Prompt que vous utilisez normalement d'habitude pour compiler). Allez dans le dossier de votre projet.
Tapez :
Code : Console
lupdate est un programme qui va mettre à jour les fichiers de traduction .ts, ou les créer si ceux-ci n'existent pas.
Essayons d'exécuter lupdate sur ZeroClassGenerator.pro :
Code : Console | C:\Users\Mateo\Projets\ZeroClassGenerator>lupdate ZeroClassGenerator.pro
Updating 'zeroclassgenerator_en.ts'...
Found 17 source text(s) (17 new and 0 already existing)
Updating 'zeroclassgenerator_es.ts'...
Found 17 source text(s) (17 new and 0 already existing) |
Le programme lupdate a trouvé dans mon code source 17 chaînes à traduire. Il a vérifié si les .ts existaient (ce qui n'était pas le cas) et les a donc créé.
Ce programme est intelligent puisque, si vous l'exécutez une seconde fois, il ne mettra à jour que les chaînes qui ont changé. C'est très pratique, puisque cela permet d'avoir à faire traduire au traducteur seulement ce qui a changé par rapport à la version précédente de votre programme !
Vous devriez maintenant avoir 2 fichiers supplémentaires dans le dossier de votre projet : zeroclassgenerator_en.ts et zeroclassgenerator_es.ts.
Envoyez-les à votre traducteur (s'il sait parler anglais et espagnol

). Bien entendu, le fait qu'on ait 2 fichiers distincts nous permet d'envoyer le premier à un traducteur anglais, et le second à un traducteur espagnol.
Qt a installé plusieurs programmes, vous vous souvenez ?
L'un d'eux va nous être sacrément utile maintenant : c'est
Qt Linguist.
Votre traducteur a besoin de 2 choses :
- Du fichier .ts à traduire
- Et de Qt Linguist pour pouvoir le traduire !
Votre traducteur lance donc Qt Linguist. Il devrait voir quelque chose comme ça :
Ca a l'air un petit peu compliqué (et encore, vous avez pas vu Qt Designer

).
Vous reconnaissez d'ailleurs sûrement une QMainWindow, avec une barre de menus, une barre d'outils, des docks, et un widget central (bah oui, les programmes livrés avec Qt sont faits avec Qt

).
En fait, les docks prennent tellement de place qu'on a du mal à savoir où est le widget central. Pour vous aider, c'est l'espèce de bulle ronde au milieu à droite, avec "Source text" et "Translation". C'est justement là qu'on traduira les chaînes de caractères.
Comme vous le savez déjà, les docks peuvent être déplacés. N'hésitez pas à arranger la fenêtre à votre guise. Vous pouvez même faire sortir les docks de la fenêtre principale pour en faire des mini-fenêtres flottantes.
Ouvrez un des fichiers .ts avec Qt Linguist, par exemple zeroclassgenerator_en.ts. La fenêtre se remplit :
Détaillons un peu chaque section de la fenêtre :
- Context (à gauche) : affiche la liste des fichiers source qui contiennent des chaînes à traduire. Vous reconnaissez vos fenêtres FenCodeGenere et FenPrincipale. Le nombre de chaînes traduites est indiqué à droite.
- Strings (en haut) : c'est la liste des chaînes à traduire pour le fichier sélectionné. Ces chaînes ont été extraites grâce à la présence de la méthode tr().
- Au milieu : vous avez la version française de la chaîne, et on vous demande d'écrire la version anglaise. Notez que Qt a automatiquement détecté que vous alliez traduire en anglais, grâce au nom du fichier qui contient "en".
Si la chaîne à traduire peut être mise au pluriel, Qt Linguist vous demandera 2 traductions : une au singulier ("There is %n file") et une au pluriel ("There are %n files").
- Warnings (en bas) : affiche des avertissements bien utiles , comme "Vous avez oublié de mettre un & pour faire un raccourci", ou "La chaîne traduite ne se termine pas par le même signe de ponctuation" (ici un deux-points). Cette zone peut afficher aussi la chaîne à traduire dans son contexte du code source.
C'est maintenant au traducteur de traduire tout ça !
Lorsqu'il est sûr de sa traduction, il doit marquer la chaîne comme étant validée (en cliquant sur le petit "?" ou en faisant Ctrl + Entrée). Une petit symbole coché vert doit apparaître, et le dock context doit afficher que toutes les chaînes ont bien été traduites (16/16 par exemple).
Voici les 3 états que peut avoir chaque message :
On procède donc en 2 temps : d'abord on traduit, puis ensuite on se relit et on valide. Lorsque toutes les chaînes sont validées (en vert), le traducteur vous rend le fichier .ts.
Il ne nous reste plus qu'une étape : compiler ce .ts en un .qm, et adapter notre programme pour qu'il charge automatiquement le programme dans la bonne langue.
Dernière ligne droite !
Nous avons le .ts entièrement traduit par notre traducteur adoré, il ne nous reste plus qu'à le compiler dans le format final binaire .qm, et à le charger dans l'application.
Compiler le .ts en .qm
Pour effectuer cette compilation, nous devons utiliser un autre programme de Qt :
lrelease.
Ouvrez donc une console Qt, rendez-vous dans le dossier de votre projet, et tapez :
Code : Console
... pour compiler le fichier .ts indiqué.
Vous pouvez aussi faire :
Code : Console
... pour compiler tous les fichiers .ts du projet.
Comme je viens de terminer la traduction anglaise, je vais compiler le fichier .ts anglais :
Code : Console | C:\Users\Mateo\Projets\ZeroClassGenerator>lrelease zeroclassgenerator_en.ts
Updating 'zeroclassgenerator_en.qm'...
Generated 17 translation(s) (17 finished and 0 unfinished) |
Vous pouvez voir que lrelease ne compile que les chaînes marquées comme terminées (celles qui ont le symbole vert dans Qt Linguist). Si certaines ne sont pas marquées comme terminées, elles ne seront pas compilées dans le .qm.
Les chaînes non traduites ou non validées n'apparaîtront donc pas dans le programme. Dans ce cas, c'est la chaîne par défaut écrite dans le code (ici en français) qui sera affichée à la place.
D'autre part, notez que vous pouvez aussi faire la même chose directement dans Qt Linguist, en allant dans le menu File / Release.
Nous avons maintenant un fichier
zeroclassgenerator_en.qm dans le dossier de notre projet. Cool.
Si on le chargeait dans notre programme maintenant ?
Charger un fichier de langue .qm dans l'application
Le chargement d'un fichier de langue s'effectue au début de la fonction main().
Pour le moment, votre fonction main() devrait ressembler à quelque chose comme ceci :
Code : C++1
2
3
4
5
6
7
8
9 | int main(int argc, char* argv[])
{
QApplication app(argc, argv);
FenPrincipale fenetre;
fenetre.show();
return app.exec();
}
|
Juste après la création de l'objet de type QApplication, nous allons rajouter les lignes suivantes :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13 | int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTranslator translator;
translator.load("zeroclassgenerator_en");
app.installTranslator(&translator);
FenPrincipale fenetre;
fenetre.show();
return app.exec();
}
|
Vérifiez bien que le fichier .qm se trouve dans le même dossier que l'exécutable, sinon la traduction ne sera pas chargée et vous aurez toujours l'application en français !
Si tout va bien, bravo, vous avez traduit votre application !
Euh, c'est bien mais c'est pas pratique. Là, mon application se chargera toujours en anglais. Il n'y a pas moyen qu'elle s'adapte à la langue de l'utilisateur ?
Si, bien sûr, c'est faisable. C'est même ce qu'on fera dans 99% des cas.
Dans ce cas, on peut procéder comme ceci :
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QString locale = QLocale::system().name().section('_', 0, 0);
QTranslator translator;
translator.load(QString("zeroclassgenerator_") + locale);
app.installTranslator(&translator);
FenPrincipale fenetre;
fenetre.show();
return app.exec();
}
|
Explication : on veut récupérer le code à 2 lettres de la langue du PC de l'utilisateur. On utilise une méthode statique de
QLocale pour récupérer des informations sur le système d'exploitation sur lequel le programme a été lancé.
La méthode
QLocale::system().name()
renvoie un code ressemblant à ceci : "
fr_FR", où "fr" est la langue (français) et "FR" le pays (France).
Si vous êtes québecois, vous aurez par exemple "
fr_CA" (français au Canada).
On veut juste récupérer les 2 premières lettres. On utilise la méthode section() pour couper le chaîne en deux autour de l'underscore "_". Les 2 autres paramètres permettent d'indiquer qu'on veut le premier mot à gauche de l'underscore, à savoir le "fr".
Au final, notre variable locale contiendra juste ce qu'on veut : la langue de l'utilisateur (par exemple "fr").
On combine cette variable avec le début du nom du fichier de traduction, comme ceci :
Code : C++1 | QString("zeroclassgenerator_") + locale
|
Si locale vaut "fr", le fichier de traduction chargé sera "zeroclassgenerator_fr".
Si locale vaut "en", le fichier de traduction chargé sera "zeroclassgenerator_en".
C'est compris ?
Grâce à ça, notre programme ira chercher le fichier de traduction correspondant à la langue de l'utilisateur. Au pire des cas, si le fichier de traduction n'existe pas car vous n'avez pas fait de traduction dans cette langue, c'est la langue française qui sera utilisée.
Vous voilà maintenant aptes à traduire dans n'importe quelle langue !

Pour information, voilà ce que donne le ZeroClassGenerator traduit en arabe (merci à
zoro_2009 pour la traduction !) :
Voilà donc la preuve que Qt peut vraiment gérer tous les caractères de la planète grâce à son support de l'Unicode.
Comme vous avez pu le constater, la traduction d'applications Qt est un processus bien rôdé : tout est prévu !
Vous avez maintenant tous les outils en main pour diffuser votre programme partout dans le monde, même au Japon ! Encore faut-il trouver un traducteur japonais...
... et pour ça, désolé les amis, mais je ne pourrai vraiment pas vous aider.