So You Want Your Application to Be Multilingual?

by Paul Rock

One of the things that happens when you develop an application is that you view your application differently from how others do. It's easy to lose sight of the diverse customs and languages of those who might use your application.

The problem is that most applications written today need to be recompiled by a person who speaks the language to which you are translating. This article shows how, in a Presentation Manager (PM) application, you can handle this problem by stripping out the application's resources and generating a Dynamic Link Library (DLL) for each language you want to implement. Thus, an application can have a series of DLLs for each language, which can be loaded by the initial executable program. The main executable program doesn't have to know the language of the text within the DLL, simply that the DLL has the particular templates necessary to run the application successfully.

Why Would You Want Your Application to Be Multilingual?
Given the increasingly global nature of business today, applications need to address the many potential boundaries in which they might be used. People use the Internet to communicate with others around the world as if they were in the next room. The borders between countries, customs, and languages are slowly blurring. Consequently, applications need to be robust enough to accommodate an international marketplace. For example, you could have an application written in English that is color-coded to help the end user to decide what path to take through the application. To most users, this seems user friendly; but to a color-blind person who can't distinguish the picture interpretation, and doesn't speak English, this design is not helpful.

The technique presented in this article could also be used for educational purposes. Students could learn new languages by viewing applications in a variety of languages simultaneously and, with the click of a button, change the focus to yet another language. Likewise, a room full of people from different cultures could view the same program's information in their respective languages. Thus the translation of events and information (language being used) is controlled by the individual rather than the person who is speaking or the linguist translating what is being said.

Further use of such a design will enable portability to different countries, reduce maintenance costs as applications become more modular and concentrated in function, and provide customization for the end user.

When designing your application, consider how vast an audience you can attract if your application is easily transferable to many languages. This article shows how to use common code in your applications so you can reach a greater audience while keeping your maintenance cost low.

How Can You Create a Multilingual Application?
To make your application multilingual, split your initial application into two programs:
 * The first set of program files (called MYFILE.*) will actually be your initial program minus all text statements and resources included within your resource (.RC) file.
 * The second set of program files (called MYLANG.*) is simply a compilation of the resources and text that were taken out of the ORIGINAL code generated in the form of a DLL. This DLL is then loaded from your first executable file (MYFILE.EXE).

Some of the files used for both programs remain the same. For example, because both programs address the resources that will eventually be loaded, a common header file is used for both programs. Likewise, the definitions (*.DEF) file will remain the same except for a name change.

Here's what the new files will be used for:

The original source files were:
 * ORIGINAL.C - The original source file
 * ORIGINAL.DEF - The definitions file, which may hold any imports or exports
 * ORIGINAL.H - The header file defining all the variables and dialog controls used
 * ORIGINAL.RC - The resource file containing all dialog templates, icons, and bitmaps
 * ORIGINAL.MAK - The makefile used to compile, link, and generate an executable program

The new source files are:
 * MYFILE.C - The original source file with updated code to load all resources
 * MYFILE.DEF - The original definitions file (no change necessary)
 * MYFILE.H - The original header file (no change necessary)
 * MYFILE.MAK - The original makefile (no change necessary). The resource compile statement is not necessary and may be taken out if desired.
 * MYLANG.C - The generic source file. Only a main procedure is necessary.
 * MYLANG.H - The original header file (no change necessary)
 * MYLANG.RC - The original resource file ORIGINAL.RC (no change necessary)
 * MYLANG.DEF - The original definitions file (no change necessary). Note that the imports or exports declared can be taken out. MYFILE.DEF will handle any imports or exports.
 * MYLANG.MAK - The original makefile, with the file names changed from MYFILE to MYLANG, generating a DLL instead of an executable program.

The new MYFILE files generate an executable program that will load the DLL generated by the MYLANG files. The source files basically remain the same. As for the first set of files (MYFILE.*), you must make the following changes:
 * 1) Strip all text messages out of the main source file.
 * 2) Implement an array of text messages that are loaded from the MYLANG DLL to display text for the end user.
 * 3) Load icons, bitmaps, and other dialog controls before they can be used (these can be single statements).

