Obligement - L'Amiga au maximum

Lundi 22 mai 2017 - 17:26  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Soutien

N'hésitez pas à soutenir le projet Obligement



Contact

David Brunet

Courriel

 


Programmation : Assembleur - la locale.library
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - mai 1995)


Depuis maintenant quelques années, la locale.library fait partie de notre usage quotidien du Workbench. Elle permet de franciser non seulement le Workbench, mais aussi tout programme sachant tirer parti de ses possibilités par le biais d'un simple fichier rajouté par l'utilisateur dans le bon tiroir.

Présentation

Avant le Kickstart 2.1, un programme voulant fonctionner dans plusieurs langues devait se débrouiller tout seul. Certains le faisaient assez bien en présentant, de manière très similaire au comportement de la locale.library, des fichiers séparés pour chaque langue, de façon à ce qu'un Français n'occupe pas inutilement son disque dur avec du Norvégien ou du Polonais. D'autres, en revanche, ne s'embarrassaient pas de ce genre de considérations et codaient brutalement les différentes langues dans leurs exécutables. C'est pour normaliser et faciliter, tant du point de vue programmeur qu'utilisateur, la polyglottie des applications que Commodore a introduit la locale.library.

Concrètement, l'utilisateur peut ajouter une langue à une application particulière, à condition qu'il dispose du fichier catalogue adéquat, en plaçant celui-ci dans le répertoire du langage considéré, lui-même se trouvant soit dans le répertoire système Locale:Catalogs/, soit dans le répertoire "Catalogs" du répertoire de l'application (auquel on accède par la pseudo-assignation PROGDIR:). Ce système permet une grande souplesse pour l'utilisateur, qui peut configurer ses choix à l'aide du programme de préférences de la locale.library.

Du point de vue du programmeur, cela oblige évidemment à quelques adaptations, mais si un programme est conçu dès le début dans cette optique, cela ne pose aucun problème. De plus, le choix de l'utilisateur est absolument transparent pour le programme. Enfin, la locale.library propose beaucoup d'autres fonctions permettant à un programme de s'adapter aux normes en vigueur dans le pays où il tourne, comme la gestion des différents formats numériques, de dates, une fonction de formatage dans le style RawDoFmt() mais permettant de changer l'ordre des arguments, une gigantesque structure contenant des tas d'informations utiles.

Contraintes

Chaque chaîne de caractères susceptible de varier selon les langues doit être dans un fichier nommé Catalog Description File (son extension est en général .cd) qui sera utilisé par le programme CatComp pour générer des fichiers complémentaires, comme un fichier include pour le C ou l'assembleur, un fichier objet pour le lien (linkage), un fichier de traduction de catalogue (ceux-là se terminent par .ct) qui sera utilisé pour indiquer les chaînes de caractères correspondant à une autre langue, et, bien entendu, les fichiers catalogues.

J'ai parlé de remplir les fichiers .cd, mais avec quoi ? Avec les chaînes de caractères dans la langue par défaut, il est préférable que ce soit l'anglais. Chaque chaîne de caractères se voit attribuer un identificateur qui est un entier sur 32 bits. Ces identificateurs sont toujours représentés par une étiquette commençant par MSG_, en majuscules. Choisissez-la suffisamment explicite pour que vos traducteurs éventuels la comprennent, et toujours en anglais.

Toutes les références à des messages se feront obligatoirement par cet identificateur et par l'intermédiaire des fonctions de la locale.library. Pour compiler correctement vos catalogues et générer tous les fichiers annexes, vous aurez de toute façon besoin du programme CatComp qui se trouve sur le paquetage développeur (disponible chez Someware par exemple). Reportez-vous à sa documentation pour sa syntaxe exacte.

Concrètement

L'ouverture de la locale.library se fait normalement par OpenLibrary(). Réclamez toujours la version 38. Une fois ceci fait (n'oubliez pas de tester le résultat !). Vous pouvez ouvrir la locale courante (c'est-à-dire une bibliothèque partagée, un peu spéciale dont la structure exacte n'est connue que de la locale.library) grâce à la fonction OpenLocale().

