Difference between revisions of "Translations / i18n / localizations for programs/fr"

From Free Pascal wiki
Jump to navigationJump to search
m (Fixed syntax highlighting; deleted category included in page template)
 
(7 intermediate revisions by one other user not shown)
Line 4: Line 4:
  
 
Cette page concerne la façon dont un programme peut utiliser différentes chaînes pour des langues aussi variées que l'anglais, le chinois, l'allemand, le finnois, l'italien, etc.
 
Cette page concerne la façon dont un programme peut utiliser différentes chaînes pour des langues aussi variées que l'anglais, le chinois, l'allemand, le finnois, l'italien, etc.
Fondamentalement, cela fonctionne comme ceci : ajoutez une ''resourcestring'' pour chaque légende(''caption'') ; compilez pour obtenir les fichiers .rst et/ou .po (l'EDI peut le faire automatiquement) ; créez un fichier traduit .po pour chaque langue (il existe des outils visuels libres pour ce faire) ; utilisez les fonctions de l'unité ''translations'' de la LCL pour charger la bonne version de traduction au lancement du programme.
+
Fondamentalement, cela fonctionne comme ceci :
 +
* ajoutez une ''resourcestring'' pour chaque légende (''caption'') ;
 +
* compilez pour obtenir les fichiers ''.rst'' et/ou ''.po'' (l'EDI peut le faire automatiquement) ;
 +
* créez un fichier traduit ''.po'' pour chaque langue (il existe des outils visuels libres pour ce faire) ;
 +
* utilisez les fonctions de l'unité ''translations'' de la LCL pour charger la bonne version de traduction au lancement du programme.
  
 
==Date, heure et format de nombres==
 
==Date, heure et format de nombres==
Line 13: Line 17:
  
 
Par exemple :
 
Par exemple :
<syntaxhighlight>resourcestring
+
<syntaxhighlight lang=pascal>resourcestring
 
     Caption1 = 'Du texte';
 
     Caption1 = 'Du texte';
 
     HelloWorld1 = 'Bonjour, monde';</syntaxhighlight>
 
     HelloWorld1 = 'Bonjour, monde';</syntaxhighlight>
  
 
Elles sont comme des constantes de chaîne normales, ce qui veut dire que vous pouvez les assigner à n'importe quelle chaîne. Par exemple :
 
Elles sont comme des constantes de chaîne normales, ce qui veut dire que vous pouvez les assigner à n'importe quelle chaîne. Par exemple :
<syntaxhighlight>Label1.Caption := HelloWorld1;</syntaxhighlight>
+
<syntaxhighlight lang=pascal>Label1.Caption := HelloWorld1;</syntaxhighlight>
  
 
Quand FPC les compile, il crée pour chaque unité un fichier '''unitname.rst''' contenant les données des chaînes de ressources (nom + contenu).
 
Quand FPC les compile, il crée pour chaque unité un fichier '''unitname.rst''' contenant les données des chaînes de ressources (nom + contenu).
Line 53: Line 57:
  
 
Les entrées en double apparaissent quand pour quelque raison le même texte est utilisé pour différentes chaînes de ressources. Un exemple au hasard : dans le fichier lazarus/ide/lazarusidestrconst.pas pour la chaîne 'Gutter':
 
Les entrées en double apparaissent quand pour quelque raison le même texte est utilisé pour différentes chaînes de ressources. Un exemple au hasard : dans le fichier lazarus/ide/lazarusidestrconst.pas pour la chaîne 'Gutter':
<syntaxhighlight>  dlfMouseSimpleGutterSect = 'Gutter';
+
<syntaxhighlight lang=pascal>  dlfMouseSimpleGutterSect = 'Gutter';
 
   dlgMouseOptNodeGutter = 'Gutter';
 
   dlgMouseOptNodeGutter = 'Gutter';
 
   dlgGutter = 'Gutter';
 
   dlgGutter = 'Gutter';
Line 85: Line 89:
 
Cette détection automatique des doublons n'est pas encore parfaite. La détection des doublons est effectuée quand des éléments sont ajoutés à la liste et il peut arriver que certaines entrées non traduites soient lues d'abord. Aussi se peut-il que plusieurs passes soient nécessaires pour récupérer tous les doublons traduits automatiquement par l'outil.
 
Cette détection automatique des doublons n'est pas encore parfaite. La détection des doublons est effectuée quand des éléments sont ajoutés à la liste et il peut arriver que certaines entrées non traduites soient lues d'abord. Aussi se peut-il que plusieurs passes soient nécessaires pour récupérer tous les doublons traduits automatiquement par l'outil.
  
===Entrées sources de confusions possibles===
+
===Entrées à l'origine de confusions possibles===
  
 
Les changements dans les chaînes de ressources affectent les traductions. Par exemple, si une chaîne de ressource a été initialement définie comme ceci :
 
Les changements dans les chaînes de ressources affectent les traductions. Par exemple, si une chaîne de ressource a été initialement définie comme ceci :
<syntaxhighlight>dlgEdColor = 'Syntax highlight';</syntaxhighlight>
+
<syntaxhighlight lang=pascal>dlgEdColor = 'Syntax highlight';</syntaxhighlight>
  
 
cela produirait une entrée .po similaire à ceci :  
 
cela produirait une entrée .po similaire à ceci :  
Line 102: Line 106:
 
Supposons que, plus tard, la chaîne de ressources a été changée en :
 
Supposons que, plus tard, la chaîne de ressources a été changée en :
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
   dlgEdColor = 'Colors';
 
   dlgEdColor = 'Colors';
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 124: Line 128:
 
En terme de format de fichier .po, le préfixe "#," signifie que l'entrée est marquée avec un drapeau (''fuzzy'') si bien que les programmes de traduction peuvent présenter à l'utilisateur traducteur une interface visuelle adaptée à cet élément. Dans le cas qui nous intéresse, le drapeau signifierait que la traduction dans son état actuel est douteuse et nécessite d'être révisée plus attentivement par le traducteur. Le préfixe "#|" indique ce qu'était la précédente chaîne non traduite de cette entrée et donne une indication au traducteur sur pourquoi cette entrée a été marquée comme source de confusions possibles.
 
En terme de format de fichier .po, le préfixe "#," signifie que l'entrée est marquée avec un drapeau (''fuzzy'') si bien que les programmes de traduction peuvent présenter à l'utilisateur traducteur une interface visuelle adaptée à cet élément. Dans le cas qui nous intéresse, le drapeau signifierait que la traduction dans son état actuel est douteuse et nécessite d'être révisée plus attentivement par le traducteur. Le préfixe "#|" indique ce qu'était la précédente chaîne non traduite de cette entrée et donne une indication au traducteur sur pourquoi cette entrée a été marquée comme source de confusions possibles.
  
==Traduction de Fiches, de modules de données et de cadres==
+
==Traduction de fiches, de modules de données et de cadres==
  
 
Quand l'option i18n est activée pour le projet/paquet, l'EDI produit automatiquement des fichiers .lrt pour chaque fiche. Il crée le fichier .lrt à l'enregistrement de l'unité. Par conséquent, si vous activez l'option pour la première fois, vous devez ouvrir chaque fiche une fois, la déplacer un petit peu à l'écran de sorte qu'elle soit modifiée, et l'enregistrer. Par exemple, si vous enregistrez une fiche ''unit1.pas'', l'EDI crée un fichier ''unit1.lrt''. A la compilation, l'EDI rassemble toutes les chaînes de tous les fichiers .lrt files et .rst dans un seul fichier .po (''projectname.po'' ou ''packagename.po'') dans le répertoire i18n.
 
Quand l'option i18n est activée pour le projet/paquet, l'EDI produit automatiquement des fichiers .lrt pour chaque fiche. Il crée le fichier .lrt à l'enregistrement de l'unité. Par conséquent, si vous activez l'option pour la première fois, vous devez ouvrir chaque fiche une fois, la déplacer un petit peu à l'écran de sorte qu'elle soit modifiée, et l'enregistrer. Par exemple, si vous enregistrez une fiche ''unit1.pas'', l'EDI crée un fichier ''unit1.lrt''. A la compilation, l'EDI rassemble toutes les chaînes de tous les fichiers .lrt files et .rst dans un seul fichier .po (''projectname.po'' ou ''packagename.po'') dans le répertoire i18n.
Line 130: Line 134:
 
Pour les fiches qui sont à traduire à l'exécution, vous devez affecter un traducteur à ''LRSTranslator'' (défini dans ''LResources'') dans la section ''initialization'' de l'une de vos unités.
 
Pour les fiches qui sont à traduire à l'exécution, vous devez affecter un traducteur à ''LRSTranslator'' (défini dans ''LResources'') dans la section ''initialization'' de l'une de vos unités.
  
<syntaxhighlight>...
+
<syntaxhighlight lang=pascal>...
 
uses
 
uses
 
   ...
 
   ...
Line 141: Line 145:
 
<s>Néanmoins, il n'y a pas de classe TPoTranslator (i.e une classe qui traduit à partir des fichiers .po) disponible dans la LCL. Voici une implémentation possible  (partiellement reprise de DefaultTranslator.pas dans la LCL):</s> Le code suivant n'est plus nécessaire si vous utilisez une version 0.9.29 ou ultérieure de Lazarus. Ajoutez simplement l'unité ''DefaultTranslator'' dans la clause ''uses''.
 
<s>Néanmoins, il n'y a pas de classe TPoTranslator (i.e une classe qui traduit à partir des fichiers .po) disponible dans la LCL. Voici une implémentation possible  (partiellement reprise de DefaultTranslator.pas dans la LCL):</s> Le code suivant n'est plus nécessaire si vous utilisez une version 0.9.29 ou ultérieure de Lazarus. Ajoutez simplement l'unité ''DefaultTranslator'' dans la clause ''uses''.
  
<syntaxhighlight>unit PoTranslator;
+
<syntaxhighlight lang=pascal>unit PoTranslator;
  
 
{$mode objfpc}{$H+}
 
{$mode objfpc}{$H+}
Line 201: Line 205:
 
Alternativement, vous pouvez transformer le fichier.po en .mo en utilisant ''msgfmt'' (n'est plus nécessaire non plus depuis la version 0.9.29) et utiliser simplement l'unité ''DefaultTranslator''
 
Alternativement, vous pouvez transformer le fichier.po en .mo en utilisant ''msgfmt'' (n'est plus nécessaire non plus depuis la version 0.9.29) et utiliser simplement l'unité ''DefaultTranslator''
  
<syntaxhighlight>...
+
<syntaxhighlight lang=pascal>...
 
uses
 
uses
 
   ...
 
   ...
Line 225: Line 229:
 
Pour chaque fichier .po, vous devez appeler ''TranslateUnitResourceStrings'' de l'unité ''translations'' de la LCL. Par exemple :
 
Pour chaque fichier .po, vous devez appeler ''TranslateUnitResourceStrings'' de l'unité ''translations'' de la LCL. Par exemple :
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
     {En premier lieu: ajoutez les unités "gettext" et "translations" à la clause uses}
 
     {En premier lieu: ajoutez les unités "gettext" et "translations" à la clause uses}
 
     procedure TForm1.FormCreate(Sender: TObject);1
 
     procedure TForm1.FormCreate(Sender: TObject);1
Line 249: Line 253:
  
 
Ceci va créer un fichier d'inclusion unit1.lrs commençant par
 
Ceci va créer un fichier d'inclusion unit1.lrs commençant par
<syntaxhighlight>LazarusResources.Add('unit1.de','PO',[
+
<syntaxhighlight lang=pascal>LazarusResources.Add('unit1.de','PO',[
 
   ...</syntaxhighlight>
 
   ...</syntaxhighlight>
  
 
*Ajoutez le code :
 
*Ajoutez le code :
<syntaxhighlight>uses LResources, Translations;
+
<syntaxhighlight lang=pascal>uses LResources, Translations;
  
 
resourcestring
 
resourcestring
Line 281: Line 285:
  
 
Pour ces versions anciennes, vous pouvez utiliser quelque chose comme cela :
 
Pour ces versions anciennes, vous pouvez utiliser quelque chose comme cela :
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
type
 
type
 
   TTranslateFromResourceResult = (trSuccess, trResourceNotFound, trTranslationError);
 
   TTranslateFromResourceResult = (trSuccess, trResourceNotFound, trTranslationError);
Line 312: Line 316:
 
Exemple d'utilisation :
 
Exemple d'utilisation :
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
initialization
 
initialization
 
   {$I lclstrconsts.de.lrs}
 
   {$I lclstrconsts.de.lrs}
Line 323: Line 327:
 
La fonction ci-dessous retourne une chaîne qui représente la langue de l'interface utilisateur. Elle tourne sous Linux, Mac OS X et Windows.
 
La fonction ci-dessous retourne une chaîne qui représente la langue de l'interface utilisateur. Elle tourne sous Linux, Mac OS X et Windows.
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
uses
 
uses
 
   Classes, SysUtils {ajoute dessunités supplémentaires nécessaires au code qui suit}
 
   Classes, SysUtils {ajoute dessunités supplémentaires nécessaires au code qui suit}
Line 337: Line 341:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
 
function GetOSLanguage: string;
 
function GetOSLanguage: string;
 
{méthode indépendante de la plate-forme pour lire la langue de l'interface utilisateur}
 
{méthode indépendante de la plate-forme pour lire la langue de l'interface utilisateur}
Line 385: Line 389:
 
===Traducteurs===
 
===Traducteurs===
 
*la traduction en allemand est maintenue par Joerg Braun.
 
*la traduction en allemand est maintenue par Joerg Braun.
*la traduction en finnois est maintenue par Seppo Suurtarla
+
*la traduction en finnois est maintenue par Seppo Suurtarla.
*la traduction en russe est maintenue par Maxim Ganetsky
+
*la traduction en russe est maintenue par Maxim Ganetsky.
 +
*la traduction en français est maintenue par Gilles Vasseur.
  
Quand vous voulez commencer une nouvelle traduction, demandez via le mailing si quelqu'un travaille déjà dessus.
+
Si vous voulez commencer une nouvelle traduction, demandez via le mailing si quelqu'un travaille déjà dessus.
  
 
Veuillez lire attentivement :[[Lazarus_Documentation/fr#Translating.2FInternationalization.2FLocalization|Traduction/Internationalisation/Localisation]]
 
Veuillez lire attentivement :[[Lazarus_Documentation/fr#Translating.2FInternationalization.2FLocalization|Traduction/Internationalisation/Localisation]]
Line 394: Line 399:
 
==Voir aussi==
 
==Voir aussi==
 
* [[IDE_Development#Translations.2C_i18n.2C_lrt_files.2C_po_files|IDE Development: Translations, i18n, lrt, po files]]
 
* [[IDE_Development#Translations.2C_i18n.2C_lrt_files.2C_po_files|IDE Development: Translations, i18n, lrt, po files]]
* [[Getting_translation_strings_right/fr|Obtenir des bonnes traductions des chaînes]]
+
* [[Getting_translation_strings_right/fr|Obtenir de bonnes traductions des chaînes]]
 
* [[Lazarus_Documentation/fr#Traductions|Traduction/Internationalisation/Localisation]]
 
* [[Lazarus_Documentation/fr#Traductions|Traduction/Internationalisation/Localisation]]
 
[[Category:Tutorials/fr]]
 
[[Category:Localization/fr]]
 

Latest revision as of 12:29, 1 March 2020

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 한국어 (ko) polski (pl) português (pt) русский (ru) 中文(中国大陆)‎ (zh_CN)

Vue d'ensemble

Cette page concerne la façon dont un programme peut utiliser différentes chaînes pour des langues aussi variées que l'anglais, le chinois, l'allemand, le finnois, l'italien, etc. Fondamentalement, cela fonctionne comme ceci :

* ajoutez une resourcestring pour chaque légende (caption) ;
* compilez pour obtenir les fichiers .rst et/ou .po (l'EDI peut le faire automatiquement) ;
* créez un fichier traduit .po pour chaque langue (il existe des outils visuels libres pour ce faire) ;
* utilisez les fonctions de l'unité translations de la LCL pour charger la bonne version de traduction au lancement du programme.

Date, heure et format de nombres

Sous Linux, BSD et Mac OS X existent différentes valeurs "locales" définissant des éléments comme le format de l'heure et de la date ou le séparateur des milliers. Afin d'initialiser la RTL, vous devez inclure l'unité clocale dans la section uses de votre programme (fichier .lpr).

Les chaînes de ressources

Par exemple :

resourcestring
    Caption1 = 'Du texte';
    HelloWorld1 = 'Bonjour, monde';

Elles sont comme des constantes de chaîne normales, ce qui veut dire que vous pouvez les assigner à n'importe quelle chaîne. Par exemple :

Label1.Caption := HelloWorld1;

Quand FPC les compile, il crée pour chaque unité un fichier unitname.rst contenant les données des chaînes de ressources (nom + contenu).

Les fichiers .po

Il existe de nombreux outils visuels libres pour éditer les fichiers .po, qui sont de simples fichiers de texte comme les fichiers .rst, mais avec quelques options supplémentaires, comme un en-tête contenant des champs indiquant le nom de l'auteur, le type d'encodage, la langue et la date. Chaque installation de FPC met à disposition l'outil rstconv (Windows : rstconv.exe). Cet outil peut être utilisé pour convertir un fichier .rst en un fichier .po. L'EDI peut le faire automatiquement. Exemples d'outils libres : kbabel, po-auto-translator, poedit, virtaal.

Virtaal a une mémoire de traduction contenant des paires source-cible pour les éléments que vous avez déjà traduits, et une fonction de suggestion de traduction qui montre les termes déjà traduits dans différents paquets de logiciels open source. Cette fonction peut vous permettre d'économiser beaucoup de travail et d'améliorer la cohérence des traductions.


Exemple utilisant directement rstconv :

 rstconv -i unit1.rst -o unit1.po

La traduction

Pour chaque langue, le fichier .po doit être copié et traduit. L'unité translation de la LCL utilise les codes habituels des langues(en=anglais, de=allemand, it=italien, ...) pour ses recherches. Par exemple, la traduction française de unit1.po serait unit1.fr.po. Pour atteindre ce résultat, le fichier unit1.po sera copié en unit1.fr.po, unit1.it.po, et toute autre langue que vous souhaitez supporter. Les traducteurs pourront alors éditer leur fichier .po spécifique.

Light bulb  Remarque: Pour les Brésiliens/Portugais: L'EDI de Lazarus et la LCL possèdent uniquement les traductions du Portugais Brésilien et ces fichiers ont pour extension 'pt_BR.po' (et non 'pt.po').

Les options de l'EDI pour la mise à jour des fichiers .po

  • L'unité contenant les ressources de chaînes doit être ajoutée au paquet ou au projet.
  • Vous devez définir un chemin pour les .po, ce qui signifie un dossier qui leur est propre. Par exemple : créez un sous-répertoire language dans le répertoire du paquet/projet. Pour les projets, allez dans Projet > Options du projet. Pour les paquets, allez dans Options > Intégration à l'EDI.

Quand ces options sont activées, l'EDI génère ou met à jour le fichier .po de base en utilisant les informations contenues dans les fichiers .rst et .lrt (l'outil rstconv n'est alors pas nécessaire). Le processus de mise à jour commence en collectant toutes les entrées existantes trouvées dans le fichier .po de base et dans les fichiers .rst et .lrt pour continuer en appliquant les caractéristiques qu'il trouve ensuite réactualisées dans n'importe quel fichier .xx.po de traduction.

Suppression des entrées obsolètes

Les entrées du fichier .po de base qui ne sont pas trouvées dans les fichiers .rst et .lrt sont supprimées. De même, toutes les entrées trouvées dans les fichiers .xx.po non trouvées dans le fichier .po de base sont également enlevées. De cette façon, les fichiers .po ne sont pas encombrés avec des entrées obsolètes et les traducteurs n'ont pas à traduire les entrées qui ne sont pas utilisées.

Entrées en double

Les entrées en double apparaissent quand pour quelque raison le même texte est utilisé pour différentes chaînes de ressources. Un exemple au hasard : dans le fichier lazarus/ide/lazarusidestrconst.pas pour la chaîne 'Gutter':

  dlfMouseSimpleGutterSect = 'Gutter';
  dlgMouseOptNodeGutter = 'Gutter';
  dlgGutter = 'Gutter';
  dlgAddHiAttrGroupGutter = 'Gutter';

Un fichier .rst converti pour ces chaînes de ressources serait similaire à ceci dans un fichier .po:

#: lazarusidestrconsts.dlfmousesimpleguttersect
msgid "Gutter"
msgstr ""
#: lazarusidestrconsts.dlgaddhiattrgroupgutter
msgid "Gutter"
msgstr ""
etc.

Les lignes commençant avec "#: " sont considérées comme des commentaires et les outils utilisés pour traduire ces entrées voient les lignes répétées msgid "Gutter" comme des entrées dupliquées produisant des erreurs ou des avertissements au chargement ou à la sauvegarde. Les entrées dupliquées sont considérées comme une éventualité normale dans un fichier .po et elles ont besoin d'avoir un certain contexte qui leur est attaché. Le mot clé msgctxt est utilisé pour ajouter un contexte aux entrées dupliquées et l'outil de mise à jour automatique utilise l'ID d'entrée (le texte à côté du préfixe "#: ") comme contexte. Pour l'exemple précédent serait produit quelque chose comme ceci :

#: lazarusidestrconsts.dlfmousesimpleguttersect
msgctxt "lazarusidestrconsts.dlfmousesimpleguttersect"
msgid "Gutter"
msgstr ""
#: lazarusidestrconsts.dlgaddhiattrgroupgutter
msgctxt "lazarusidestrconsts.dlgaddhiattrgroupgutter"
msgid "Gutter"
msgstr ""
etc.

Pour les fichiers .xx.po traduits, l'outil automatique effectue une vérification supplémentaire : si l'entrée dupliquée était déjà traduite, la nouvelle entrée récupère l'ancienne traduction, apparaissant alors comme traduite automatiquement.

Cette détection automatique des doublons n'est pas encore parfaite. La détection des doublons est effectuée quand des éléments sont ajoutés à la liste et il peut arriver que certaines entrées non traduites soient lues d'abord. Aussi se peut-il que plusieurs passes soient nécessaires pour récupérer tous les doublons traduits automatiquement par l'outil.

Entrées à l'origine de confusions possibles

Les changements dans les chaînes de ressources affectent les traductions. Par exemple, si une chaîne de ressource a été initialement définie comme ceci :

dlgEdColor = 'Syntax highlight';

cela produirait une entrée .po similaire à ceci :

#: lazarusidestrconsts.dlgedcolor
msgid "Syntax highlight"
msgstr ""

qui, en cas de traduction en espagnol (cet exemple a été tiré de l'historique de Lazarus), peut résulter en :

#: lazarusidestrconsts.dlgedcolor
msgid "Syntax highlight"
msgstr "Color"

Supposons que, plus tard, la chaîne de ressources a été changée en :

  dlgEdColor = 'Colors';

l'entrée .po résultante pourrait devenir :

#: lazarusidestrconsts.dlgedcolor
msgid "Colors"
msgstr ""

Notez qu'alors que l'ID demeure le même (lazarusidestrconsts.dlgedcolor), la chaîne est passée de 'Syntax highlight' à 'Colors'. Comme la chaîne a déjà été traduite, l'ancienne traduction peut ne pas correspondre au nouveau sens recherché. Pour la nouvelle chaîne, il est probable que 'Colores' serait une meilleure traduction.

L'outil de mise à jour automatique remarque cette situation et produit une entrée comme :

#: lazarusidestrconsts.dlgedcolor
#, fuzzy
#| msgid "Syntax highlight"
msgctxt "lazarusidestrconsts.dlgedcolor"
msgid "Colors"
msgstr "Color"

En terme de format de fichier .po, le préfixe "#," signifie que l'entrée est marquée avec un drapeau (fuzzy) si bien que les programmes de traduction peuvent présenter à l'utilisateur traducteur une interface visuelle adaptée à cet élément. Dans le cas qui nous intéresse, le drapeau signifierait que la traduction dans son état actuel est douteuse et nécessite d'être révisée plus attentivement par le traducteur. Le préfixe "#|" indique ce qu'était la précédente chaîne non traduite de cette entrée et donne une indication au traducteur sur pourquoi cette entrée a été marquée comme source de confusions possibles.

Traduction de fiches, de modules de données et de cadres

Quand l'option i18n est activée pour le projet/paquet, l'EDI produit automatiquement des fichiers .lrt pour chaque fiche. Il crée le fichier .lrt à l'enregistrement de l'unité. Par conséquent, si vous activez l'option pour la première fois, vous devez ouvrir chaque fiche une fois, la déplacer un petit peu à l'écran de sorte qu'elle soit modifiée, et l'enregistrer. Par exemple, si vous enregistrez une fiche unit1.pas, l'EDI crée un fichier unit1.lrt. A la compilation, l'EDI rassemble toutes les chaînes de tous les fichiers .lrt files et .rst dans un seul fichier .po (projectname.po ou packagename.po) dans le répertoire i18n.

Pour les fiches qui sont à traduire à l'exécution, vous devez affecter un traducteur à LRSTranslator (défini dans LResources) dans la section initialization de l'une de vos unités.

...
uses
  ...
  LResources;
...
...
initialization
  LRSTranslator := TPoTranslator.Create('/path/to/the/po/file');

Néanmoins, il n'y a pas de classe TPoTranslator (i.e une classe qui traduit à partir des fichiers .po) disponible dans la LCL. Voici une implémentation possible (partiellement reprise de DefaultTranslator.pas dans la LCL): Le code suivant n'est plus nécessaire si vous utilisez une version 0.9.29 ou ultérieure de Lazarus. Ajoutez simplement l'unité DefaultTranslator dans la clause uses.

unit PoTranslator;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, typinfo, Translations;

type

 { TPoTranslator }

 TPoTranslator=class(TAbstractTranslator)
 private
  FPOFile:TPOFile;
 public
  constructor Create(POFileName:string);
  destructor Destroy;override;
  procedure TranslateStringProperty(Sender:TObject; 
    const Instance: TPersistent; PropInfo: PPropInfo; var Content:string);override;
 end;

implementation

{ TPoTranslator }

constructor TPoTranslator.Create(POFileName: string);
begin
  inherited Create;
  FPOFile:=TPOFile.Create(POFileName);
end;

destructor TPoTranslator.Destroy;
begin
  FPOFile.Free;
  inherited Destroy;
end;

procedure TPoTranslator.TranslateStringProperty(Sender: TObject;
  const Instance: TPersistent; PropInfo: PPropInfo; var Content: string);
var
  s: String;
begin
  if not Assigned(FPOFile) then exit;
  if not Assigned(PropInfo) then exit;
{DO we really need this?}
  if Instance is TComponent then
   if csDesigning in (Instance as TComponent).ComponentState then exit;
{End DO :)}
  if (AnsiUpperCase(PropInfo^.PropType^.Name)<>'TTRANSLATESTRING') then exit;
  s:=FPOFile.Translate(Content, Content);
  if s<>'' then Content:=s;
end;

end.


Alternativement, vous pouvez transformer le fichier.po en .mo en utilisant msgfmt (n'est plus nécessaire non plus depuis la version 0.9.29) et utiliser simplement l'unité DefaultTranslator

...
uses
   ...
   DefaultTranslator;

qui recherchera automatiquement dans plusieurs emplacements standards un fichier .po (plus haute priorité) ou un fichier .mo (l'inconvénient est que vous devrez garder ensemble les fichiers .mo pour l'unité DefaultTranslator et les fichiers .po pour l'unité TranslateUnitResourceStrings.. Si vous utilisez l'unité DefaultTranslator, elle va essayer de détecter automatiquement la langue à partir de la variable d'environnement LANG (surchargeable en utilisant l'option --lang en ligne de commande), puis regardera dans les emplacements suivants pour la traduction (LANG représente la langue désirée ; l'extension peut être po ou mo) :

  • <Répertoire de l'application>/<LANG>/<Nom de fichier de l'application>.<ext>
  • <Répertoire de l'application>/languages/<LANG>/<Nom de fichier de l'application>.<ext>
  • <Répertoire de l'application>/locale/<LANG>/<Nom de fichier de l'application>.<ext>
  • <Répertoire de l'application>/locale/LC_MESSAGES/<LANG/><Nom de fichier de l'application>.<ext>

Avec les systèmes du genre Unix, l'emplacement peut aussi ressembler à

  • /usr/share/locale/<LANG>/LC_MESSAGES/<Nom de fichier de l'application>.<ext>

L'unité pourra aussi utiliser l'intitulé court de la langue (par exemple, s'il s'agit de "es_ES" ou "es_ES.UTF-8" et que le fichier n'existe pas, elle essayera aussi "es").

Traduction au début du programme

Pour chaque fichier .po, vous devez appeler TranslateUnitResourceStrings de l'unité translations de la LCL. Par exemple :

    {En premier lieu: ajoutez les unités "gettext" et "translations" à la clause uses}
    procedure TForm1.FormCreate(Sender: TObject);1
    var
      PODirectory, Lang, FallbackLang: String;
    begin
      PODirectory := '/path/to/lazarus/lcl/languages/';
      GetLanguageIDs(Lang, FallbackLang); // dans l'unité gettext
      TranslateUnitResourceStrings('LCLStrConsts', PODirectory + 'lclstrconsts.%s.po', Lang, FallbackLang);
      MessageDlg('Titre', 'Texte', mtInformation, [mbOk, mbCancel, mbYes], 0);
    end;

Compilation des fichiers po dans l'exécutable

Si vous ne voulez pas installer les fichiers .po, mais placer tous les fichiers dans l'exécutable, utilisez ce qui suit :

  • Créez une nouvelle unité (pas une fiche !).
  • Convertissez le(s) fichier(s) .po en fichiers .lrs en utilisant le programme tools/lazres:
./lazres unit1.lrs unit1.de.po

Ceci va créer un fichier d'inclusion unit1.lrs commençant par

LazarusResources.Add('unit1.de','PO',[
  ...
  • Ajoutez le code :
uses LResources, Translations;

resourcestring
  MyCaption = 'Caption';

function TranslateUnitResourceStrings: boolean;
var
  r: TLResource;
  POFile: TPOFile;
begin
  r:=LazarusResources.Find('unit1.de','PO');
  POFile:=TPOFile.Create(False);  //Si Full=True vous pouvez craindre un crash (problème #0026021)
  try
    POFile.ReadPOText(r.Value);
    Result:=Translations.TranslateUnitResourceStrings('unit1',POFile);
  finally
    POFile.Free;
  end;
end;

initialization
  {$I unit1.lrs}
  • Appelez TranslateUnitResourceStrings au début du programme. Vous pouvez aussi choisir de le faire dans la section initialization.

Malheureusement, ce code ne compilera pas avec Lazarus 1.2.2 et antérieurs.

Pour ces versions anciennes, vous pouvez utiliser quelque chose comme cela :

type
  TTranslateFromResourceResult = (trSuccess, trResourceNotFound, trTranslationError);

function TranslateFromResource(AResourceName, ALanguage : String): TTranslateFromResourceResult;
var
  LRes : TLResource;
  POFile : TPOFile = nil;
  SStream : TStringStream = nil;
begin
  Result := trResourceNotFound;
  LRes := LazarusResources.Find(AResourceName + '.' + ALanguage, 'PO');
  if LRes <> nil then
  try
    SStream := TStringStream.Create(LRes.Value);
    POFile := TPoFile.Create(SStream, False);
    try
      if TranslateUnitResourceStrings(AResourceName, POFile) then Result := trSuccess
      else Result := trTranslationError;
    except
      Result := trTranslationError;
    end;
  finally
    if Assigned(SStream) then SStream.Free;
    if Assigned(POFile) then POFile.Free;
  end;
end;

Exemple d'utilisation :

initialization
  {$I lclstrconsts.de.lrs}
  TranslateFromResource('lclstrconsts', 'de');
end.

Méthode indépendante de la plate-forme pour déterminer la langue système

La fonction ci-dessous retourne une chaîne qui représente la langue de l'interface utilisateur. Elle tourne sous Linux, Mac OS X et Windows.

uses
  Classes, SysUtils {ajoute dessunités supplémentaires nécessaires au code qui suit}
  {$IFDEF win32}
  , Windows
  {$ELSE}
  , Unix
    {$IFDEF LCLCarbon}
  , MacOSAll
    {$ENDIF}
  {$ENDIF}
  ;
function GetOSLanguage: string;
{méthode indépendante de la plate-forme pour lire la langue de l'interface utilisateur}
var
  l, fbl: string;
  {$IFDEF LCLCarbon}
  theLocaleRef: CFLocaleRef;
  locale: CFStringRef;
  buffer: StringPtr;
  bufferSize: CFIndex;
  encoding: CFStringEncoding;
  success: boolean;
  {$ENDIF}
begin
  {$IFDEF LCLCarbon}
  theLocaleRef := CFLocaleCopyCurrent;
  locale := CFLocaleGetIdentifier(theLocaleRef);
  encoding := 0;
  bufferSize := 256;
  buffer := new(StringPtr);
  success := CFStringGetPascalString(locale, buffer, bufferSize, encoding);
  if success then
    l := string(buffer^)
  else
    l := '';
  fbl := Copy(l, 1, 2);
  dispose(buffer);
  {$ELSE}
  {$IFDEF LINUX}
  fbl := Copy(GetEnvironmentVariable('LC_CTYPE'), 1, 2);
    {$ELSE}
  GetLanguageIDs(l, fbl);
    {$ENDIF}
  {$ENDIF}
  Result := fbl;
end;

Traduction de l'EDI

Fichiers

Les fichiers .po sont dans le répertoire source de Lazarus :

  • lazarus/languages => chaînes pour l'EDI
  • lazarus/lcl/languages/ => chaînes pour la LCL
  • lazarus/components/ideintf/languages/ => chaînes pour l'interface de l'EDI

Traducteurs

  • la traduction en allemand est maintenue par Joerg Braun.
  • la traduction en finnois est maintenue par Seppo Suurtarla.
  • la traduction en russe est maintenue par Maxim Ganetsky.
  • la traduction en français est maintenue par Gilles Vasseur.

Si vous voulez commencer une nouvelle traduction, demandez via le mailing si quelqu'un travaille déjà dessus.

Veuillez lire attentivement :Traduction/Internationalisation/Localisation

Voir aussi