I. Préparer l'internationalisation▲
L'internationalisation d'un projet Delphi doit être envisagée avant même de commencer le développement de l'application. Il y a en effet un certain de nombre de détails à prendre en compte aussi bien pendant l'écriture du code que durant la conception de l'interface et qui faciliteront la traduction. Les principaux points sont les suivants.
I-A. Messages pour l'utilisateur▲
Vous devez isoler les messages envoyés à l'utilisateur dans les ressources de votre projet afin de pouvoir les traduire sans modifier votre projet lui-même. Les resourcestring de Delphi permettent d'atteindre cet objectif. Vous devez simplement déclarer votre chaîne de caractères en resourcestring avant de l'utiliser :
// ancienne méthode
ShowMessage('Au revoir'
);
// nouvelle méthode
resourcestring
MessageFin = 'Au revoir'
;
...
ShowMessage(MessageFin); // bon
Et si votre message comporte plusieurs morceaux, regroupez-les en utilisant les chaînes de format :
// ancienne méthode
ShowMessage('Vous avez '
+IntToStr(I)+' éléments'
);
// mauvaise nouvelle méthode
resourcestring
DebutMsg = 'Vous avez'
;
FinMsg = ' éléments'
;
...
ShowMessage(Debut+IntToStr(I)+FinMsg); // mauvais
// bonne nouvelle méthode
resourcestring
MonMessage = 'Vous avez %d éléments'
;
...
ShowMessage(Format(MonMessage,[i])); // bon
Vous aurez ainsi des phrases facilement compréhensibles par le traducteur plutôt que des bouts de texte disparates.
Il est conseillé, mais ce n'est pas une obligation, de les réunir dans une unité à part, unique pour l'ensemble du projet :
unit
chaines;
interface
resourcestring
MonMessage = 'Bonjour monde'
;
implementation
end
.
Pour conclure sur les resourcestring, si vous n'avez pas extrait les chaînes de texte au cours de la conception, j'ai développé ma propre méthode de traduction qui s'affranchit de ce problème.
I-B. Gestion des chaînes▲
La gestion des chaînes de caractères est un autre point important, surtout si vous envisagez d'utiliser des langues orientales dont tous les caractères ne peuvent pas être représentés par un jeu de 256 caractères. Dans ce cas, un caractère peut aussi bien être représenté par un seul ou par deux octets et la longueur d'un texte n'est alors pas toujours égale au nombre d'octets. On parle aussi de jeux de caractères MBCS (MultiByte Character Sets). À chaque fois que vous effectuez un traitement sur une chaîne, vous devez vous demander si celui-ci est compatible avec les jeux MBCS. Vous devez aussi vérifier dans l'aide de Delphi que les fonctions que vous appelez sont compatibles. Pour celles qui ne le sont pas, il existe dans de nombreux cas une fonction équivalente préfixée par Ansi :
// exemple extrait de l'aide de Delphi
function
LowerCase(const
S: string
): string
;
Description
LowerCase renvoie une chaîne AnsiString contenant le même texte que celui de la chaîne transmis par S, l'ensemble des lettres ayant été converties en minuscules. La conversion n'affecte que les caractères ASCII sur 7 bits compris entre 'A' et 'Z'. Pour convertir les caractères internationaux sur 8 bits, utilisez AnsiLowerCase.
function
AnsiLowerCase(const
S: string
): string
;
Description
AnsiLowerCase renvoie une chaîne, qui est une copie de la chaîne donnée convertie en minuscules. La conversion fait appel au pilote de langue Windows actuellement installé. Cette fonction accepte les jeux de caractères MBCS (MultiByte Character Sets).
Nous constatons que non seulement AnsiLowerCase gère les caractères MCBS, mais s'occupe aussi de la conversion des caractères accentués, ce que ne fait pas LowerCase. Comme je n'ai pas vraiment de compétences concernant la traduction avec les caractères MCBS, je vous invite à consulter l'aide de Delphi qui fait le tour du problème.
I-C. Utilisation des paramètres régionaux▲
Après le respect de la langue de l'utilisateur, il est fortement conseillé de tenir correctement compte des paramètres régionaux (y compris pour les projets non internationalisés).
Si l'utilisateur a choisi la virgule comme séparateur décimal, il est de bon goût, lorsqu'il effectue une saisie avec le pavé numérique de remplacer la frappe du point par une virgule. Sauf qu'en Allemagne, par exemple, il y a une virgule sur le pavé numérique qu'il faut transformer en point si celui-ci est le séparateur décimal. Le code suivant doit résoudre ce problème dans toutes les situations :
Virgule : boolean
;
procedure
TForm1.EditXMinKeyDown(Sender: TObject; var
Key: Word
;
Shift: TShiftState);
begin
Virgule:=(Key=VK_DECIMAL); // détection de l'appui de la touche séparateur décimal
// sur le pavé numérique
end
;
procedure
TForm1.EditXMinKeyPress(Sender: TObject; var
Key: Char
);
begin
if
Virgule then
Key:=decimalseparator; // on met le séparateur décimal de l'utilisateur à la place
end
;
Dans le même genre, vous pouvez avoir des surprises avec la gestion de la date ou de l'heure. J'ai par exemple créé une application chronomètre qui m'indique le temps écoulé en hh:mm:ss en utilisant TimeToStr. J'amène ça au travail, sur un ordinateur en allemand, et surprise, j'obtiens 12:00:01 AM. Donc, n'hésitez pas à jouer avec les paramètres régionaux pour voir si votre application se comporte bien avec toutes les possibilités, sachant que je n'ai pas pu reproduire sur mon PC l'affichage AM/PM dans mon application même quand il était actif au niveau de l'horloge de Windows.
I-D. Conception de l'interface▲
Enfin, la préparation concerne l'interface graphique et consiste à prévenir les variations de longueur du texte affiché. Bien que cette adaptation puisse être réalisée après la traduction, la mise en œuvre des conseils suivants facilitera fortement le travail des personnes chargées de l'internationalisation. Vous devez donc réserver suffisamment d'espace au texte affiché dans les fenêtres pour qu'il puisse s'adapter à la nouvelle langue. Faites en particulier attention aux abréviations qui n'existent pas dans d'autres langues et qui exigeront beaucoup plus de place. L'aide de Delphi (recherchez le mot foisonnement) fournit des indications sur le pourcentage de place à prévoir en fonction de la taille du mot.
Petite astuce concernant les labels. Si un label est centré au-dessus d'un contrôle, mettez ses propriétés Autosize à false, Alignment à taCenter et augmentez sa largeur en prévision de la traduction. Ainsi, lorsque le texte changera de taille, il restera centré au-dessus de l'autre contrôle :
Pour un label situé devant un contrôle, faite le contraire avec Autosize à true et Alignment à taLeftJustify et prévoyez assez de place entre le label et le contrôle.
Pour terminer, je vous conseille fortement de consulter l'aide de Delphi sur le sujet, qui détaille certaines des remarques précédentes et fournit d'autres informations.