This add-in demonstrates how to support multiple languages in a single XLL, using a resource file. The add-in will start with the language that matches the user's current regional settings in the Control Panel. The user can switch between languages using a menu.
For step-by-step instructions on how to convert an existing project to support multiple languages, see Conversion of an existing project in the User Guide.
The resource file InterSingle.rc contains two string tables, one in English (US) and one in French (France). It also contains two bitmaps, one for each language.
The global function ResListLanguages is used to get a list of all the languages supported by the resource file.
In contrast to a standard XLL, this one uses resources IDs such as #202 instead of strings wherever possible. These IDs represent strings held in the resource file. The XLL+ run-time libraries take care of loading the correct language version of the sting.
Resource IDs are used in the following places:
/* static */ LPCSTR CInterSingleApp::m_pszDefName = _T("#1");
m_menu.SetTexts(""#2"); m_menu.AddItem(""#3", "BuyWater");
// Create toolbar
CXlToolbar::AddToolbar(m_pszToolbarName);
CXlToolbar::AddTool(m_pszToolbarName, 1, "BuyWater", "#5");
CXlToolbar::SetToolBitmap(m_pszToolbarName, 1, IDB_BITMAP1);
CXlToolbar::ShowToolbar(m_pszToolbarName, true, CXlToolbar::DockRight);
//{{XLP_SRC(IntlFn) // NOTE - the FunctionWizard will add and remove mapping code here. // DO NOT EDIT what you see in these blocks of generated code! IMPLEMENT_XLLFN2(IntlFn, "RB", "IntlFn", "Price", "#201", "#202", "#204\000", "B#203#Price #204\0appscope=1\0comerroronxlerror" "=1\0comerrorstringprefix=#Error:\0", 1) extern "C" __declspec( dllexport ) LPXLOPER IntlFn(double Price) { XLL_FIX_STATE; CXlOper xloResult; //}}XLP_SRC xloResult = Price * 2.0; return xloResult.Ret(); }
(Notice that this string uses a hexadecimal string ID, prefixed with "0x", instead of a decimal ID. Either form can be used at any time.)CXllApp::XlMessageBox(XllGetTranslatedString("#0x0008"), XlMessageBoxTypeExclamation);
InitLanguageList() is called once, during OnXllOpenEx(), to initialize a list of languages supported by the XLL. The utility function ResListLanguages is used to get a list of all the languages supported by the resource file.
void CInterSingleApp::InitLanguageList() { ResListLanguages(XllGetStringResourceHandle(), m_languageIDs, LOCALE_SNATIVELANGNAME, m_languageNames); }
In order to change the language at run-time, you need to consider all the areas of behavior that are localized:
Normally much of this code is handled in the event handlers, OnXllOpenEx() and OnXllClose(), so that it is called when the add-in is opened or closed. In the add-in, the relevant code is removed from the event handlers and placed in RegisterLocalized() and UnregisterLocalized().
RegisterLocalized() handles all the creation tasks. Note that the first time it is called, it is not necessary to register the add-in functions themselves, since the XLL+ framework has already taken care of this. On later calls, the add-in functions have been unregistered (by UnregisterLocalized()) and need to be explicitly reregistered.
void CInterSingleApp::RegisterLocalized(BOOL bRegFunctions) { // Set up menu m_menu.SetTexts("#2"); m_menu.AddItem("#3", "BuyWater"); m_menu.AddItem("-", ""); // Separator for (size_t i = 0; i < m_languageNames.size(); i++) m_menu.AddItem(m_languageNames[i], "SelectLanguage"); m_menu.Create(); // Save position of 1st language menu item m_nFirstLanguageMenu = 3; // (Menu item positions are zero based) // Create toolbar CXlToolbar::AddToolbar(m_pszToolbarName); CXlToolbar::AddTool(m_pszToolbarName, 1, "BuyWater", "#5"); CXlToolbar::SetToolBitmap(m_pszToolbarName, 1, IDB_BITMAP1); CXlToolbar::ShowToolbar(m_pszToolbarName, true, CXlToolbar::DockRight); // Save actual toolbar name, for deregistration m_strToolbarNameUsed = ::XllGetTranslatedString(m_pszToolbarName); // Reregister functions using new texts if (bRegFunctions) RegisterFunctions(); } void CInterSingleApp::UnregisterLocalized() { // Delete menu m_menu.Destroy(); // Delete toolbar CXlToolbar::DeleteToolbar(m_strToolbarNameUsed); // Unregister functions UnregisterFunctions(); }
The program logic of switching languages is done handled by SetLanguageID(), using XllSetStringLanguageID():
void CInterSingleApp::SetLanguageID(LANGID langid) { UnregisterLocalized(); XllSetStringLanguageID(langid); RegisterLocalized(TRUE); }
::ResListLanguages |
::XllSetStringLanguageID |
::XllGetTranslatedString |
If you are using MS Developer Studio 6, then you should open the project file InterSingle.dsp.
If you are using MS Visual Studio .NET 2002, then you should open the solution file InterSingle.sln or the project file InterSingle.vcproj.
If you are using MS Visual Studio .NET 2003, then you should open the solution file InterSingle71.sln or the project file InterSingle71.vcproj.
If you are using MS Visual Studio 2005, then you should open the solution file InterSingle8.sln or the project file InterSingle8.vcproj.
List of Sample Projects
| Samples and Walkthroughs
| Localized (Multiple DLLs) sample