- - * - WhiteUnicorn - * - -




* #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ >


3201:How to use a string table resource

KEYWORDS: string, stringtable, resource files, language, translation AREA: App

Stringtable resources are a very useful tool when your
application must store a large number of strings for use
at runtime. While you may be tempted to directly embed
strings into your executable, using a stringtable resource
offers two advantages: 1) The strings contained in the
stringtable do not consume memory until they are loaded
by your application. 2) Stringtables are easily edited,
providing an easy path to internationally localized
versions of your application.

Stringtables are compiled into a ".res" file that is
attached to your application's exe file at build time.
Even after you distribute your appliaction, the stringtable
contained in your application's exe file can be edited with
a resource editor. My favorite resource editor is Borland's
Resource Workshop that ships with the RAD pack. It can produce
and edit both 16 and 32 bit resources that are self contained,
standalone, or embedded in a .exe or .dll in full WYSIWYG
fashion.

It's worth noting that all versions of Delphi ship with the
Borland Resource Command Line Compiler (BRCC.EXE and BRCC32.EXE),
and can be found in Delphi's Bin directory.

For our example, we will build an internationalized application
that displays two buttons. The buttons will have captions for
"Yes" and "No" presented in English, Spanish, and Swedish.

It's worth noting that if you want to build international
applications using Delphi, you should take a look at Borland's
Delphi Translation Suite and Language Pack software. These
packages can make porting your application to international
markets a snap!


Example:

We first must create a text file containing our string
resources in the applications build directory. You may
name the file anything you wish, so long as it has the
file extension ".rc" and the filename without the extension
is not the same as any unit or project filename. This is
very important, as Delphi also will create a number of
resource files for your project automatically.

Here is the contents of the .rc file for our example. It
contains the words "Yes" and "No" in English, Spanish,
and Swedish:

STRINGTABLE
{
 1, "&Yes"
 2, "&No"
 17, "&Si"
 18, "&No"
 33, "&Ja"
 34, "&Nej"
}


The file starts with the key word stringtable denoting that
a string table resource will follow. Enclosed in the
curly braces are the strings. Each string is listed by its
index identifier, followed by the actual string data in
quotes. Each string may contain up to 255 characters. If you
need to use a non-standard character, insert the character
as a backslash character followed by the octal number of
the character you wish to insert. The only exception is
when you want to embed a backslash character, you will need
to use two backslashes. Here are two examples:

1, "A two\012line string"

2, "c:\\Borland\\Delphi"

The Index numbers that you use are not important to the
resource compiler. You should keep in mind that string
tables are loaded into memory in 16 string segments.

To compile the .rc file to a .res file that can be linked
with your application, simply type on the dos command line
the full path to the resource compiler, and the full path
to the name of the .rc file to compile. Here is an example:

c:\Delphi\Bin\brcc32.exe c:\Delphi\strtbl32.rc

When the compiler is finished, you should have a new file
with the same name as the .rc file you've compiled, only
with an extension of ".res".

You can link the resource file with your application simply
by adding the following statement to your application's
code, substituting the name of your resource file:

{$R ResFileName.RES}

Once the .res file is linked to your program, you can load
the resource from any module, even if you specified
the $R directive in the implementation section of a
different unit.

Here is an example of using the Windows API function
LoadString(), to load the third string contained in
a string resource into a character array:

  if LoadString(hInstance,
                3,
                @a,
                sizeof(a)) <> 0 then ....

In this example, the LoadString() function accepts the
hInstance of the module containing the resource, the
string index to load, the address of the character array
to load the string to, and the size of the character array.
The LoadString function returns the number of characters
that where actually loaded not including the null terminator.
Be aware that this can differ from the number of bytes
loaded when using unicode.


Here is a complete example of creating an international
application with Borland's Delphi. The application is
compatible with both 16 and 32 bit versions of Delphi.

To do this, you will need to create two identical .rc
files, one for the 16 bit version, and the other for the
32 bit version, since the resources needed for each
platform are different. In this example. we will create
one file named STRTBL16.rc and another called STRTBL32.rc.
Compile the STRTBL16.rc file using the BRCC.exe compiler
found in Delphi 1.0's bin directory, and compile STRTBL32.rc
using the BRCC32.exe compiler found in Delphi 2.0's bin
directory.

We have taken into account the language that Windows
is currently using at runtime. The method for getting
this information differs under 16 and 32 bit Windows.
To make the code more consistant, we have borrowed the
language constants from the Windows.pas file used in 32
bit versions of Delphi.



{$IFDEF WIN32}
   {$R STRTBL32.RES}
{$ELSE}
   {$R STRTBL16.RES}
   const LANG_ENGLISH = $09;
   const LANG_SPANISH = $0a;
   const LANG_SWEDISH = $1d;
{$ENDIF}


function GetLanguage : word;
{$IFDEF WIN32}
{$ELSE}
  var
    s : string;
    i : integer;
{$ENDIF}
begin
{$IFDEF WIN32}
  GetLanguage := GetUserDefaultLangID and $3ff;
{$ELSE}
  s[0] := Char(GetProfileString('intl',
                                'sLanguage',
                                'none',
                                @s[1],
                                sizeof(s)-2));
  for i := 1 to length(s) do
    s[i] := UpCase(s[i]);
  if s = 'ENU' then GetLanguage := LANG_ENGLISH else
  if s = 'ESN' then GetLanguage := LANG_SPANISH else
  if s = 'SVE' then GetLanguage := LANG_SWEDISH else
    GetLanguage := LANG_ENGLISH;
{$ENDIF}
end;


procedure TForm1.FormCreate(Sender: TObject);
var
  a : array[0..255] of char;
  StrTblOfs : integer;
begin

 {Get the current language and stringtable offset}
  case GetLanguage of
    LANG_ENGLISH : StrTblOfs := 0;
    LANG_SPANISH : StrTblOfs := 16;
    LANG_SWEDISH : StrTblOfs := 32;
   else
    StrTblOfs := 0;
  end;

 {Load language dependent "Yes" and set the button caption}
  if LoadString(hInstance,
                StrTblOfs + 1,
                @a,
                sizeof(a)) <> 0 then
    Button1.Caption := StrPas(a);

 {Load language dependent "No" and set the button caption}
  if LoadString(hInstance,
                StrTblOfs + 2,
                @a,
                sizeof(a)) <> 0 then
    Button2.Caption := StrPas(a);
end;

<end of ti>


        TI



* #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ >



- - * - Anastasija aka WhiteUnicorn - * - - LJLiveJournal
PFPhotoFile