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

From Free Pascal wiki
Jump to navigationJump to search
Line 20: Line 20:
 
<syntaxhighlight>Label1.Caption := HelloWorld1;</syntaxhighlight>
 
<syntaxhighlight>Label1.Caption := HelloWorld1;</syntaxhighlight>
  
Quand FPC les compile, il crée pour chaque unité un fichier '''unitname.rst''' contenant les données resourcestring (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).
  
 
==Fichiers .po==
 
==Fichiers .po==

Revision as of 18:43, 14 March 2015

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 différentes langues comme l'anglais, le chinois, l'allemand, le finois, l'italien, etc. Fondamentalement, cela fonctionne comme ceci : ajoutez une resourcestring pour chaque légende('caption'), compilez pour obtenir le(s) fichier(s) .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) et utilisez les fonctions de l'unité translations de la LCL pour charger la bonne version au lancement du programme.

Date, heure et format de nombres

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

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 leur 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).

Fichiers .po

Il existe de nombreux outils graphiques 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 améliorer la cohérence des traductions.


Exemple utilisant directement rstconv :

 rstconv -i unit1.rst -o unit1.po

Traduction

Pour chaque langue, le fichier .po doit être copié et traduit. L'unité translation de la LCL utilise les codes courants des langues(en=anglais, de=allemand, it=italien, ...) pour ses recherches. Par exemple la traduction française de unit1.po serait unit1.fr.po. Cela signifie que le fichier unit1.po sera copié en unit1.de.po, unit1.it.po, et toute autre langue que vous souhaitez supporter. Les traducteurs pourront alors éditer leurs fichiers .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').

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

  • L'unité contenant les ressources de chaînes doit être ajoutée au package ou au projet.
  • Vous devez définir un chemin pour les .po, ce qui signifie un dossier séparé. Par exemple : créez un sous-dossier language dans le dossier 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 les fichiers .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 appliquer alors les caractéristiques suivantes qu'il trouve et réactualiser tout fichier .xx.po traduit.

Retrait 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 enlevées. Par conséquent, 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înee '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 et produisent 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 additionnelle : si l'entrée dupliquée était déjà traduite, la nouvelle entrée prend 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 faite quand des éléments sont ajoutés à la liste et il peut arriver que certaines entrées non traduites soient lues d'abord. Alors, il se peut que plusieurs passes soient nécessaires pour obtenir automatiquement tous les doublons traduits automatiquement par l'outil.

Entrées floues

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

dlgEdColor = 'Syntax highlight';

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

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

qui, si traduit 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ésultant pourrait devenir

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

Notez qu'alors que l'ID demeure le même (lazarusidestrconsts.dlgedcolor), la chaîne a changé de 'Syntax highlight' à 'Colors'. Alors que la chaîne a déjà été traduite, l'ancienne traduction peut ne pas correspondre au nouveau sens. Toutefois, pour la nouvelle chaîne ils est probable que 'Colores' pourrait être 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 "#," signigie que l'entrée a un flag (fuzzy) et les programme sde tradution peuvent présenter un GUI à l'utilisateur traducteur pour cet élément. Dans ce cas, le flag signifierait que la traduction dans sont état courant est douteux et nécessite d'être révisé plus attentivement par le traducteur. Le préfixe "#|" indique ce qu"tait la précédente chapine non traduite de cette entrée et donne une indication au traducteur pourquoi cette entrée a été marquée comme fuzzy.

Traduction de Fiches, Modules de données et Cadres

Quand l'option i18n est activée pour le projet / paquet, alors l'EDI produit automatiquement des fichiers .lrt pour chaque fiche. Il crée le fichier .lrt à l'enregistrement de l'unité. Donc, si vous activez l'option pour la première fois, vous devez ouvrir chaque fiche une fois, la changer un petit peu, de sorte qu'il soit modifié, et enregistrez la fiche. Par exemple, si vous sauvez une fiche unit1.pas l'EDI crée un fichier unit1.lrt. Et à 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 depuis la version 0.9.29 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 plius nécessaire depuis la version 0.9.29) et utiliser simplement l'unité DefaultTranslator

...
uses
   ...
   DefaultTranslator;

qui inspectera automatiquement dans plusieurs emplacements standards pour 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 DefaultTranslator, il va essayer automatiquement de détecter la langue à partir de la variable d'environnement LANG (surchargeable en utilisant l'option --lang en ligne de commande), puis regardera dans ces emplacements pour la traduction (LANG veut dire 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>

sous les systèmes à la Unix, cela ressemble aussi à

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

aussi bien en utilisant la petite partie de la langue (par exemple s'il s'agit de "es_ES" ou "es_ES.UTF-8" et qu'il n'existe pas il sera aussi essayé "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('Title', 'Text', mtInformation, [mbOk, mbCancel, mbYes], 0);
    end;

Compilation des fichiers po dans l'exécutable

Si vous ne voulez pas installer les fichiers .po, mais mettre 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 file(s) en .lrs utilisant 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 alors vous pouvez avoir 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 le faire dans la section initialization si vous voulez.

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

Pour ces versions, 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 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

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

SVP, lire attentivement:Traduction/Internationalisation/Localisation

Voir aussi