Section courante

A propos

Section administrative du site

Chaînes de caractères de ressources

Les chaînes de ressources existent principalement pour faciliter l'internationalisation des applications, en introduisant une construction de langage fournissant une manière uniforme de gérer les chaînes de caractères constantes.

La plupart des applications communiquent avec l'utilisateur via certains messages sur l'écran graphique ou la console. L'entreposage de ces messages dans des constantes spéciales permet de les entreposer de manière uniforme dans des fichiers séparés, pouvant être utilisés pour la traduction. Une interface de programmeur existe pour manipuler les valeurs réelles des chaînes de caractères constantes au moment de l'exécution, et un outil utilitaire est fourni avec le compilateur Free Pascal pour convertir les fichiers de chaînes de ressources dans le format souhaité par le programmeur. Ces deux choses sont abordées dans les sections suivantes.

Le fichier de chaîne de caractères de ressources

Lorsqu'une unité est compilée et contient une section resourcestring, le compilateur fait 2 choses :

Cette approche présente 2 avantages : tout d'abord, la valeur de la chaîne de caractères est toujours présente dans le programme. Si le programmeur ne se soucie pas de traduire les chaînes de caractères, les valeurs par défaut sont toujours présentes dans le binaire. Cela évite également de devoir fournir un fichier contenant les chaînes de caractères. Deuxièmement, avoir toutes les chaînes ensemble dans un fichier généré par le compilateur garantit que toutes les chaînes sont ensemble (vous pouvez avoir plusieurs sections de chaînes de caractères de ressources dans 1 unité ou programme) et avoir ce fichier dans un format fixe permet au programmeur de choisir sa méthode d'internationalisation.

Pour chaque unité compilée et contenant une section resourcestring, le compilateur génère un fichier portant le nom de l'unité et une extension .rsj. Le format de ce fichier est un fichier JSON (en page de code UTF8), structuré comme suit (formatage ajouté pour plus de clarté) :

  1. { "version":1,
  2.  "strings":[
  3.   {"hash":53831826,
  4.    "name":"custapp.serrinvalidoption",
  5.    "sourcebytes":[79,112,116,105,111,110,32,105,110,118,97,108,105,100,101,32,195,160,32,108,97,32,112,111,115,105,116,105,111,110,32,37,100,58,32,34,37,115,34],
  6.    "value":"Option invalide à la position %d: \"%s\""
  7.   }
  8.  ]
  9. }

L'objet JSON global contient 2 éléments : un numéro de version et un tableau appelé strings. Le tableau contient un élément (un objet JSON) pour chaque chaîne de caractères de ressource de l'unité. Cet objet JSON contient les propriétés suivantes :

Si l'unité ne contient aucune section de chaîne de caractères de ressources, aucun fichier n'est généré. Par exemple, l'unité suivante :

  1. Unit RSDemo;
  2.  
  3. {$mode delphi}
  4. {$H+}
  5.  
  6. INTERFACE
  7.  
  8. ResourceString
  9.  First = 'Premier';
  10.  Second = 'Une deuxième chaîne de caractères très longue devant couvrir plus d''une ligne';
  11.  
  12. IMPLEMENTATION
  13.  
  14. END.

Cela donnera le fichier de chaîne de caractères de ressources suivant :

  1. {
  2.  "version":1,
  3.  "strings":[
  4.   {"hash":5048740,
  5.    "name":"rsdemo.first",
  6.    "sourcebytes":[80,114,101,109,105,101,114],
  7.    "value":"Premier"
  8.   },
  9.   {"hash":171989989,
  10.    "name":"rsdemo.second",
  11.    "sourcebytes":[85,110,101,32,100,101,117,120,105,195,168,109,101,32,99,104,97,195,174,110,101,32,100,101,32,99,97,
  12.                   114,97,99,116,195,168,114,101,115,32,116,114,195,168,115,32,108,111,110,103,117,101,32,100,101,118,
  13.                   97,110,116,32,99,111,117,118,114,105,114,32,112,108,117,115,32,100,39,117,110,101,32,108,105,103,110,101],
  14.     "value":"'Une deuxième chaîne de caractères très longue devant couvrir plus d'une ligne"
  15.   }
  16.  ]
  17. }

La valeur de hachage est calculée avec la fonction Hash. Il est présent dans l'unité objpas. La valeur est la même que celle utilisée par le mécanisme gettext de GNU. Il n'est en aucun cas unique et ne peut servir qu'à accélérer les recherches.

