DDgui Programmers Reference Guide by Nicholas J. Kingsley - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.

Introduction

 

If you are displaying text, it would be good if you design your program so that all text can be internationalised.

 

This means that instead of using text that can't be changed to accommodate other languages, you design your program to use tokens, which will then display text based on the users language settings.

 

An example use could be something like :

 

DDgui_widget(“hello”,language$(“{{hello}}”),0,0)

 

with the function language$ taking the token string “{{hello}}” and converting it to the word “hello” in English, French, German or any other language.

 

Thus, I present the following internationalisation routine.   It was converted from another BASIC language, and is designed to convert tokens to text.

 

Additional language files would go in Media/Language/x/LANGUAGE.INI, where “x” is the LOCALE string (returned from PLATFORMINFO(“LOCALE”)

 

REQUIRE "defaultLanguage.c"

 

INLINE

}

typedef int size_t;

 

extern char *defaultLanguage[];

extern "C" size_t strlen(const char *s);

 

namespace __GLBASIC__ {

ENDINLINE

 

CONSTANT LANGUAGE_ACTIVE% = 1

 

TYPE TLocalisation

flags%

languageDef$

languageVer$

languageAuth$

map AS TMap

 

SECTION_NAME$ = "LanguageDefinition"

 

FUNCTION Initialise%:flags%=0

IF self.map.Initialise()

  self.flags%=flags%

  self.languageDef$=""

  self.languageVer$=""

  self.languageAuth$=""

  RETURN TRUE

ELSE

  RETURN FALSE

ENDIF

ENDFUNCTION

 

FUNCTION Destroy%:

self.map.Destroy()

ENDFUNCTION

 

FUNCTION SetLanguageDetails%:langDef$,langVer$,langAuth$

self.languageDef$=langDef$

self.languageVer$=langVer$

self.languageAuth$=langAuth$

ENDFUNCTION

 

FUNCTION AddLanguage%:key$,value$

self.map.Add(key$,value$)

ENDFUNCTION

 

FUNCTION LoadLanguage%:override$=""

LOCAL path$,language$,temp$

LOCAL loop%

LOCAL split$[]

 

  path$="Media/Language/"

IF override$=""

  language$=PLATFORMINFO$("LOCALE")

ELSE

  language$=override$

ENDIF

 

  path$=path$+language$+"/LANGUAGE.INI"

 

  IF DOESFILEEXIST(path$)

  INIOPEN path$

 

   self.languageDef$=INIGET$(self.SECTION_NAME$,"LanguageID")

  self.languageVer$=INIGET$(self.SECTION_NAME$,"LanguageVersion")

  self.languageAuth$=INIGET$(self.SECTION_NAME$,"LanguageAuthor")

 

   loop%=0

  temp$=INIGET$(self.SECTION_NAME$,loop%,"")

  DEBUG "T:"+temp$+"\n"

  KEYWAIT

  WHILE temp$<>""

   DIM split$[0]

   IF SPLITSTR(temp$,split$[],",")>=2

    self.map.Add(split$[0],split$[1])

   ENDIF

 

    INC loop%

   temp$=INIGET$(self.SECTION_NAME$,loop%,"")

  WEND

 

   INIOPEN ""

  RETURN TRUE

ELSE

  RETURN FALSE

ENDIF

ENDFUNCTION

 

FUNCTION GetLanguageID$:

RETURN self.languageDef$

ENDFUNCTION

 

FUNCTION GetLanguageVersion$:

RETURN self.languageVer$

ENDFUNCTION

 

FUNCTION GetLanguageAuthor$:

RETURN self.languageAuth$

ENDFUNCTION

 

FUNCTION LocaliseText$:string$

LOCAL loop%

LOCAL one$,tmpPrevChar$,tmpText$

LOCAL tmpCount%

LOCAL tmpOpening%[]

 

  IF bAND(self.flags%,LANGUAGE_ACTIVE%)

  DIM tmpOpening%[LEN(string$)/2]

  FOR loop%=0 TO BOUNDS(tmpOpening%[],0)-1; tmpOpening%[loop%]=0; NEXT

 

   loop%=0

  tmpPrevChar$=""

  tmpCount%=0

 

   WHILE loop%<LEN(string$)

   one$=MID$(string$,loop%,1)

   SELECT one$

    CASE "{" // Start of token

       IF tmpPrevChar$ = one$

        tmpOpening%[tmpCount%] = loop%+1

        INC tmpCount%

        tmpPrevChar$=""

       ELSE

        tmpPrevChar$=one$

       ENDIF

 

     CASE "}" // End of token

       IF tmpPrevChar$ = one$

        DEC tmpCount%

        tmpText$=MID$(string$,tmpOpening%[tmpCount%],loop%-tmpOpening%[tmpCount%]-1)

        SELECT UCASE$(tmpText$)

         CASE "DOCS"

             tmpText$=PLATFORMINFO$("DOCUMENTS")

 

          CASE "WHAT"

             tmpText$=PLATFORMINFO$("")

 

          CASE "ID"

             tmpText$=PLATFORMINFO$("ID")

 

          CASE "DEVICE"

             tmpText$=PLATFORMINFO$("DEVICE")

 

          CASE "COMPILED"

             tmpText$=PLATFORMINFO$("COMPILED")

 

          DEFAULT

             DEBUG "Tmp : "+tmpText$+"\n"

             tmpText$ = self.LocaliseText$(self.map.GetValue$(tmpText$))

 

         ENDSELECT

 

         string$=MID$(string$,0,tmpOpening%[tmpCount%]-2)+tmpText$+MID$(string$,loop%+1)

        INC loop%,LEN(tmpText$)-(loop%+3-tmpOpening%[tmpCount%])

