Local

Par
Benoît GILON

Cet article présente une méthode et le module adhoc afin qu'une application écrite en langage C puisse facilement ”s'adapter au ”pays de l'ordinateur hôte (c.a.d. sur laquelle elle s'exécute). S'adapter signifie ici afficher les informations de dialogue (messages textuels isolés ou au sein de boîtes de dialogue) dans la langue comprise par l'utilisateur (à condition que celui-ci ait préalablement positionné son pays d'origine par la commande: *Country ou *Configure Country.

(NDA: Il n'est pas tenu compte dans cette version de pays multilingues comme le sont la Suisse et la Belgique dans lesquels la désignation du pays n'implique pas forcément la langue pratiquée).

Précisons l'ancienne architecture:

  1. Le diagramme ci-dessus ne cite que les principaux fichiers rencontrés au sein d'une application; d'autres fichiers comme !Choices, Template3D ou !Sprite22 peuvent être également présents.
  2. Cette architecture, quoique très ouverte comparée à d'autres systèmes d'exploitation (dont Windows) parce que les fichiers dits de ressource sont externes au code et peuvent par conséquent être édités relativement facilement, ne permet pas une adaptation automatique et évolutive à des exploitations sous plusieurs pays. En particulier, nous notons que celle-ci ne propose qu'un seul lot de fichiers Messages/Templates et !Help.
    D'où ma proposition pour adopter l'architecture suivante:

Présentation

Nous disposons d'un jeu de fichiers Help/Messages/Templates par pays d'utilisation potentiel (sur le diagramme précédent, la France, l'Allemagne et le Royaume Uni). De plus le module gère automatiquemnt le chargement d'un fichier Template3D si l'utilisateur a auparavant souhaité disposer d'un bureau au look 3D (lancement de l'application !NewLook sur RISC OS 3.10 ou dans l'application Configure pour RISC OS 3.5).

Module intern et modification de vos sources

Le module intern est le module exportant les fonctions mmsgs_init() et mtemplate_init(), fonctions à substituer aux deux fonctions classiques msgs_init() et template_init() de la RISC OS Lib. Il est acquis dans le texte qui suit que l'application écrite en C suit l'architecture présentée précédemment, plus précisemment que les informations affichés sous forme de texte en clair sont ”extraites du fichier Messages par appel à la fonction msgs_lookup().

#include "msgs.h"
#include "template.h" devient:
#include "msgs.h"
#include "template.h"
#include "intern.h"

Module intern: implémentation

La première action effectuée au sein des deux fonctions mtemplate_init() et mmsgs_init() est d'appeler une fonction C chargée de tester l'existence d'un répertoire au sein de l'application dont le nom concorde avec celui du pays en cours. Cette fonction a comme nom validate_country().

static void validate_country(void)
{
static char country_name[32]= "";
/* Look for the current country only on 1st
 * call */
if(country_name[0]== '\0')
    {
    int r0out,r1out,r2out,r3out,r4out,r5out;
    static int country_number= -1;
    /* Read country number */
    (void) os_swi3r(OS_BYTE|os_X,(int) 240,0,
        255,&r0out, &country_number,&r2out);
    /* Convert country no to country name */
    (void) os_swi6r(OS_SERVICE_CALL|os_X,NULL,
        INTERNATIONAL,2,country_number,
        (int) country_name,
        sizeof(country_name),&r0out,&r1out,
        &r2out,&r3out,&r4out,&r5out);
     country_name[r5out]= '\0';
     strcpy(resname+sizeof("Resources.")-1,
         country_name);
     if(!FindFile(resname))
         {
         if(country_number== COUNTRY_UK)
             werr(TRUE,
                 "Unable to find resource files");
         strcpy(resname+sizeof("Resources.")-1, "UK");
         if(!FindFile(resname)) werr(TRUE,
             "Unable to find resource files");
         else
             {
             char strparm[32];
             sprintf(strparm,
                 "Unable to find %s resource files",
                 country_name);
             werr(FALSE,"%s %s",strparm,
                  "Default to UK");
             strcpy(country_name,"UK");
             country_number= COUNTRY_UK;
             }
        }
    }
}
/* Buffer str. to hold complete filename */
static char buffer[64]; 
static BOOL FindFile(char *fname)
{
int r0out= 0, r1out, r2out;
(void) res_findname(fname,buffer);
/* Test for existence of the file and open
 * it for read access */
(void) os_swi3r(OS_FIND | os_X, (int) 0x40,
    (int) buffer, NULL, &r0out, &r1out, &r2out);
if(!r0out) return(FALSE);
/* Closes the file */
(void) os_swi2(OS_FIND | os_X, 0, r0out); 
return(TRUE);
}
static BOOL FindResFile(char *suffix)
{
static char buffer[32];
sprintf(buffer,"%s%s",resname,suffix);
return(FindFile(buffer));
}
/* This function is a substitute for the
 * RISC OS lib msgs_init() function as
 * it reads a file in the language setup to
 * the currently setup country */
void mmsgs_init(void)
{
msgs_init();
validate_country();
(void) FindResFile(".Messages");
msgs_readfile(buffer);
}
/* This function is a substitute for the
 * RISC OS lib template_init() function.
 * Support for dynamic selection of 3D
 * template files has been added. */
void mtemplate_init(void)
{
validate_country();
switch(isNewLook())
    {
    case TRUE:
        if(FindResFile(".Template3D")) break;
    case FALSE:
        (void) FindResFile(".Templates");
        break;
    }
(void) template_readfile(buffer);
}
/* OS Byte reason code */
#define READ_OS_VERSION 129
/* Read CMOS RAM */
#define READ_CMOS_RAM 161
/* CMOS RAM byte to scan for desktop 3D
 * look */
#define DESKTOP_FEATURES 140
/* Finds out if the 3D rendered template should be used
 * or not. For RISC OS 2, 3.0,
 * 3.10 and above (RISC OS 3.5) */
static BOOL isNewLook(void)
{
int r1inout = 0, r2inout  = (int) 0xff;
(void) os_byte(READ_OS_VERSION, &r1inout,
    &r2inout);
if(r1inout < RISCOS_3_10) return(FALSE);
r1inout= DESKTOP_FEATURES;
(void) os_byte(READ_CMOS_RAM, &r1inout,
    &r2inout);
/* Only LSB is of some interest to us */
return((r2inout & 1) != 0);
}

ReadHelp: implémentation

Le programme Readhelp est chargé de trouver le fichier Help situé dans le répertoire correspondant au pays courant, et d'effectuer un Filer_Run sur ce fichier. Si ce fichier n'existe pas, la version UK de celui-ci est prise par défaut. Notons aussi que le Filer_Run est à même de traiter tout type de fichier Help (texte statique aujourd'hui, dynamique/HTML demain, autre chose après demain etc...) sans avoir à recompiler le fichier ReadHelp pour cela,

#include <stdlib.h>
...
static char buffer[96];
static int lob;
...
int main(argc, argv)
int argc;
char *argv[];
{
char locbuffer[128], *p;
char *monenv= getenv("Obey$Dir");
if(!monenv)
    {
    werr(0,"Obey$Dir not set ????");
    return(0);
    }
lob= strlen(strcpy(buffer,monenv));
p= FindFile("help",".Help");
sprintf(locbuffer,"Filer_Run %s",p);
system(locbuffer);
return(0);
}
static char *FindFile(
    char *filetype, char *filename)
{
int r0out= 0, r1out, r2out;
strcpy(resname+
    sizeof(".Resources.")-1,
    read_country_name());
strcat(buffer,resname);
(void) os_swi3r(OS_FIND | os_X, (int) 0x40,
    (int) buffer, NULL,
    &r0out, &r1out, &r2out);
if(!r0out)
    {
    char strparm[32];
    sprintf(strparm,"Unable to find %s file",filetype);
    werr(0,"%s %s",strparm,"Default to UK");
    strcpy(resname+sizeof(".Resources.")-1,
        "UK");
    strcpy(buffer+lob,resname);
    }
else
    (void) os_swi2(OS_FIND | os_X, 0, r0out);
return(strcat(buffer, filename));
}