Passion/Programming

MSDN - Localization of MFC Components

sunshout 2006. 11. 21. 20:46

TN057: Localization of MFC Components

This note describes some of the designs and procedures you can use tolocalize your component, be it an application or an OLE control, or aDLL which uses MFC.

Overview

There are really two issues to resolve when localizing a componentwhich uses MFC. First of all, you must localize your own resources ­strings, dialogs, and other resources that are specific to yourcomponent. Most components built using MFC also include and use anumber of resources that are defined by MFC. You must provide localizedMFC resources as well. Fortunately, several languages are alreadyprovided by MFC itself.

In addition, your component should be prepared to run in its targetenvironment (European, or DBCS enabled environment). For the most part,this depends on your application treating characters with the high bitset correctly and handling strings with double byte characters. MFC isenabled, by default, for both of these environments, such that it ispossible to have a single "world wide" binary that is used on allplatforms with just different resources plugged in at setup time.

Localizing your Component's Resources

Localizing your application or DLL should involve simply replacing theresources with resources that match the target language. For your ownresources, this is relatively simple: edit the resources in theresource editor and build your application. If your code is writtenproperly there will be no strings or text that you wish to localizehard-coded into your C++ source code ­ all localization can be done bysimply modifying resources. In fact, you can implement your componentsuch that all providing a localized version does not even involve abuild of the original code. This is more complex, but is well worth itand is the mechanism chosen for MFC itself. It is also possible tolocalize an application by loading the EXE or DLL file into theresource editor and editing the resources directly. While this ispossible, it is requires re-application of those changes each time youbuild a new version of your application.

One way to avoid that is to locate all resources in a separate DLL,sometimes called a satellite DLL. This DLL is then loaded dynamicallyat runtime and the resources are loaded from that DLL instead of fromthe main module with all your code. MFC directly supports thisapproach. Consider an application called MYAPP.EXE; it could have allof its resources located in a DLL called MYRES.DLL. In theapplication's InitInstance it would perform the following to load that DLL and cause MFC to load resources from that location:

CMyApp::InitInstance()
{
// one of the first things in the init code
HINSTANCE hInst = LoadLibrary("myres.dll");
if (hInst != NULL)
AfxSetResourceHandle(hInst);

// other initialization code would follow
.
.
.
}

From then on, MFC will load resources from that DLL instead of frommyapp.exe. All resources, however, must be present in that DLL ­ MFCwill not search the application's instance in search of a givenresource. This technique applies equally well to regular DLLs as wellas OLE Controls. Your setup program would copy the appropriate versionof MYRES.DLL depending upon which resource locale the user would like.

It is relatively easy to create a resource only DLL. You create a DLLproject, add your .RC file to it, and add the necessary resources. Ifyou have an existing project that does not use this technique, you cancopy the resources from that project. After adding the resource file tothe project you are almost ready to build the project. The only thingyou must do is set the linker options to include /NOENTRY. This tells the linker that the DLL has no entry point ­ since it has no code, it has no entry point.

Note   The resource editor in Visual C++ 4.0 and latersupports multiple languages per .RC file. This can make it very easy tomanage your localization in a single project. The resources for eachlanguage is controlled by preprocessor directives generated by theresource editor.

Using the Provided MFC Localized Resources

Any MFC application that you build re-uses two things from MFC: codeand resources. That is, MFC has various error messages, built-indialogs, and other resources that are used by the MFC classes. In orderto completely localize your application, you need to localize not onlyyour application's resources, but also the resources which comedirectly from MFC. MFC provides a number of different language resourcefiles automatically, so that if the language you are targeting is oneof the languages MFC already supports, you just need to make sure youuse those localized resources.

As of this writing MFC supports: Chinese, German, Spanish, French,Italian, Japanese, and Korean. The files which contain these localizedversions are in the MFC\INCLUDE\L.* (the '' stands for localized)directories. The German files are in MFC\INCLUDE\L.DEU, for example. Inorder to cause your application to use these RC files instead of thefiles located in MFC\INCLUDE, simply add a /IC:\PROGRAM FILES\DEVSTUDIO\VC\MFC\INCLUDE\L.DEUto your RC command line (this is just an example ­ you would need tosubstitute your locale of choice as well as the directory into whichyou installed Visual C++).

The above instructions will work if your application links staticallywith MFC. Most applications link dynamically (because that is theAppWizard default). In this scenario, not only the code is dynamicallylinked ­ so are the resources. As a result, you can localize yourresources in your application, but the MFC implementation resourceswill still be loaded from the MFC4x.DLL (or a later version) or fromMFC4xLOC.DLL if it exists. You can approach this from two differentangles.

Feature Only in Professional and Enterprise Editions   Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The more complex approach is to ship one of the localized MFC4xLOC.DLLs(such as MFC4xDEU, for German, MFC4xESP.DLL for Spanish, etc.), or alater version, and install the appropriate MFC4xLOC.DLL into the systemdirectory when the user installs your application. This can be verycomplex for both the developer and the end user and as such is notrecommended. See Technical Note 56 for more information on this technique and its caveats.

The simplest and safest approach is to include the localized MFCresources in your application or DLL itself (or its satellite DLL ifyou are using one). This avoids the problems of installing MFC4xLOC.DLLproperly. To do so, you follow the same instructions for the staticcase given above (setting the RC command line properly to point to thelocalized resources), except that you must also remove the /D_AFXDLL define that was added by AppWizard. When /D_AFXDLLis defined, AFXRES.H (and the other MFC RC files) don't actually defineany resources (because they will be pulled from the MFC DLLs instead).