L'utilitaire rstconv fourni avec le compilateur Free Pascal permet la manipulation de ces fichiers de chaînes de ressources. Pour le moment, il ne peut être utilisé que pour créer un fichier .po pouvant être transmis au programme msgfmt de GNU. Si quelqu'un souhaite avoir un autre format (les fichiers de ressources Win32 viennent à l'esprit), on peut améliorer le programme rstconv afin qu'il puisse également générer d'autres types de fichiers. gettext de GNU a été choisi car il est disponible sur toutes les plateformes et est déjà largement utilisé dans la communauté Unix et du logiciel libre. Puisque l'équipe Free Pascal ne souhaite pas restreindre l'utilisation des chaînes de ressources, le format .rst a été choisi pour fournir une méthode neutre, non limitée à aucun outil.

Si vous utilisez des chaînes de ressources dans vos unités et que vous souhaitez que les utilisateurs puissent traduire les chaînes de caractères, vous devez fournir le fichier de chaînes de ressources. Actuellement, il n'existe aucun moyen de les extraire du fichier unité, bien que cela soit en principe possible. Cela n'est pas obligatoire, le programme peut être compilé sans cela, mais la traduction des chaînes de caractères n'est alors pas possible.

Mise à jour des tables de chaînes de caractères

Avoir compilé un programme avec des chaînes de caractères de ressources ne suffit pas pour internationaliser votre programme. Au moment de l'exécution, le programme doit initialiser les tables de chaînes avec les valeurs correctes pour la langue sélectionnée par l'utilisateur. Par défaut, aucune initialisation de ce type n'est effectuée. Toutes les chaînes sont initialisées avec leurs valeurs déclarées.

L'unité objpas fournit le mécanisme permettant d'initialiser correctement les tables de chaînes de caractères. Il n'est pas nécessaire d'inclure cette unité dans une clause Uses, puisqu'elle est automatiquement chargée lorsqu'un programme ou une unité est compilé en mode Delphi ou objfpc. Étant donné que l'un de ces modes est requis pour utiliser les chaînes de ressources, l'unité est de toute façon toujours chargée en cas de besoin.

Les chaînes de ressources sont entreposées dans des tables, une par unité et une pour le programme, s'il contient également une section de chaîne de caractères de ressources. Chaque chaîne de ressources est stockée avec son nom, sa valeur de hachage, sa valeur par défaut et la valeur actuelle, le tout sous forme d'AnsiStrings.

L'unité objpas propose 2 méthodes pour définir la valeur actuelle des chaînes de caractères :

  1. Type
  2.  TResourceIterator=Function(Name,Value:AnsiString;Hash:LongInt;Arg:Pointer):AnsiString;
  3.  
  4. Procedure SetResourceStrings(SetFunction:TResourceIterator;Arg:Pointer);
  5. Procedure SetUnitResourceStrings(UnitName:String;SetFunction:TResourceIterator;Arg:Pointer);

Voici une brève explication de ce que fait chaque fonction :

Fonction Description
SetResourceStrings Donner à cette fonction un rappel entraînera l'appel du rappel pour toutes les chaînes de ressources, une par une. Au retour du rappel, la valeur de la chaîne de caractères de ressource sera définie sur la valeur de retour du rappel. Le pointeur arg est passé au rappel (cela peut être utilisé pour transmettre par exemple une instance d'objet).
SetUnitResourceStrings Son comportement est identique à celui de SetResourceStrings, mais appelle uniquement le rappel pour les chaînes de caractères de ressources de l'unité UnitName.
Hash Peut être utilisé pour calculer la valeur de hachage d'une chaîne de caractères. La valeur de hachage entreposée dans les tables est le résultat de cette fonction, appliquée sur la valeur par défaut. Cette valeur est calculée au moment de la compilation par le compilateur : avoir la valeur disponible peut accélérer les opérations de traduction.
ResetResourceTables Réinitialisera toutes les chaînes de ressources à leurs valeurs par défaut. Il est appelé par le code d'initialisation de l'unité objpas.
FinalizeResourceTables Supprimera toutes les valeurs de chaîne de caractères de ressources (c'est-à-dire les rendra vides).

gettext de GNU

L'unité gettext fournit un moyen d'internationaliser une application avec les utilitaires GNU gettext. Cette unité est fourni avec la bibliothèque de composants gratuits FCL (Free Component Library). Pour une application donnée, les étapes suivantes doivent être suivies :

  1. Collectez tous les fichiers de chaînes de caractères de ressources et concaténez-les ensemble.
  2. Appelez le programme rstconv avec le fichier résultant de l'étape 1, ce qui donne un seul fichier .po contenant toutes les chaînes de ressources du programme.
  3. Traduisez le fichier .po de l'étape 2 dans toutes les langues requises.
  4. Exécutez le programme de formatage msgfmt sur tous les fichiers .po, ce qui génère un ensemble de fichiers .mo pouvant être distribués avec votre application.
  5. Appelez la méthode TranslateResourceStrings de l'unité gettext, en lui donnant un modèle pour l'emplacement des fichiers .mo, par exemple, comme dans :

    1. TranslateResourcestrings('intl/restest.%s.mo'); 

    le spécificateur %s sera remplacé par le contenu de la variable d'environnement LANG. Cet appel devrait avoir lieu au démarrage du programme.

Un exemple de programme existe dans les sources FCL-base, dans le répertoire fcl-base/tests.

Mise en garde

En principe, il est possible de traduire toutes les chaînes de caractères de ressources à tout moment dans un programme en cours d'exécution. Cependant, cette modification n'est pas communiquée aux autres chaînes de caractères; son changement n'est remarqué que lorsqu'une chaîne de caractères constante est utilisée.

Prenons l'exemple suivant :

  1. ResourceString
  2.  help = 'Avec l''aide d''un programmeur.';
  3. Var
  4.  A:AnsiString;
  5. Begin
  6.  { Beaucoup de code }
  7.  A:=Help;
  8.  { Encore du code }
  9.  TranslateStrings;
  10.  { Plus de code }

Après l'appel à TranslateStrings, la valeur de A restera inchangée. Cela signifie que l'affectation A:=Help doit être exécutée à nouveau pour que la modification devienne visible. Ceci est important, en particulier pour les programmes GUI ayant par exemple un menu. Pour que le changement des chaînes de caractères de ressources soit visible, les nouvelles valeurs doivent être rechargées par code programme dans les menus.

Code source

Voici des exemples de code source d'utilitaires pour manipuler les RSJ de Free Pascal :

Lien Langage de programmation Description Projet
PAS2RSJ.PAS Free Pascal, Turbo Pascal Cette commande permet de convertir des constantes Pascal en fichier de ressource RSJ. DEV-COOLS


Dernière mise à jour : Dimanche, le 27 août 2023