| By Jacek Furmankiewicz | Article Rating: |
|
| April 1, 2001 12:00 AM EST | Reads: |
121 |
Expanding into other language markets presents an ample challenge for any PowerBuilder shop. In my case, we were faced with internationalizing our existing sales audit application into French (we're based in Quebec, where French versions of applications are required by law), as well as UK English (there are enough differences in retail terminology between North America and England to make this necessary). Our European salespeople were also targeting clients in Germany and Spain and, realistically, we had to anticipate supporting more languages in the future.
Our application is fairly mature and quite large by now. Development started in early 1996 and the application now consists of over 55 PBLs with thousands of objects. Due to time pressures, we didn't design with internationalization in mind, and we faced the daunting task of designing an internationalization solution for our application that could be implemented in a realistic time frame by our fairly small PowerBuilder development team (six programmers). Also, it had to be easy to maintain and integrate well with the tools used by our translation team, who were also responsible for non-PowerBuilder applications (we have large Visual Basic and Visual C++ development teams for some of our other products).
The internationalization solution recommended by Sybase is to use the PowerBuilder Translation Toolkit (included since version 6.5, if I remember correctly), but after initial investigation we decided we needed to build our own custom solution. In a future article I'll focus on our internationalization solution; in this article I focus solely on the use of resource DLLs in PB.
Using Resource DLLs in PowerBuilder
Not knowing much about Visual Basic or Visual C++, I investigated their internationalization tools and it became apparent that they were all based on the usage of regular Windows resource DLLs (which, incidentally, is what Delphi uses). A Windows resource DLL can contain many different types of resources including graphics, video files, and text. Let your imagination run wild as to how you can use resource DLLs in your applications. In our case we were interested only in simple DLLs that stored string phrases identified by numeric resource IDs. In Windows it can be an unsigned integer, so you have up to 65,535 possible unique resource IDs within one DLL, which was more than enough for our needs.
As an added benefit, fetching string resources from a resource DLL is extremely fast. In my initial tests I was able to fetch over 100 resources from a DLL in less than 200ms. These tests made it clear that this method was preferred over any other we had considered (e.g., storing the phrases in the database or in a text file).
To efficiently use a resource DLL the following steps must be completed:
- The DLL has to be loaded into memory at startup time.
- String resources are fetched from it multiple times during the user's session.
- The DLL is unloaded from memory when the user shuts down the application.
In essence, to load a DLL into memory you need the following Windows API declaration (defined in PowerBuilder as an external local function):
Function Ulong LoadLibraryA (string lpLibFileName) Library "kernel32.dll"
This returns a variable of type unsignedlong, which is your handle to the loaded DLL.
To read a string from the loaded DLL you'll need the following API:
Function Int
LoadStringA(Ulong hInstance, Uint UiD, ref
string lpBuffer, int nBufferMax) Library "user32.dll"
The first variable is your unsignedlong handle to the DLL as returned by the initial LoadLibraryA. The next variable is your resource ID, the numeric identifier of the string phrase you're trying to retrieve, then a string variable (passed by reference) that will hold the retrieved text.
The last variable is the maximum size of the string you're expecting. We initially set this value to 255, but have run into some longer French phrases along the way and have now changed that to 512 characters.
To unload the DLL from memory you must use:
Function Boolean
FreeLibrary (Ulong hLibModule) Library "Kernel32.dll"
once again passing it the unsignedlong handle to your initially loaded DLL.
Listing 1 provides this entire process in PB code. It illustrates all the steps needed to load, fetch a resource, and unload a DLL from memory. Obviously, this is not how we would be using it in production, where the DLL is loaded once at startup, used repeatedly to fetch resources from during the user's session, and then unloaded from memory at the end when the application is shut down.
However, this listing clearly shows there's no magic in integrating resource DLLs into PowerBuilder; it's actually quite simple once you know which Windows APIs to use.
More important, there's no French-specific (or any language-specific) logic anywhere in this code. All you need to do to support a different language is load a different language DLL at runtime, depending on the user's preferences. In our application, we currently deploy three DLLs: one with phrases in U.S. English, one with UK English, and one with French. To support other languages we only need to create new DLLs with the translated descriptions and give the user the option to use that language at startup; that's it. As you can see, it's much simpler than the PowerBuilder Translation Toolkit approach of requiring different compilations of the EXE for each of the supported languages.
As an added benefit, the compiled resource DLLs are extremely small. We have over 6,000 phrases in our application (window titles, buttons, combo boxes, group boxes, messages, help, etc.); the English DLL is around 350KB and the French one is around 400KB. Therefore the impact on memory usage is negligible.
Creating Resource DLLs
Now that we know how to use resource DLLs in PowerBuilder, we're faced with the much tougher issue of how to create them. Most of the other Windows development tools (Visual Basic, Visual C++, Delphi) come with their own resource editors and compilers that allow them to create resource DLLs natively within their IDEs. PowerBuilder comes with neither of these, so we had to look at third-party tools.
The simplest solution would be to get a Visual Basic or Visual C++ license for each of the PowerBuilder developers, so they could create the resource files and compile them from within those tools. However, that seemed like a waste of money and no self-respecting PowerBuilder developer would be caught with a copy of Visual Basic on his or her PC (well, at least not before VB.Net arrived recently).
The first thing we needed to find was a (preferably free) C or C++ compiler that could turn resource files (which are simple ASCII text files) into DLLs. In our production environment we settled on using LCC-WIN32, a free, open-source C compiler maintained by Jacob Navia from France and available from www.cs.virginia.edu/~lcc-win32/.
Make sure you not only download the compiler installer (lccwin32.exe) with the manual, but also the documentation installer (lccdoc.exe). It's a command-line compiler that comes with a simple yet very capable IDE (and even includes a GUI builder).
At the very beginning we ran into some issues with the LCC-WIN32 resource compiler failing to compile strings larger than 255 characters (quite common for some of our French messages). What happened next made me a believer in open source. I contacted Jacob Navia about the problem around 5 p.m. EST via e-mail. Despite the time difference (France versus Canada), he had a fixed version for me the next morning. My congratulations go out to Jacob for providing such superb support for his tool.
Please refer to the sidebar, Installing and Setting Up LCC-WIN32, for a detailed list of the steps required to install LCC-WIN32 and set up a project in it that you can use to maintain resource strings and compile them into a DLL.
Seeing It All in Action
Please download the LANGUAGE.PBL from www.sys-con.com/pbdj/source.cfm. It contains the class N_CST_LANGUAGE in which all the required APIs are already set up for you. It also includes a small test application that prompts you to enter any of the two DLLs supplied (English.dll and Polish.dll, for example) and displays an internationalized window in whatever language the selected DLL was compiled in (see Figure 1).
Note that the test window doesn't contain any hard-coded internationalization logic; instead it's encapsulated in the ancestor visual objects (command button, label, multiline edit, etc.). They automatically translate themselves upon creation using a resource ID embedded in their text label. This simple approach allows you to visually enter resource IDs in the PowerBuilder GUI builder instead of coding them by hand, making the whole process faster and more productive.
Building an Internationalization Framework Based on Resource DLLs
In my next article I'll discuss creating an internationalization framework based on resource DLLs that takes care of translating all window controls and DataWindow objects, as well as resizing them dynamically at runtime to properly display internationalized text regardless of its length (which varies from language to language). It will also cover the differences between resizing regular window controls and DataWindow elements, which require a totally different approach due to the Windows APIs that are involved. I'll also cover the coding and layout issues involved in developing internationalized applications as well as a few obscure PowerBuilder issues you need to be aware of in order to deliver a professional, polished product. Currently, we are successfully using such a framework in production, supporting three different languages with more to come.
Summary
To recap, you've now seen how to use resource DLLs in PowerBuilder code and how to create them using the LCC-WIN32 Wedit IDE. In other words, you have everything you need to start fully integrating resource DLLs into your application and using them as a primary means of internationalization. Again, that's just one use for resource DLLs. Now that you know how to create and use them, you have another powerful tool to add to your application development toolkit.
Stay tuned and happy internationalization!
SIDEBAR
Installing and Setting Up LCC-WIN32
1. Install LCC-WIN32 using the installer EXE. I recommend installing into the default directory (usually "C:\lcc") to avoid installing into a directory with spaces embedded in its name.
2 After installing, start up the lcc-win IDE (Wedit) using the shortcut in Start-->Programs-->lcc-win32.
3. After Wedit starts up, create a new project using File-->New--> Project....
4. Choose a project name.
5. Define the project properties (namely, the source directory in which you want your files to be compiled). Be sure to select the "Type of Project" as "Dynamic Link Library (dll)".
6. When prompted whether to create an application skeleton, select "Yes."
7. Wedit displays a summary of the options for your project. Please note the "Resource file" field at the bottom. It's the actual resource file we'll be maintaining and then compiling into a DLL.
8. You're then prompted for the default compiler settings; select "OK" to accept them.
9. Select "OK" to accept the default linker settings.
10. Select "Finish" to accept the default debugger settings and complete the wizard. This will create the stub C code necessary to compile a DLL. No other C coding on our part is required; Wedit makes the entire process very simple.
11. Create a resource file within the project using the Design--> Open/New... menu option and then type in the required name of the resource file (it can be anything you want, but I keep it the same as the project name). This opens the Wedit resource editor, which can be used to create all types of resources, not just strings. This editor is geared more toward creating dialogs, menus, etc., but you'll only be using it to maintain the string table of all phrases you want to internationalize. To accomplish that, change a few of the default resource settings.
12. Invoke the Design-->Output menu option, which pops up the output options dialog. Make sure the "RC ASCII resource file (.rc)" option is set up and flagged as "Generate," as in Figure 2. Select "Validate" to save the settings.
13.Our next step is the actual creation of a string resource. To accomplish this we need to go to Design-->New-->strings. This opens the String Table editor where we can finally start entering string phrases with the resource IDs that identify them.
14. To start adding strings, select the "Add" action on the right-hand side of the window, which prompts you for the resource string to enter as well as its ID (see Figure 3).
The "Value" field is the resource ID; the "Content" field is the actual string phrase. Selecting "OK" saves the value to the resource file. Using this resource editor we can add all the string phrases required by our application.
15. After you're finished, select "Save" to save your changes to the file. Obviously, you can reopen the same resource file later from within Wedit and add any new phrases that you might need later.
16. To let LCC-WIN32 know that this resource file needs to be compiled with the DLL, you need to add it to the project. This is a one-time action that you need to perform only after creating the file for the first time. It can be accomplished via the Project-->Add/Delete Files... menu option, which in turns brings up the dialog box shown in Figure 4, where you can add the newly created *.RC file to the project.
Simply select the "Add" button and select your *.RC file. Select the "Validate" button when you're finished.
17. At this point we already have a base C project and a base resource file in which we can keep adding new strings. To compile both of them into a DLL we simply need to invoke the Compiler-->Compile "project_name.c" option. This compiles the DLL and makes it ready for you to use in your PowerBuilder application. The compiled DLL is located in the "\lcc" subdirectory of your project's base directory.
Published April 1, 2001 Reads 121
Copyright © 2001 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Jacek Furmankiewicz
Jacek Furmankiewicz is a PowerBuilder R&D supervisor at the Montreal office of STS Systems, an NSB company. His team is responsible for developing applications for some of the largest retailers in North America and Europe. Jacek has been using PowerBuilder since version 4.0 in Sybase, Oracle, and Microsoft SQL Server environments.
- Why SOA Needs Cloud Computing - Part 1
- Cloud Expo and The End of Tech Recession
- The Transition to Cloud Computing: What Does It Mean For You?
- A Rules Engine Built in PowerBuilder
- Sybase Named “Silver Sponsor” of iPhone Developer Summit
- How PowerBuilder Got Its Groove Back
- The Cloud Has Cross-Border Ambitions
- Ulitzer Names The World's 30 Most Influential Virtualization Bloggers
- Ulitzer Named "New Media" Partner of Greatly Anticipated iStrategy Event in Berlin
- Risks and Enterprise Mobility?
- Steps for Success in Enterprise Mobility?
- Are Mobile Luddites Resisting Mobility?
- The Difference Between Web Hosting and Cloud Computing
- Sybase CTO to Speak at 4th International Cloud Computing Expo
- Why SOA Needs Cloud Computing - Part 1
- Cloud Expo and The End of Tech Recession
- The Transition to Cloud Computing: What Does It Mean For You?
- Five Reasons to Choose a Private Cloud
- Seeding The Cloud: The Future of Data Management
- The Threat Behind the Firewall
- Economy Drives Adoption of Virtual Lab Technology
- Tips for Efficient PaaS Application Design
- A Rules Engine Built in PowerBuilder
- Sybase Named “Silver Sponsor” of iPhone Developer Summit
- Where Are RIA Technologies Headed in 2008?
- PowerBuilder History - How Did It Evolve?
- The Top 250 Players in the Cloud Computing Ecosystem
- Custom Common Dialogs Using SetWindowsHookEx
- DDDW Tips and Tricks
- OLE - Extending the Capabilities of PowerBuilder
- DataWindow.NET How To: Data Entry Form
- Book Excerpt: Sybase Adaptive Server Anywhere
- Sybase ASE 12.5 Performance and Tuning
- Working with SOA & Web Services in PowerBuilder
- Office 2003 Toolbar: A New Look For Your Old PowerBuilder App
- Dynamically Creating DataWindow Objects
































