Resource DLLs and Language Selection Menu

Introduction

In today’s world, localization and translation of your software becomes an important feature because it dramatically helps boost sales. As far as Win32/MFC applications are concerned, managing different languages for your app requires using satellite DLLs.

This article describes a very easy-to-use method to support multiple languages in your C++/MFC applications. It shows how to add support for satellite DLLs (also known as resource DLLs) to your app by simply adding a few of lines of code. This includes:


  • Automatically selecting the most appropriate language at startup according to user preferences.

  • Providing a submenu for language selection (in case the user is not happy with the default choice). See the illustration.

It also explains how to create the satellite/resource DLLs, although this is already covered in many other articles. By the way, I am the developer of appTranslator, a localization tool that, among other things, can create the resource DLLs for you, freeing you from the hassle of managing Visual Studio projects for all these resource DLLs.

Background

There are a couple of articles on that deal with localization and resource DLLs. There is even one that shows a language menu, but this menu is hard-coded. My article describes an automated language menu that looks up the list of available languages and automatically builds the menu accordingly.

A Few Words about Resource DLLs

It is commonly accepted that the most flexible method to support multiple languages in your app is to use so-called Resource DLLs (also known as Satellite DLLs). The idea is to create one DLL per language. The DLL contains a copy of all your application resources translated into one given language. Therefore, if your app’s original version is English and you translate it to French, German, and Japanese, you’ll end up with three resource DLLs : The English resources stay in the .exe and there is one DLL for French, one for German, and one for Japanese.

Whenever you make a new translation of your app, you simply need to add one more DLL to your installer. At startup, the application decides which language it should use (according to user preferences) and loads the resource DLL accordingly.

Resource DLLs can be created by using a dedicated Visual Studio project. Better yet, they can be created by localization tools such as appTranslator. One nice thing about appTranslator is that the developer doesn’t have to worry about the creation and maintenance of resource DLLs: Just clicks the Build button and it creates them for you!

By the way, packing all languages into a single EXE is theoritically possible, but it just doesn’t work. That’ because most high-level APIs that load resources—such as LoadString(), DialogBox(), and so forth—won’t let you specify the language you want. SetThreadLocale() has stopped working the way you expect since Windows 2000 (and it never existed on Win9x).

The Step-by-step Method to Support Resource DLLs

Here’s the list of steps to add support for resource DLLs (a languages menu) in your main application.

  1. Add LanguageSupport.h and LanguageSupport.cpp to your project.
  2. In MyApp.h and MyApp.cpp (assuming CMyApp is your application class), add the lines shown in bold:
  3. #include "LanguageSupport.h"
    
    class CMyApp : public CWinApp
    {
    public:
       CLanguageSupport m_LanguageSupport;
       ...
    };
    
    BOOL CMyApp::InitInstance()
    {
       // Comment out this line to prevent MFC from doing its own
       // resource DLL processing. See explanation below.
       // CWinApp::InitInstance();
       ...
       // You have this line, don't you!
       SetRegistryKey(_T("MyCompany"));
    
       // Load the resource DLL according to user preferences
       m_LanguageSupport.LoadBestLanguage();
       ...
    }
    
  4. In your main menu, add a menu item labeled ‘Language‘. I usually add it in my Tools menu (if any), but it is up to you.
  5. In your CMainFrame class, add an update menu handler for the Language menu item. Assume you named it OnUpdateToolsLanguage(). Fill it as follows:
  6. void CMainFrame::OnUpdateToolsLanguage(CCmdUI *pCmdUI)
    {    // Note: This is the UPDATE_COMMAND_UI handler, not the
         // COMMAND handler!
    
       // Creates the languages submenu (only the first time the
       // menu is opened!)
       theApp.m_LanguageSupport.CreateMenu(pCmdUI);
    }
    
  7. Add the menu handler for the languages menu item:
  8. In MainFrm.h, add the handler declaration somewhere in the protected part of CMainFrame:
  9.  afx_msg void OnLanguage(UINT nID);

    In MainFrm.cpp, add the handler definition and its message map entry:

    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ...
    ON_COMMAND_RANGE(ID_LANGUAGE_FIRST,ID_LANGUAGE_LAST, OnLanguage)
    // These IDs are declared in LanguageSupport.h
    END_MESSAGE_MAP()
    
    void CMainFrame::OnLanguage(UINT nID)
    { // User selected a language in the language sub menu
      theApp.m_LanguageSupport.OnSwitchLanguage(nID);
    }
    
    

    Note: This handler cannot be added using the wizard because it is a command range menu handler: On handler for all languages items in the Language submenu.

  10. Last step:

    In the String Table (resources), add a string named IDS_RESTART with the text “Please restart %1”.

    Note: You can replace %1 by your app’s name.

How to Create the Resource DLLs

First of all, the CLanguageSupport class assumes the DLLs are named MyAppXXX.dll, where MyApp.exe is the name of your executable file and XXX is the three-letter acronym of the language they contain (for example, FRA stands for French, DEU for German, and JPN for Japanese). Also, both your EXE and the DLLs should have a Version Info resource whose language match the three-letter acronym in the file name.

The easiest way to create the DLL is to use appTranslator because the tool creates the dialog for you (you simply have to check ‘Satellite DLL‘ in the properties). But of course, I won’t assume that everyone uses my tool, so here’s the manual way to do it:


  • Create a Win32 DLL project: In Visual Studio 2003, choose File, New, Project…, enter a project name such as MyAppDEU to create a German version, and click OK. Then, on the Application Settings tab, select DLL and Empty Project.

  • Turn it into a resource DLL (also known as a Resource-only DLL or Satellite DLL): Open the project properties, select All Configurations in the configurations combobox, and then open the Linker, Advanced tab. Set Resource Only DLL to Yes.
  • Note to VC6 users: This setting does not exist in the VC6 project property pages. You must manually add /NOENTRY in the linker settings edit box with the command line settings.

  • Create a copy of your EXE resource file and add it to the DLL project: I recommend you rename your MyApp.rc file to MyAppDEU.rc (or whatever language acronym applies).

  • Modify your path: In the Resource View, right-click MyAppFRA.rc (MyAppFRA in Visual Studio 6) and open ‘Resource Includes…’. Modify the path/filename of all included resource files to include their translation. The MFC resources translations are stored in a sub-directory per language: l.xxx\ where xxx is the three-letter acronym of the language. For example, change #include “afxres.rc” to #include “l.deu\afxres.rc”.

  • Set the language properties: In the Resource View, open the version info (or create one if you don’t have one) and set the language property of the Block Header to the right language (for example, German (Germany)). Make sure the language matches the three-letter acronym used in the DLL name.

You now can compile the DLL. I suggest you edit the output settings of the DLL project to copy the file side-by-side with your main exe (in other words, in the same directory). You now have a resource DLL. Of course, it’s not translated yet but that’s the translator’s job. By the way, did I mention that I’m the author of a great localization tool that (among other things) completely handles the whole resource DLL creation process?

Start your app and open the Tools menu (or whatever menu where you created the Language item). The submenu should contain English and German.

Follow the same procedure to create DLLs for whatever other translations you need. Once your DLL is available, the only thing you need to do is copy it side by side with your app (.exe) and it will automatically be taken into account for language selection.

More by Author

Must Read