Celle-ci admet en A0 un pointeur sur le nom de la locale à ouvrir, 0 signifiant la locale actuelle, ce qui doit toujours être le cas, sauf effet spécial désiré. En retour, D0 pointe sur une structure Locale, ou vaut 0 en cas d'erreur (ce ne sera jamais le cas avec la locale courante). Cette structure Locale contient tout un tas d'informations utiles comme le format de la date dans le pays ou la lettre réservée pour la monnaie. Elle sera en outre nécessaire pour (presque) toutes les opérations de la locale.library, mais pas forcément pour l'ouverture d'un catalogue.

Vous pouvez ouvrir le catalogue de votre application grâce à la fonction OpenCatalog() : pointeur sur la Locale en A0 (précédemment ouverte par OpenLocale(), ou 0 pour la locale courante, ce qui sera généralement le cas), nom en A1, pointeur sur une taglist en A2. Les tags actuellement définis permettent de réclamer un langage particulier (OC_Language), une version précise (OC_Version), de préciser le langage des chaînes incluses dans votre exécutable (OC_BuiltInLanguage). Attention, le numéro de version ne fonctionne pas comme celui d'OpenLibrary() : il faut que la version du catalogue soit exactement celle demandée. En retour, on obtient un pointeur qui ne signifie quelque chose que pour la locale.library. 0 signifie que le catalogue n'a pu être ouvert pour une raison ou pour une autre.

L'accès aux messages contenus dans le catalogue se fait par l'intermédiaire de la fonction GetCatalogStr() : pointeur sur le catalogue retourné par OpenCatalog() en A0, identificateur de la chaîne à renvoyer en D0 et pointeur sur la chaîne dans la langue par défaut en A1. C'est ce message qui est retourné quand le message en question n'existe pas dans le catalogue, par exemple lorsque CatComp remarque que la chaîne traduite et la chaîne originale sont les mêmes. En D0, la fonction retourne un pointeur sur le message voulu, pour utilisation par votre application. Ce pointeur reste valable tant que le catalogue reste ouvert. Bien entendu, vous ne devez jamais modifier ce message.

Lorsque votre programme est sur le point de quitter, il faut tout fermer : fermer le catalogue grâce à CloseCatalog(), la Locale grâce à CloseLocale(), et la locale.library par CloseLibrary().

Il existe aussi une fonction, d'usage assez rare toutefois, GetLocaleStr(), permettant l'accès à des messages courants (Oui, Non, Aujourd'hui...) que la locale connaît. Même syntaxe que pour GetCatalogStr(), sauf le paramètre catalogue, qui est remplacé par un pointeur sur la Locale, et la chaîne par défaut, qui n'existe pas. Voyez les includes pour toutes les possibilités.

Autres possibilités

La locale.library offre d'autres fonctions. Celles qui concernent la date sont FormatDate(), qui permet de préparer une date grâce à des codes de formatage similaires à ceux utilisés par RawDoFmt() et printf(), par exemple %A pour le nom du jour, %a pour le nom abrégé, %Y pour l'année. L'autre, ParseDate(), tente de faire l'opération inverse : interpréter une chaîne de caractères représentant une date, dans la langue considérée bien sûr.

D'autres fonctions concernent la gestion des caractères : ConvToUpper() et ConvToLower() pour mettre en majuscules ou minuscules, FormatString() est un remplacement de RawDoFmt() qui permet de faire varier la position des arguments (très utile), la série des IsXXX() permet de tester si un caractère est une majuscule, un symbole de ponctuation, un chiffre hexadécimal... et Strncmp() et StrConvert() proposent des algorithmes sophistiqués de comparaison (comment comparer les lettres e et é en français ?) et transformation de chaînes de caractères. Je vous renvoie aux autodocs pour plus de détails car la place m'est comptée.

Exemple

Le "programme de mai 95 que j'ai" vous permet d'examiner quelques champs d'une structure locale : formats de date et heure, symboles monétaires, décalage horaire, etc. C'est bien entendu un programme localisé, il vous faudra impérativement vous procurer le programme CatComp. Vous devrez taper le fichier ShowLocale.cd et fabriquer un fichier include pour l'assembleur en tapant :

Catcomp ShowLocale.cd ASMFILE=ShowLocaleCat.i

Vous pourrez alors assembler le programme normalement. Lorsque vous le lancerez, vous constaterez que les messages sont en anglais. Pour effectuer une traduction, c'est devenu très simple : fabriquez un fichier .ct vierge par la commande :

Catcomp ShowLocale.cd CTFILE=ShowLocale.ct

Éditez alors le fichier résultant, en remplissant les blancs par les traductions françaises (ou autres !) des messages placés en commentaire. Remplacez également les X par ce qu'il faut : ShowLocale.catalog au début du fichier, le numéro de version (1.0) et la date, le codeset à 0, et language à français (n'oubliez pas la cédille, et mettez tout en minuscules). Vous sauvegardez à nouveau le fichier .ct et vous pouvez alors générer le catalogue lui-même par :

