Globalization
Part_I

Search

References

  1. Multilingual User Interface (MUI)
  2. Writing Win32 MUI Application

A common question in the Smalltalk world is "how do I globalize my application".

Windows 2000 introduced MUI which was extended into Windows XP and will probably become a standard part of Windows Longhorn. So what is MUI?

"Windows Multi-language User Interface (MUI) includes resources for each supported UI language separated from their binaries and provided in separate language directories. The MUI allows users to set the user-interface language according to their preferences, provided the required language was added to the system. This allows large corporations to rollout the operating system worldwide, while allowing their local users or groups to select the UI language. It also allows users of different languages to share the same workstation: one user might choose to see system menus, dialog boxes, and other text in Japanese, while another user might choose to see the corresponding text in French."

Smalltalk MT has full support for MUI, and allows the user to develop an application that can show resources in different languages or to change languages on the fly.

There are several new APIs that help us.

Firstly, how do we determine the base language installed on the system (i.e. is this English windows or Spanish Windows). Language identifiers are 16 bits long and consist of 5 bits of sublanguage and 11 bits of primary language. To retrieve this try in a workspace:

WINAPI GetSystemDefaultLangID&0xFFFF

we have to mask the result with 0xFFFF to only look at the 16 bits of the LangID. To find the name of the system default language we can use:

result := String new: 30.
WINAPI GetLocaleInfo: LOCALE_SYSTEM_DEFAULT with: LOCALE_SLANGUAGE
    with: result basicAddress with: 30.

In my case the SystemDefaultLangID is 1033 and the name of this is 'English (United States)'.

Now how do we find all of the user interface languages that are supported on this system? This involves a callback so we cannot accomplish it all in a workspace. We need a class method containing the callback method. Why a class method? Because we need to pass a known address to the callback API. It is not that difficult. Create a class called Globalization. Add a class method in the .EXPORT category. To do this right click on the * on the class side and choose Add Category. Select the .EXPORT category and right click and select New Method. The Win32 API says the callback EnumUILanguagesProc has two parameters so create a method like this:

EnumUILanguagesProc: lpLocaleString param: lparam
"
    Callback procedure for showing UI languages available
"
    Processor outputDebugLine: 'LangID %s' _with: lpLocaleString.
    ^TRUE

Now we can call this callback procedure from our workspace.

WINAPI EnumUILanguages: (Globalization methodAddressAt: #EnumUILanguagesProc:param:)
    with: 0 with: 0

This will write out to the debug monitor the LangIDs of all the UI languages available on this system. These will be listed as hex strings which is not terribly useful since all of the other APIs need a numeric LangID. Luckily it is easy to convert these.

EnumUILanguagesProc: lpLocaleString param: lparam
"
Write out the UI languages available as strings
"
    |result localStr locale|

    localStr := String fromAddress: lpLocaleString.
    locale := ('0x',localStr) asHexInteger.

    result := String localNew: 100.
    WINAPI GetLocaleInfo: locale with: LOCALE_SLANGUAGE
        with: result basicAddress with: 100.
    Processor outputDebugLine: 'Lang %s' _with: result.

^TRUE

This will list the language names available. For example this lists for me:

STIMAGE.EXE TID=1704! Lang English (United States)
STIMAGE.EXE TID=1704! Lang French (France)
STIMAGE.EXE TID=1704! Lang German (Germany)
STIMAGE.EXE TID=1704! Lang Italian (Italy)
STIMAGE.EXE TID=1704! Lang Spanish (International Sort)
STIMAGE.EXE TID=1704! Lang Russian
STIMAGE.EXE TID=1704! Lang Portuguese (Portugal)

This is because I have MUI installed with a several languages for testing.