        tmpPrevChar$=""

       ELSE

        tmpPrevChar$=one$

       ENDIF

 

     DEFAULT

       tmpPrevChar$=""

   ENDSELECT

 

    INC loop%

  WEND

ENDIF

 

  RETURN string$

ENDFUNCTION

ENDTYPE

 

FUNCTION Localise_TextHelper%:BYREF index%,BYREF token$,BYREF value$

token$=""

value$=""

 

INLINE

if ((defaultLanguage[index]) && (strlen(defaultLanguage[index])>0))

{

token_Str=DGStr(defaultLanguage[(int) index]);

INC(index);

if ((defaultLanguage[(int) index]) && (strlen(defaultLanguage[index])>0))

{

  value_Str=DGStr(defaultLanguage[(int) index]);

  INC(index);

}

 

  return (DGNat) TRUE;

}

 

return (DGNat) FALSE;

ENDINLINE

ENDFUNCTION

 

//! Use default text if locale isn't available

FUNCTION Localise_UseDefault%:localise AS TLocalisation

LOCAL result%,index%,token$,value$

 

IF localise.LoadLanguage()=FALSE

index%=0

result%=Localise_TextHelper(index%,token$,value$)

WHILE result%=TRUE

  localise.AddLanguage(token$,value$)

  result%=Localise_TextHelper(index%,token$,value$)

WEND

 

  localise.SetLanguageDetails("English (British)","1.0.0.0","Default Language")

RETURN FALSE

ELSE

RETURN TRUE

ENDIF

ENDFUNCTION

 

An example of use would be :

 

LOCAL localise as Tlocalise

 

IF localise.Initialise(LANGUAGE_ACTIVE%)=FALSE

DEBUG "Unable to initialise TLocalisation"

RETURN FALSE

ENDIF

 

localise_UseDefault(localise)

DEBUG “Result : “+localise.LocaliseText$(“{{hello}}”)

 

As it stands, the routine could not be compiled as a default language string is need. 

 

First, you need the Tmap routine.  This is covered in slightly more detail in the GLBasic Programmers Reference Guide, but is included here for completeness :

 

// --------------------------------- //

// Project: ddd

// Start: Tuesday, October 05, 2010

// IDE Version: 8.120

 

TYPE tKeyValue

key$

value$

ENDTYPE

 

TYPE TMap

list[] AS tKeyValue

 

//! Initialise type

//\param None

//\return TRUE

FUNCTION Initialise%:

DIM self.list[0]

RETURN TRUE

ENDFUNCTION

 

//! Destroy type

//\param None

//\return TRUE

FUNCTION Destroy%:

DIM self.list[0]

RETURN TRUE

ENDFUNCTION

 

//! Add a key and value to the internal array, and sort array afterwards

//\param key$ - Key to add

//\param value$ - Value of key

//\return TRUE if the key and value has been added, FALSE otherwise

FUNCTION Add%:key$,value$

LOCAL temp AS tKeyValue

 

  IF self.search(key$)<0

  // Found

  temp.key$=key$

  temp.value$=value$

  DIMPUSH self.list[],temp

  SORTARRAY self.list[],0

  RETURN TRUE

ENDIF

 

  RETURN FALSE

ENDFUNCTION

 

FUNCTION search%:key$

LOCAL up%,down%,mid%

 

  up%=0

down%=BOUNDS(self.list[],0)-1

WHILE up%<down%

  mid%=(up%+down%)/2

  IF self.list[mid%].key$>key$

   down%=MAX(mid%-1,up%)

  ELSEIF self.list[mid%].key$<key$

   up%=MIN(down%,mid%+1)

  ELSE

   RETURN mid% // Found

  ENDIF

WEND

 

  IF BOUNDS(self.list[],0)>0 AND self.list[up%].key$=key$

  RETURN up%

ELSE

  RETURN -1

ENDIF

ENDFUNCTION

 

FUNCTION Debug%:

LOCAL loop AS tKeyValue

 

  FOREACH loop IN self.list[]

  DEBUG "Key : "+loop.key$+" Value : "+loop.value$+"\n"

NEXT

DEBUG "Number of keys and values : "+BOUNDS(self.list[],0)+"\n"

ENDFUNCTION

 

FUNCTION GetValue$:key$,notFound$="NOT_FOUND"

LOCAL index%

 

  index%=self.search(key$)

IF index%>=0

  RETURN self.list[index%].value$

ELSE

  RETURN notFound$

ENDIF

ENDFUNCTION

 

FUNCTION DeleteKey%:key$

LOCAL index%

 

  index%=self.search(key$)

IF index%>=0

  DIMDEL self.list[],index%

  RETURN TRUE

ELSE

  RETURN FALSE

ENDIF

ENDFUNCTION

 

FUNCTION Count%:

RETURN BOUNDS(self.list[],0)

ENDFUNCTION

ENDTYPE

 

Usually, the text would be added during compilation.  Its a simple procedure to add to your programs – save the following as a .c file into the same place as your project (calling it defaultLanguage.c) :

 

char *defaultLanguage[]={

"startgame",  "Start Game",

"continuegame", "Continue Game",

"options",  "Options",

"instructions", "Instructions",

"hiscores",  "Hiscores",

"quitgame",  "Quit Game",

"arcadegame",  "Player V Computer Game",

"standardgame", "Standard Game",

"upto3",  "Up To 3 Wins",

"prev",   "Previous Menu",

"\0",   "\0"

};

 

And now, if you use “{{startgame}}”, you could get “Start Game” as the resulting string.  If you had a French language file setup, “{{startgame}}” could return “Commencez le jeu”.