Catcomp ShowLocale.cd ShowLocale.ct CATALOG=LOCALE:Catalogs/ français/ShowLocale.catalog

Après cela, le programme devrait marcher en français, comme par miracle. Un dernier mot : le programme attend un argument. C'est le nom de la locale à ouvrir, c'est-à-dire le nom d'un fichier créé avec l'éditeur de préférences de la locale. Si vous ne donnez aucun nom, c'est la locale en cours qui sera utilisée (fichier locale.prefs).

Fichier.cd

#header SHOWLOCALE_MESSAGES
#array ShowLocale.Mes
;
MSG_NOLOCALE (//)
Cannot open required locale.
;
MSG_LOCALENAME (//)
Locale name: "%s"
;
MSG_LANGUAGENAME (//)
Language name: "%s"
;
MSG_COUNTRYCODE (//)
Country code: %lU
;
MSG_TELEPHONECODE (//)
Telephone code: %lU
;
MSG_GMTOFFSET (//)
Greenwich Meridian Time offset (minutes): %lD
;
MSG_DATEFORMAT (//)
Date format: "%s"
;
MSG_TIMEFORMAT (//)
Time format: "%s"
;
MSG_SHORTDATEFORMAT (//)
Short date format: "%s"
;
MSG_SHORTTIMEFORMAT (//)
Short time format: "%s"
;
MSG_DECIMALPOINT (//)
Decimal point: "%s"
;
MSG_GROUPSEPARATOR (//)
Group separator: "%s"
;
MSG_FRACGROUPSEPARATOR (//)
Fractional group separator: "%s"
;
MSG_MONCS (//)
Currency symbol: "%s"
;
MSG_MONINTCS (//)
Internationnal currency code (ISO 4217): "%s"

Programme principal

; listing du programme: ShowLocale.s
; n'oubliez pas de produire le fichier include
; ShowLocaleCat.i avec Catcomp avant d'assembler
    include exec/exec.i
    include exec/exec_lib.i
    include dos/dos.i
    include dos/dos_lib.i
    include libraries/locale.i
    include libraries/locale_lib.i

    move.l  4.w,a6
    lea     DOS.Name(pc),a1
    moveq   #37,d0
    jsr     _LVOOpenLibrary(a6)
    move.l  d0,DOS.Base
    beq     exit
    lea     Locale.Name(pc),a1
    moveq   #38,d0
    jsr     _LVOOpenLibrary(a6)
    move.l  d0,Locale.Base
    beq     closedos
    suba.l  a0,a0               ; locale courante
    move.l  d0,a6
    jsr     _LVOOpenLocale(a6)
    move.l  d0,CurrentLocale
    suba.l  a0,a0
    lea     Catalog.Name(pc),a1
    move.l  a0,a2
    jsr     _LVOOpenCatalogA(a6)
    move.l  d0,Prog.Catalog
    move.l  #Args.Template,d1
    move.l  #Args.Array,d2
    moveq   #0,d3
    move.l  DOS.Base(pc),a6
    jsr     _LVOReadArgs(a6)    ; lit les args
    move.l  d0,Args.RDArgs
    beq.s   closecatalog
    jsr     _LVOOutput(a6)
    move.l  d0,Out.Handle       ; canal de sortie

    move.l  Args.Array(pc),a0   ; ouvre locale
    move.l  Locale.Base(pc),a6  ; demandée
    jsr     _LVOOpenLocale(a6)
    move.l  d0,Locale.ToShow
    bne.s   LocaleFound
    move.l  #MSG_NOLOCALE,d0    ; non trouvée
    bsr     Print
    bra.s   freeargs
LocaleFound
    lea     Print.Hook(pc),a3   ; routine d'affichage
    lea     Fields.Table(pc),a4 ; champs à afficher
    move.l  Locale.ToShow(pc),a5
    move.l  Locale.Base(pc),a6
MainLoop
    move.l  (a4)+,d0            ; offset du champ
    blt.s   .End                ; <0 => fin
    move.l  0(a5,d0),-(sp)
    move.l  CurrentLocale(pc),a0
    move.l  (a4)+,d0            ; message réel
    bsr.s   GetString
    move.l  d0,a1
    move.l  sp,a2
    jsr     _LVOFormatString(a6)
    addq.l  #4,sp
    bra.s   MainLoop
.End  move.l Locale.ToShow(pc),a0
    move.l  Locale.Base(pc),a6
    jsr     _LVOCloseLocale(a6)
freeargs
    move.l  Args.RDArgs(pc),d1
    move.l  DOS.Base(pc),a6
    jsr     _LVOFreeArgs(a6)
closecatalog
    move.l  Prog.Catalog(pc),a0
    move.l  Locale.Base(pc),a6
    jsr     _LVOCloseCatalog(a6)
    move.l  CurrentLocale(pc),a0
    jsr     _LVOCloseLocale(a6)
    move.l  a6,a1
    move.l  4.w,a6
    jsr     _LVOCloseLibrary(a6)
closedos
    move.l  DOS.Base(pc),a1
    jsr     _LVOCloseLibrary(a6)
exit moveq  #0,d0
    rts
; cette routine renvoie le message dont
; l'identificateur est en D0
GetString
    movem.l d1/a0-a1/a6,-(sp)
    lea     ShowLocale.Mes(pc),a1
.sloop cmp.l cca_ID(a1),d0
    beq.s   .found
    addq.l  #ShowLocale.MesType_SIZEOF,a1
    bra.s   .sloop
.found move.l cca_Str(a1),a1
    move.l  Prog.Catalog(pc),a0
    move.l  Locale.Base(pc),a6
    jsr     _LVOGetCatalogStr(a6)
    movem.l (sp)+,d1/a0-a1/a6
    rts
Print movem.l d0-d1/a0-a1/a6,-(sp)
    bsr     GetString
    move.l  DOS.Base(pc),a6
    move.l  d0,d1
    jsr     _LVOPutStr(a6)
    movem.l (sp)+,d0-d1/a0-a1/a6
    rts

; routine appelée par la fonction FormatString() de 
; la locale.library
Print.Func
    movem.l d0-d2/a0-a1/a6,-(sp)
    move.l  a1,d2
    beq.s   .None
    move.l  Out.Handle(pc),d1
    move.l  DOS.Base(pc),a6
    jsr     _LVOFPutC(a6)
.None movem.l (sp)+,d0-d2/a0-a1/a6
    rts
DOS.Base        dc.l    0
Locale.Base     dc.l    0
CurrentLocale   dc.l    0
Prog.Catalog    dc.l    0
Args.Array      dc.l    0
Args.RDArgs     dc.l    0
Out.Handle      dc.l    0
Locale.ToShow   dc.l    0
Print.Hook      dc.l    0,0,Print.Func,0,0

DOS.Name        dc.b    'dos.library',0
Locale.Name     dc.b    'locale.library',0
Catalog.Name    dc.b    'ShowLocale.catalog',0
Args.Template   dc.b    'LOCALENAME',0
    even
Fields.Table
    dc.l        loc_LocaleName,MSG_LOCALENAME
    dc.l        loc_LanguageName,MSG_LANGUAGENAME
    dc.l        loc_CountryCode,MSG_COUNTRYCODE
    dc.l        loc_TelephoneCode,MSG_TELEPHONECODE
    dc.l        loc_GMTOffset,MSG_GMTOFFSET
    dc.l        loc_DateFormat,MSG_DATEFORMAT
    dc.l        loc_TimeFormat,MSG_TIMEFORMAT
    dc.l        loc_ShortDateFormat,MSG_SHORTDATEFORMAT
    dc.l        loc_ShortTimeFormat,MSG_SHORTTIMEFORMAT
    dc.l        loc_DecimalPoint,MSG_DECIMALPOINT
    dc.l        loc_GroupSeparator,MSG_GROUPSEPARATOR
    dc.l        loc_FracGroupSeparator,MSG_FRACGROUPSEPARATOR
    dc.l        loc_MonCS,MSG_MONCS
    dc.l        loc_MonIntCS,MSG_MONINTCS
    dc.l        -1
CATCOMP_NUMBERS SET 1
CATCOMP_STRINGS SET 1
CATCOMP_ARRAY   SET 1
    include     ShowLocaleCat.i


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]