For the second set of files (MYLANG.*), you must do the following:
 * 1) Create a generic main source file with which to associate the resources. Only a main procedure is necessary.
 * 2) Update the makefile to change the names from MYFILE to MYLANG and generate a DLL (rather than an executable program).
 * 3) Create a string table in the resource file (MYLANG.RC) for all text messages used in the application.

How Do You Program These Changes?
Once you have established the different program files, the next thing to do is make a string table in your resource file to handle all the text that you display within your application. These text messages will then be loaded by the executable file (MYFILE.EXE) into an array so they can be called upon at any time during execution. The following code examples show how to load and display text, icons, bitmaps, and other dialog controls.  // Declare an Icon called MyIcon.ICO

ICON MY_ICON MyIcon.ICO

// Set up a string table to hold the text statements that will be // used throughout the application

STRINGTABLE LOADONCALL MOVEABLE DISCARDABLE { TextMessage1, 'My first text message' TextMessage2, 'My second text message' TextMessage3, 'My third text message' };  ''Sample Code 1. MYLANG.RC''

The header file defines the dialog template controls, text messages, and other variables. The following is an example of how an icon and a text message can be defined. Your individual #define statements simply need to be unique (as with all PM programs).  - - - - - - - - - - - - - - - - - - - -  ''Sample Code 2. MYFILE.H (also MYLANG.H)''
 * 1) define MY_ICON 100// define the icon MYICON.ICO
 * 2) define TextMessage1 200// Define the first text message
 * 3) define TextMessage2 201// Define the second text message
 * 4) define TextMessage3 202// Define the third text message

Next, update the source file (MYFILE.C) to load the text strings you have created inside your resource file. Once the text is loaded, it may be entered into a global array so the program can access the text at any time in the application. This can be very helpful when creating object-oriented applications where certain methods do not have access to a local anchor block (HAB) to load the text.  VOID LoadTextMessages { HAB hab; // handle to an anchor block CHAR TextMessage[3][80]; // hold three text messages of up to 80 // characters CHAR ErrorBuffer[80];

hab=WinInitialize(0);

// Load the DLL that now holds our resources (MYLANG.DLL). // From this we will have a module handle (hmod) that may be used to // access the DLL's contents.

DosLoadModule( (PSZ)ErrorBuffer, sizeof(ErrorBuffer), 'MyLang',

// Now load the text strings from the DLL (MYL.DLL).

WinLoadString(hab, hmod, // load the first text message TextMessage1, 80, TextMessage[0]); WinLoadString(hab, hmod, // load the second text message TextMessage2, 80, TextMessage[1]); WinLoadString(hab, hmod, // load the third text message TextMessage3, 80, TextMessage[2]); // Example of how to load an icon. hMyIcon will be a handle which // references the icon. Please refer to the .RC file above.

hMyIcon = WinLoadPointer(HWND_DESKTOP, hmod, MY_ICON); - - - - - - - - - - - - - - - - - - - -

// Example of how one can display information for the end user.

WinMessageBox (HWND_DESKTOP, // display the text message in a HWND_DESKTOP, // message box. TextMessage[0], TextMessage[1], 0,MB_OK | MB_INFORMATION);

WinSetDlgItemText( hwnd, MyListBox, // display the text message in a TextMessage[2]); // dialog control (ex. listbox) - - - - - - - - - - - - - - - - - - - - }  ''Sample Code 3. MYFILE.C''

Once this is done, the executable's main source code simply calls upon the module handle (hmod) of the DLL to load and manipulate any of the resources that were once used statically.

Conclusion
Using the instructions I have provided, you can generate a series of DLLs that include different languages for use by people of different backgrounds. Just imagine if not only individual applications but operating systems worked this way. With a simple reboot, an end user could load a different language, color, or illustration.

By improving your application's ease of use, you'll show that you care about your customers. As a result, your application will not be shunned by those of other origins, but will flourish in the international marketplace.