Introduction
I have read a lot of good articles on CodeProject. Now it's time for me to provide one. Please leave any comment or suggestion you may have. All are welcome and greatly appreciated. I do want to get your feedback on this implementation of multiple language support. Following requirements have been made for this implementation of multiple language support for MFC applications with MFC extension DLL:
- Supporting one more language should not require changing the code any more unless there is some kind of hard-code in the previous code. You should remove all hard coding. E.g. all message strings should come from resources, not hardcoded in CPP / H files.
- Supporting one more language only needs to be dealt with resource files - *.rc and res/*.* files only. This means you can provide the resource file to anyone, and they can build resource-only DLLs for a new language without access to your code. Their new language DLL files should work with your application.
- Each existing MFC EXE / DLL file has one resource-only language DLL file for each language. Resource-only language DLL file is named after its application; appended iwth three-letter language abbreviation codes. It uses DLL as suffix.
- Existing EXE / DLLs have the choice to store resources or not. If no other language DLL exists, it searches the system default fake language �LOC�. If that fails, it uses the resource stored in EXE / DLL file, if any.
- Resource-only language DLL files stay with MFC application in the same folder.
- Use Control Panel settings in user�s OS to determine which language DLL to load to memory.
- Easily change to existing VC6 code to make it support the above features for multiple languages. Change a few codes in
InitInstance()
/ExitInstance()
and DllMain()
and that should be enough.
This document is for Visual Studio 6, may be version 5, but not for version 7, 7.1, 8.0. MFC version 7 has some built-in support for multiple languages. This article includes the following:
- How to build resource-only language DLLs.
- How to detect OS language settings, how to load resource-only language DLLs when application starts.
- Three-letter language table.
Why another Article on Multiple Language Applications
I have read some articles here at CodeProject and Microsoft:
From VC7 and up, you shouldn't worry that much on multiple language support.
I wrapped some language related functions to a class. I made some changes for VC6, and put a demo project using it. You need to exit and launch your application again for a new language selected in the Control Panel.
Make a Sample MFC Application and its Extension DLL
- Using MFC AppWizard, make a MFC application. I chose "single document", "German [German] (APPWZDEU.DLL)", "Header files only" for database support, etc. and named it as Main. Press F7 to build it and run it.
- In FileView, right click workspace and add a MFC AppWizard (DLL) project. Name it as SubDLL. Choose "MFC Extension DLL (Using shared MFC DLL)".
- To avoid resource ID conflict, using main's resource.h, delete SubDLL's resource.h and replace it in ResourceView. Backup Main's resource.h before it be overwritten in this process, since there is no resource in SubDLL now. You are safe to restore it back after it is saved. Now Main.Exe and SubDLL.DLL share one resource.h. To make life easier, you can change the output SubDLL.dll to the same folder as Main.exe, and make Main dependent on SubDll.dll in Project Dependencies.
- Now add a dialog to SubDLL and call it from Main. Export this new dialog class by adding
AFX_EXT_CLASS
in the class definition header file. In Main, add a new menu item to run this test dialog. Sure, you need to include main.h or resource.h in TestDlg.cpp, and include TestDlg.h in MainFrame.cpp.
- Build them, run Main.exe, and test this TestDlg. Yes, we got our sample MFC application and MFC extension DLL working now.
- Optional, add Unicode configuration to this project. Add new configuration from Build / Configurations menu, get new configuration by copying it from the existing release and debug versions, change
_MBCS
to _UNICODE
at C/C++ tab in project settings dialog, change Entry-point symbol at output category of Link tab to wWinMainCRTStartup
. You need do this for Main and SubDLL, Release and Debug.
- Notes on MFC AppWizard Language Support for East Asian Languages:
Visual C++ allows you to choose different languages when you create an MFC AppWizard program. The East Asian language support DLLs (Japanese, Korean, and simplified Chinese) for the MFC AppWizard, which require double-byte enabled operating systems, are not installed by default. Thus you will not see them in the language drop-down list on the first page of the MFC AppWizard. However, you can find them in the Microsoft Visual Studio\Common\msdev98\bin\ide directory on the Visual C++ CD as follows:
Language |
AppWizard DLL |
Japanese |
APPWZJPN.DLL |
Korean |
APPWZKOR.DLL |
Chinese (simplified) |
APPWZCHS.DLL |
To take advantage of East Asian language support:
- Copy the appropriate MFC AppWizard DLL to your Microsoft Visual Studio\Common\msdev98\bin\ide directory. This DLL can be found in the corresponding directory on the Visual C++ CD.
- Install the appropriate code page on your system.
If your application is dynamically linked to MFC, you must have the corresponding localized version of the MFC resource DLL, MFC##LOC.DLL, in your Windows system directory. To do this, copy the corresponding DLL in the MFC\include\L.XXX\MFC##XXX.DLL on the Visual C++ CD into the Windows system directory, and rename it to MFC##LOC.DLL. For more information on using the localized resources that Visual C++ provides, see Tech Note 56 and Tech Note 57.
� or�
If your application is statically linked to MFC, you must have the appropriate localized MFC resource files in your MFC\[src|include]\L.XXX\*.rc directory. You can find these files in the corresponding directories of Visual Studio CD1. For more information on using the localized resources that Visual C++ provides, see Tech Note 56 and Tech Note 57.
Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.
Build Resource-only Language DLL
Now build English resource only DLL files for Main.exe and subdll.dll. A resource-only DLL is a DLL that contains nothing but resources, such as icons, bitmaps, strings, and dialog boxes. It is also a good way to provide an application with resources localized for multiple languages. See �Creating a Resource-Only DLL� (1.) in MSDN. Here are the steps to build a resource-only language DLL. It's named after its EXE or DLL, appending the three-letter language code. E.g. Main.exe has its English resource DLL as MainENU.DLL. Following are the steps to build English (ENU) resource-only language DLL from the previous German (DEU) code.
- Copy Main.rc to MainENU.rc.
- Copy resENU\*.* to resENU\*.*.
- Use a text editor to edit MainENU.rc and replace the following:
- All word "
AFX_TARG_DEU
" to "AFX_TARG_ENU
".
- All word "
LANG_GERMAN, SUBLANG_GERMAN
" to "LANG_ENGLISH, SUBLANG_ENGLISH_US
".
- The same as above "LANGUAGE 7, 1" to "LANGUAGE 9, 1". (
LANG_ENGLISH
is 9, LANG_GERMAN
is 7; both sublanguages are 1.)
- Take out "
l.deu\\
" or "l.deu\
" for English. For language other than English, use �l.xxx� subfolder to locate the MFC resource for that language. xxx
is the three-letter language code. See tables below.
- Change "
res\
" to "resENU\
".
VERSIONINFO
block from "040704B0" to "040904B0" - "7" for German and "9" for English.
- The same "407" to "409".
- "German (Germany)" to "English (U.S.)".
- "code_page(1252)" to "code_page(1252)". No need to change code page for this case. (Otherwise, you may need to update codepage based on �Code-Page Identifiers� (2.)) Keep in mind only some code pages are supported by Windows. See �Code Pages Supported by Windows� (7.).
- Translate all resources in MainENU.rc to English.
- Translate all resources in resENU\*.* to English.
- In FileView, right click workspace, add a �Win32 Dynamic-Link Library� project, name it as MainENU, and put it to the same location as Main. Select "An empty DLL project" in the wizard.
- Add the resource file MainENU.rc to this project's source files.
- Change the setting for the project MainENU, select Link tab in Project Settings dialog. Highlight this project, add "/NOENTRY" for both release and debug configurations.
- Optionally update intermediate and output files folder as the same as Main project. This can be done under General tab and Link tab.
- Under Resources tab change Language to English (United States).
- Build this project, you should get MainENU.DLL.
Detect OS UI Language settings
For MUI (Multiple User Interface) OS, a user can update his OS user language in Control Panel, Region and language options, Language. Following code is partially copied from VC7.1 appcore.cpp. It detects UI language, and stores a language list for loading later.
LANGID CMultiLanguage::DetectUILanguage()
{
LANGID langid = 0;
int nPrimaryLang = 0;
int nSubLang = 0;
LCID lcid = 0;
PFNGETUSERDEFAULTUILANGUAGE pfnGetUserDefaultUILanguage;
PFNGETSYSTEMDEFAULTUILANGUAGE pfnGetSystemDefaultUILanguage;
HINSTANCE hKernel32;
hKernel32 = ::GetModuleHandle(_T("kernel32.dll"));
ASSERT(hKernel32 != NULL);
pfnGetUserDefaultUILanguage =
(PFNGETUSERDEFAULTUILANGUAGE)::GetProcAddress(hKernel32,
"GetUserDefaultUILanguage");
if(pfnGetUserDefaultUILanguage != NULL)
{
langid = pfnGetUserDefaultUILanguage();
AddLangId( langid );
TRACE(_T("CMultiLanguage::DetectUILanguage()"
_T" 1st/2nd = %04X\n"), langid );
pfnGetSystemDefaultUILanguage =
(PFNGETSYSTEMDEFAULTUILANGUAGE)::GetProcAddress(hKernel32,
"GetSystemDefaultUILanguage");
ASSERT( pfnGetSystemDefaultUILanguage != NULL );
langid = pfnGetSystemDefaultUILanguage();
AddLangId( langid );
TRACE(_T("CMultiLanguage::DetectUILanguage()"
_T" 3rd/4th = %04X\n"), langid );
}
else
{
if (::GetVersion()&0x80000000)
{
HKEY hKey = NULL;
LONG nResult = ::RegOpenKeyEx(HKEY_CURRENT_USER,
_T( "Control Panel\\Desktop\\ResourceLocale" ),
0, KEY_READ, &hKey);
if (nResult == ERROR_SUCCESS)
{
DWORD dwType;
TCHAR szValue[16];
ULONG nBytes = sizeof( szValue );
nResult = ::RegQueryValueEx(hKey, NULL, NULL, &dwType,
LPBYTE( szValue ), &nBytes );
if ((nResult == ERROR_SUCCESS) && (dwType == REG_SZ))
{
DWORD dwLangID;
int nFields = _stscanf( szValue, _T( "%x" ), &dwLangID );
if( nFields == 1 )
{
langid = LANGID( dwLangID );
AddLangId( langid );
TRACE(_T("CMultiLanguage::DetectUILanguage()"
_T" 9X1st/2nd = %04X\n"), langid );
}
}
::RegCloseKey(hKey);
}
}
else
{
HMODULE hNTDLL = ::GetModuleHandle( _T( "ntdll.dll" ) );
if (hNTDLL != NULL)
{
langid = 0;
::EnumResourceLanguages( hNTDLL, RT_VERSION, MAKEINTRESOURCE( 1 ),
_AfxEnumResLangProc,
reinterpret_cast< LONG_PTR >( &langid ) );
if (langid != 0)
{
AddLangId( langid );
TRACE(_T("CMultiLanguage::DetectUILanguage()"
_T" NT1st/2nd = %04X\n"), langid );
}
}
}
}
if ( m_nLocales < MAX_NUM_LCID )
{
m_alcidSearch[m_nLocales] = LOCALE_SYSTEM_DEFAULT;
m_nLocales++;
} else {
m_alcidSearch[MAX_NUM_LCID-1] = LOCALE_SYSTEM_DEFAULT;
m_nLocales = MAX_NUM_LCID;
}
return LANGIDFROMLCID(m_alcidSearch[0]);
}
While the above code works for MUI OS, a user may change the default locale, not the UI language. The following code detects the user default language, not the UI language.
LANGID CMultiLanguage::DetectLangID()
{
LANGID langid = 0;
int nPrimaryLang = 0;
int nSubLang = 0;
LCID lcid = 0;
int nLocales = 0;
langid = GetUserDefaultLangID();
AddLangId( langid );
TRACE(_T("CMultiLanguage::GetUserDefaultLangID() 1st/2nd = %0X\n"),
langid );
LANGID langSysid = GetSystemDefaultLangID();
AddLangId( langSysid );
TRACE(_T("CMultiLanguage::GetSystemDefaultLangID() 3rd/4th = %0X\n"),
langid );
return langid;
}
We can get user selected languages in the OS now. I tested these only on Win200 Pro and WinXP Pro. If you can test this on 9X or NT, let me know if this failed or succeeded.
Load Language Resource DLL
Like that in MFC version 7, we attempt to load the resource DLL for each of the following languages in order, stopping when it finds one:
- The current user's default language, as returned from the
GetUserDefaultLangID()
Win32 API.
- The current user's default language, without any specific sublanguage (that is, ENC [Canadian English] becomes ENU [U.S. English]).
- The system's default language, as returned from the
GetSystemDefaultLangID()
Win32 API.
- The system's default language, without any specific sublanguage.
- (Windows 2000 or later only) The current user's default UI language, as returned from the
GetUserDefaultUILanguage()
Win32 API.
- (Windows 2000 or later only) The current user's default UI language, without any specific sublanguage.
- The system's default UI language. On Windows 2000 or higher, this is returned from the
GetSystemDefaultUILanguage()
API. On other platforms, this is the language of the OS itself.
- The system's default UI language, without any specific sublanguage.
- A "fake" language with the 3-letter code LOC.
To detect the user�s default language and system default language, we should make a call to DetectLangID()
. For user and system�s UI language, calling DetectUILanguage()
will be OK. After these two calls, a list of languages requested is stored in the CMultiLanguage::m_alcidSearch[]
array. To load it, use the following:
HINSTANCE CMultiLanguage::LoadLangResourceDLL(LPCTSTR szModuleName,
LANGID langUpdateId)
{
TCHAR szResDLLName[_MAX_PATH+14];
HINSTANCE hLangDLL = NULL;
LCID alcid[MAX_NUM_LCID+1];
TCHAR szLangCode[4];
int nNoExtension;
LCID lcid;
int nLocales = 0;
nNoExtension = lstrlen(szModuleName) - 3 ;
if ( langUpdateId != MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL) )
{
alcid[nLocales] = MAKELCID(langUpdateId, SORT_DEFAULT);
nLocales++;
}
for ( int iLocale = 0; iLocale < m_nLocales; iLocale++ )
{
if ( m_alcidSearch[iLocale] != 0 )
{
alcid[nLocales] = m_alcidSearch[iLocale];
nLocales++;
}
}
for ( iLocale = 0; iLocale < nLocales; iLocale++ )
{
lcid = alcid[iLocale];
if (lcid == LOCALE_SYSTEM_DEFAULT)
lstrcpy(szLangCode, _T("LOC"));
else {
int nResult = ::GetLocaleInfo(lcid,
LOCALE_SABBREVLANGNAME, szLangCode, 4);
ASSERT( nResult == 4 );
if ( nResult == 0 )
return NULL;
}
if ( nNoExtension + 3 + 4 + 1 < _MAX_PATH+14 )
{
lstrcpyn(szResDLLName, szModuleName, nNoExtension);
lstrcat(szResDLLName, szLangCode);
lstrcat(szResDLLName, _T(".DLL"));
} else {
ASSERT(FALSE);
return NULL;
}
hLangDLL = ::LoadLibrary(szResDLLName);
if(hLangDLL != NULL)
return hLangDLL;
}
return hLangDLL;
}
We can call LoadLangResourceDLL(�)
to load the first available language DLL in the list. You can change the language ID detected from above. For example, you only include the resource DLL for Chinese PRC, and you want to use it for Chinese Taiwan and Chinese Singapore too. You can do this hard-coding here. If you don't want to hard code here, you can make a duplicated copy of the resource-only DLL file with another three-letter language name. (Copy XXXXCHS.DLL to XXXXCHT.DLL for this case.)
If your EXE or DLL files don't include resource, you need to have one system default language "LOC" in your resource-only language DLL file list. This is the last chance the system will try to find the language resource.
Application Code Changes
For Main.exe to load a language related resource-only DLL, add the following code to main.cpp in the very beginning of CMain::InitInstance()
:
if ( CMultiLanguage::m_nLocales <= 0 )
{
CMultiLanguage::DetectLangID();
CMultiLanguage::DetectUILanguage();
}
TCHAR szModuleFileName[MAX_PATH];
int ret = ::GetModuleFileName(theApp.m_hInstance, szModuleFileName, MAX_PATH);
if ( ret == 0 || ret == MAX_PATH )
ASSERT(FALSE);
ghLangInst = CMultiLanguage::LoadLangResourceDLL( szModuleFileName );
if (ghLangInst)
AfxSetResourceHandle( ghLangInst );
You may want to free the library in ExitInstance()
.
DLL Code Changes
For the MFC extension DLL SubDLL.DLL to load language related resource-only DLL, add the following code to SubDLL.cpp in DllMain(...)
just before calling CDynLinkLibrary(...)
:
if ( CMultiLanguage::m_nLocales <= 0 )
{
CMultiLanguage::DetectLangID();
CMultiLanguage::DetectUILanguage();
}
TCHAR szModuleFileName[MAX_PATH];
int ret = ::GetModuleFileName(hInstance, szModuleFileName, MAX_PATH);
if ( ret == 0 || ret == MAX_PATH )
ASSERT(FALSE);
shLangInst = CMultiLanguage::LoadLangResourceDLL( szModuleFileName );
if (shLangInst)
SubDLLDLL.hResource = shLangInst;
You may want to free the library when system detaches the process.
Using the Software
- Include MultiLanguage.cpp and MultiLanguage.h in your project. With dependence, put this to the most independent DLL project.
- Use *.rc, res\*.* to build your resource-only DLL file for each EXE / DLL and each language. See "Build resource-only language DLL" above.
- Load language resource-only DLL in your MFC application as "Application Code Changes" above.
- Load language resource-only DLL in your MFC extension DLL as described in "DLL Code Changes" above for each extension DLL project.
- If you have only one EXE file, you can forget all extension related issues here.
- It�s better to detect language once and use it everywhere, so I put this as static. FYI:
DetectUILanguage()
function in DLLMain(...)
will be called earlier than that in InitInstance()
.
- Bugs are expected. This is only demo level code. You can report any bugs here or send an email to me with [codeproject] in the Subject line.
Three-letter Language Identifier Table
Column one is LANGID
; the lower 10 bits are for the language, the higher 6 bits are for the sub-language. Column two is the three-letter language code. Column three is the three-letter language code without sub-language. It looks for this language if the language in column two does not exist. Column one and column four are got from �Language Identifier�(3.); column two and column three are got from the GetLocaleInfo()
function on my XP Pro PC. See CMultiLanguage::PrintThreeLetterLanguageCodeList()
function in MultiLanguage.cpp for details.
Identifier |
Column 2 |
Column 3 |
Description and notes |
0x0436 |
AFK |
AFK |
Afrikaans |
0x041c |
SQI |
SQI |
Albanian |
0x0401 |
ARA |
ARA |
Arabic (Saudi Arabia) |
0x0801 |
ARI |
ARA |
Arabic (Iraq) |
0x0c01 |
ARE |
ARA |
Arabic (Egypt) |
0x1001 |
ARL |
ARA |
Arabic (Libya) |
0x1401 |
ARG |
ARA |
Arabic (Algeria) |
0x1801 |
ARM |
ARA |
Arabic (Morocco) |
0x1c01 |
ART |
ARA |
Arabic (Tunisia) |
0x2001 |
ARO |
ARA |
Arabic (Oman) |
0x2401 |
ARY |
ARA |
Arabic (Yemen) |
0x2801 |
ARS |
ARA |
Arabic (Syria) |
0x2c01 |
ARJ |
ARA |
Arabic (Jordan) |
0x3001 |
ARB |
ARA |
Arabic (Lebanon) |
0x3401 |
ARK |
ARA |
Arabic (Kuwait) |
0x3801 |
ARU |
ARA |
Arabic (U.A.E.) |
0x3c01 |
ARH |
ARA |
Arabic (Bahrain) |
0x4001 |
ARQ |
ARA |
Arabic (Qatar) |
0x042b |
HYE |
HYE |
Windows 2000/XP: Armenian. This is Unicode only. |
0x042c |
AZE |
AZE |
Azeri (Latin) |
0x082c |
AZE |
AZE |
Azeri (Cyrillic) |
0x042d |
EUQ |
EUQ |
Basque |
0x0423 |
BEL |
BEL |
Belarusian |
0x0445 |
BNG |
BNG |
Bengali (India) |
0x141a |
BSB |
HRV |
Bosnian (Bosnia and Herzego vina) |
0x0402 |
BGR |
BGR |
Bulgarian |
0x0455 |
=== |
=== |
Burmese |
0x0403 |
CAT |
CAT |
Catalan |
0x0404 |
CHT |
CHT |
Chinese (Taiwan) |
0x0804 |
CHS |
CHT |
Chinese (PRC) |
0x0c04 |
ZHH |
CHT |
Chinese (Hong Kong SAR, PRC ) |
0x1004 |
ZHI |
CHT |
Chinese (Singapore) |
0x1404 |
ZHM |
CHT |
Windows 98/ME, Windows 2000 /XP: Chinese (Macao SAR) |
0x041a |
HRV |
HRV |
Croatian |
0x101a |
HRB |
HRV |
Croatian (Bosnia and Herzeg ovina) |
0x0405 |
CSY |
CSY |
Czech |
0x0406 |
DAN |
DAN |
Danish |
0x0465 |
DIV |
DIV |
Windows XP: Divehi. This is Unicode only. |
0x0413 |
NLD |
NLD |
Dutch (Netherlands) |
0x0813 |
NLB |
NLD |
Dutch (Belgium) |
0x0409 |
ENU |
ENU |
English (United States) |
0x0809 |
ENG |
ENU |
English (United Kingdom) |
0x0c09 |
ENA |
ENU |
English (Australian) |
0x1009 |
ENC |
ENU |
English (Canadian) |
0x1409 |
ENZ |
ENU |
English (New Zealand) |
0x1809 |
ENI |
ENU |
English (Ireland) |
0x1c09 |
ENS |
ENU |
English (South Africa) |
0x2009 |
ENJ |
ENU |
English (Jamaica) |
0x2409 |
ENB |
ENU |
English (Caribbean) |
0x2809 |
ENL |
ENU |
English (Belize) |
0x2c09 |
ENT |
ENU |
English (Trinidad) |
0x3009 |
ENW |
ENU |
Windows 98/ME, Windows 2000 /XP: English (Zimbabwe) |
0x3409 |
ENP |
ENU |
Windows 98/ME, Windows 2000 /XP: English (Philippines) |
0x0425 |
ETI |
ETI |
Estonian |
0x0438 |
FOS |
FOS |
Faeroese |
0x0429 |
FAR |
FAR |
Farsi |
0x040b |
FIN |
FIN |
Finnish |
0x040c |
FRA |
FRA |
French (Standard) |
0x080c |
FRB |
FRA |
French (Belgian) |
0x0c0c |
FRC |
FRA |
French (Canadian) |
0x100c |
FRS |
FRA |
French (Switzerland) |
0x140c |
FRL |
FRA |
French (Luxembourg) |
0x180c |
FRM |
FRA |
Windows 98/ME, Windows 2000 /XP: French (Monaco) |
0x0456 |
GLC |
GLC |
Windows XP: Galician |
0x0437 |
KAT |
KAT |
Windows 2000/XP: Georgian. This is Unicode only. |
0x0407 |
DEU |
DEU |
German (Standard) |
0x0807 |
DES |
DEU |
German (Switzerland) |
0x0c07 |
DEA |
DEU |
German (Austria) |
0x1007 |
DEL |
DEU |
German (Luxembourg) |
0x1407 |
DEC |
DEU |
German (Liechtenstein) |
0x0408 |
ELL |
ELL |
Greek |
0x0447 |
GUJ |
GUJ |
Windows XP: Gujarati. This is Unicode only. |
0x040d |
HEB |
HEB |
Hebrew |
0x0439 |
HIN |
HIN |
Windows 2000/XP: Hindi. This is Unicode only. |
0x040e |
HUN |
HUN |
Hungarian |
0x040f |
ISL |
ISL |
Icelandic |
0x0421 |
IND |
IND |
Indonesian |
0x0434 |
XHO |
XHO |
isiXhosa/Xhosa (South Africa) |
0x0435 |
ZUL |
ZUL |
isiZulu/Zulu (South Africa) |
0x0410 |
ITA |
ITA |
Italian (Standard) |
0x0810 |
ITS |
ITA |
Italian (Switzerland) |
0x0411 |
JPN |
JPN |
Japanese |
0x044b |
KAN |
KAN |
Windows XP: Kannada. This is Unicode only. |
0x0457 |
KNK |
KNK |
Windows 2000/XP: Konkani. This is Unicode only. |
0x0412 |
KOR |
KOR |
Korean |
0x0812 |
=== |
KOR |
Windows 95, Windows NT 4.0 only: Korean (Johab) |
0x0440 |
KYR |
KYR |
Windows XP: Kyrgyz. |
0x0426 |
LVI |
LVI |
Latvian |
0x0427 |
LTH |
LTH |
Lithuanian |
0x0827 |
=== |
LTH |
Windows 98 only: Lithuanian (Classic) |
0x042f |
MKI |
MKI |
Macedonian (FYROM) |
0x043e |
MSL |
MSL |
Malay (Malaysian) |
0x083e |
MSB |
MSL |
Malay (Brunei Darussalam) |
0x044c |
MYM |
MYM |
Malayalam (India) |
0x0481 |
MRI |
MRI |
Maori (New Zealand) |
0x043a |
MLT |
MLT |
Maltese (Malta) |
0x044e |
MAR |
MAR |
Windows 2000/XP: Marathi. This is Unicode only. |
0x0450 |
MON |
MON |
Windows XP: Mongolian |
0x0414 |
NOR |
NOR |
Norwegian (Bokmal) |
0x0814 |
NON |
NOR |
Norwegian (Nynorsk) |
0x0415 |
PLK |
PLK |
Polish |
0x0416 |
PTB |
PTB |
Portuguese (Brazil) |
0x0816 |
PTG |
PTB |
Portuguese (Portugal) |
0x0446 |
PAN |
PAN |
Windows XP: Punjabi. This is Unicode only. |
0x046b |
QUB |
QUB |
Quechua (Bolivia) |
0x086b |
QUE |
QUB |
Quechua (Ecuador) |
0x0c6b |
QUP |
QUB |
Quechua (Peru) |
0x0418 |
ROM |
ROM |
Romanian |
0x0419 |
RUS |
RUS |
Russian |
0x044f |
SAN |
SAN |
Windows 2000/XP: Sanskrit. This is Unicode only. |
0x043b |
SME |
SME |
Sami, Northern (Norway) |
0x083b |
SMF |
SME |
Sami, Northern (Sweden) |
0x0c3b |
SMG |
SME |
Sami, Northern (Finland) |
0x103b |
SMJ |
SME |
Sami, Lule (Norway) |
0x143b |
SMK |
SME |
Sami, Lule (Sweden) |
0x183b |
SMA |
SME |
Sami, Southern (Norway) |
0x1c3b |
SMB |
SME |
Sami, Southern (Sweden) |
0x203b |
SMS |
SME |
Sami, Skolt (Finland) |
0x243b |
SMN |
SME |
Sami, Inari (Finland) |
0x0c1a |
SRB |
HRV |
Serbian (Cyrillic) |
0x1c1a |
SRN |
HRV |
Serbian (Cyrillic, Bosnia, and Herzegovina) |
0x081a |
SRL |
HRV |
Serbian (Latin) |
0x181a |
SRS |
HRV |
Serbian (Latin, Bosnia, and Herzegovina) |
0x046c |
NSO |
NSO |
Sesotho sa Leboa/Northern Sotho (South Africa) |
0x0432 |
TSN |
TSN |
Setswana/Tswana (South Africa) |
0x041b |
SKY |
SKY |
Slovak |
0x0424 |
SLV |
SLV |
Slovenian |
0x040a |
ESP |
ESP |
Spanish (Spain, Traditional Sort) |
0x080a |
ESM |
ESP |
Spanish (Mexican) |
0x0c0a |
ESN |
ESP |
Spanish (Spain, Modern Sort ) |
0x100a |
ESG |
ESP |
Spanish (Guatemala) |
0x140a |
ESC |
ESP |
Spanish (Costa Rica) |
0x180a |
ESA |
ESP |
Spanish (Panama) |
0x1c0a |
ESD |
ESP |
Spanish (Dominican Republic) |
0x200a |
ESV |
ESP |
Spanish (Venezuela) |
0x240a |
ESO |
ESP |
Spanish (Colombia) |
0x280a |
ESR |
ESP |
Spanish (Peru) |
0x2c0a |
ESS |
ESP |
Spanish (Argentina) |
0x300a |
ESF |
ESP |
Spanish (Ecuador) |
0x340a |
ESL |
ESP |
Spanish (Chile) |
0x380a |
ESY |
ESP |
Spanish (Uruguay) |
0x3c0a |
ESZ |
ESP |
Spanish (Paraguay) |
0x400a |
ESB |
ESP |
Spanish (Bolivia) |
0x440a |
ESE |
ESP |
Spanish (El Salvador) |
0x480a |
ESH |
ESP |
Spanish (Honduras) |
0x4c0a |
ESI |
ESP |
Spanish (Nicaragua) |
0x500a |
ESU |
ESP |
Spanish (Puerto Rico) |
0x0430 |
=== |
=== |
Sutu |
0x0441 |
SWK |
SWK |
Swahili (Kenya) |
0x041d |
SVE |
SVE |
Swedish |
0x081d |
SVF |
SVE |
Swedish (Finland) |
0x045a |
SYR |
SYR |
Windows XP: Syriac. This is Unicode only. |
0x0449 |
TAM |
TAM |
Windows 2000/XP: Tamil. This is Unicode only. |
0x0444 |
TTT |
TTT |
Tatar (Tatarstan) |
0x044a |
TEL |
TEL |
Windows XP: Telugu. This is Unicode only. |
0x041e |
THA |
THA |
Thai |
0x041f |
TRK |
TRK |
Turkish |
0x0422 |
UKR |
UKR |
Ukrainian |
0x0420 |
URD |
URD |
Windows 98/ME, Windows 2000 /XP: Urdu (Pakistan) |
0x0820 |
=== |
URD |
Urdu (India) |
0x0443 |
UZB |
UZB |
Uzbek (Latin) |
0x0843 |
UZB |
UZB |
Uzbek (Cyrillic) |
0x042a |
VIT |
VIT |
Windows 98/ME, Windows NT 4 .0 and later: Vietnamese |
0x0452 |
CYM |
CYM |
Welsh (United Kingdom) |
Reference
- Creating a Resource-Only DLL.
- Code-Page Identifiers.
- Language Identifier.
- How to test your programs with Unicode characters in multiple languages on Windows 2000.
- Localized Resources in MFC Applications: Satellite DLLs.
- Localization of MFC Components.
- Code Pages Supported by Windows.
History
- 2005.07.19 - First released.