1. Technology
Localizing Delphi applications using StringTable resources
While resource files enable storing more than just program code in an EXE file, by including stringtable resources to an application a Delphi developer can easily build multilanguage applications. Learn how.
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 More of this Feature
• Part 1: Resource Files Made Easy
• Part 2: Inside the EXE (compiling .rc files)
• Part 3: Web Site inside a Delphi EXE
• Part 4: Resource only DLL
• Part 6: Resource Managers
• Part 7: Fixing the "Duplicate resource" error
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• The fastest path to Delphi localization
• Localization Tools for Delphi
• Using the Integrated Translation Environment

This is the fifth article in the series about storing more than just executable code inside a Delphi application.
Introductory article described resources as binary data that a developer ads to an application's executable file.

StringTable resources

As you will learn from this article, an application that maintains (a large number of) strings in resources can be translated into new languages with minimum effort. Storing localized version of Label, Button, and other control Captions into a string table resource offers several advantages over placing all the strings directly into the exe file:
  1. Character strings contained in a string table resource do not consume memory until specifically loaded by an application.
  2. If using string table resources to create multilingual applications, adding a new language is trivial since Stringtables are easily edited. What's more if the string table is stored in a resource-only DLL, you do not even have to recompile your application.

As with any other type of resources, string tables are compiled into a ".res" file that is attached to your application's exe file at build time.

Creating a string table resource

Here's how to create a string table resource to support a two (multi) language application:
  1. Create a .RC text file containing your string resources in the applications build directory. Name the file "StringTableLocalization.rc" - you can name it whatever you like, but it must have the ".rc" extension.

    StringTableLocalization.rc

    STRINGTABLE
    {
    1000, "English"
    1001, "Display selected"
    1002, "Yes"
    1003, "No"
    1004, "Maybe"

    2000, "Hrvatski"
    2001, "Prikaži odabrano"
    2002, "Da"
    2003, "Ne"
    2004, "Možda"
    }

  2. Compile the RC file into a RES file with the BRCC32 resource compiler.

Note: the "StringTableLocalization.rc" CAN contain any additional number of resources of a different type (icons, images, data, etc.)

The string table starts with the key word stringtable. Enclosed in the curly braces are the strings. Each string is listed by its index identifier, followed by the actual string data in quotes. 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. For example:
1, "A two\012line string"
2, "c:\\Borland\\Delphi"

Using string tables

For the moment take a look at our string table. It is "broken" (only visually) into two regions: "English" and "Hrvatski" ("Croatian"). The Index numbers that you use are not important to the resource compiler. In order to load a particular string from the stringtable you'll use the LoadString function. One of the parameters in a call to LoadString is the index of a string in a string table.

Linking to an applicaiton
As with any .RES file, you can link the resource file with your application simply by adding the next statement to your application's code (inside the implementation section of a unit):

{$R StringTableLocalization.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 a different unit.

LoadString
Here's how a function to load a string from a stringtable could look like:

function GetString(const Index: integer) : string;
var
  buffer : array[0..255] of char;
  ls : integer;
begin
  Result := '';
  ls := LoadString(hInstance, 
                   Index, 
                   buffer, 
                   sizeof(buffer));
  if ls <> 0 then Result := buffer;
end;

A real example
I've created a test application that you can download.

English version of a stringtable-localized Delphi application

Once the application is started, the code gets all the languages defined in our string table. By "design" all the language specific strings start at 1 + (1000 * N) position (where N >= 1). The actual name of the language is located at the index for which the following is true: (1000 * N) DIV 1000 = 0.

Note: this "design" is specific to this sample application.

The application gets all the languages and presents them as items of a TRadioGroup component. Once a particular item is selected the strings defined for the selected language are loaded and used by the application.

Croatian version of a stringtable-localized Delphi application

Note: the sample application includes one "special" custom class TResourceLocalizer that actually loads the strings from the resource.

Adding additional languages to this application is a piece of cake - just edit the "StringTableLocalization.rc" by adding any new languages you want. Make sure the new language name starts with an index identifier of 3000 and all other language specific strings follow after it.
For example, to add the German language localized strings edit the RC file as follows:

StringTableLocalization.rc

STRINGTABLE
{
1000, "English"
1001, "Display selected"
1002, "Yes"
1003, "No"
1004, "Maybe"
2000, "Hrvatski"
2001, "Prikaži odabrano"
2002, "Da"
2003, "Ne"
2004, "Možda"
3000, "German"
3001, "Anzeige wählte"
3002, "Ja"
3003, "Nein"
3004, "Möglicherweise"
}

Note: I've used BabelFish to translate English to German, maybe the translation is not 100% correct.

Now, recompile it using the BRCC32 resource compiler, start the application and select the German language in the radio group:

German version of a stringtable-localized Delphi application

That's it, easy and simple. If you place all the stringtable resources into a separate DLL, you do not even have to recompile your application - only the DLL.

Note: (suggested by Mike Shkolnik on the Delphi Programming Forum)

  • When you compile the rc-file to res-file (using standard Borland bcc), the current codepage in Windows must be a same as strings in rc-file. For example, you can't compile the rc-file with Hebrew strings on English computer. Only when default codepage will be a Hebrew, bcc will compile the correct res-file. Unfortunatelly to add the LANGUAGE tag to rc-file will not solve a problem.
  • Some controls require additionally to change the Font.Charset property when language toggled.

©2014 About.com. All rights reserved.