This round of questions has to do with how to handle globalization issues when it comes to BiDi (Bi-Directional) languages like Arabic and Hebrew.
| Hidden?? mirroring functions. | |
| How do I create Arabic resource files? | |
| Visual Basic "Mirroring" | |
| Programmatically determining OS language version | |
| Locale 101 | |
| Non-ASCII characters in computer names |
I would like to know what it is that makes an international version of Windows such as the Arabic BiDi? Is it special editions of common controls such as comctl32 and other controls, or is it something else? Is there at all a hidden API function to support RTL writing in Windows Me English edition, and is there a tool for defining keyboard layouts? Last but not least, if Microsoft has separated localization info such as menu item names and start menu name, is it in a special file or something and can it be changed to localize a Windows English or Arabic localized to Persian or any other language, what are the files?
Yours Sincerely From The Internet
Dear, From the Internet
There are no "hidden" or undocumented APIs. Everything Microsoft uses for mirroring is available to you as well. A brief article on mirroring in Windows can be found at http://www.microsoft.com/globaldev/getwr/steps/WRG_mirror.mspx.
The resources, including the text in the UI, in Win32 are stored as a part of the binaries, in resource sections. Localization can change these resources without recompilation. This takes both special tools and a lot of expertise in how OS components interact, so this task is far from being trivial. But the good things are: Arabic localized OS exists already; unfortunately, Persian localization can not be done for Windows ME, because Farsi is not fully supported by ANSI, and Windows ME is not a Unicode-based OS (in contrast to Windows 2000)
I am trying to develop dual Arabic/English Application using Visual C++ 6.0 under Windows 2000 Arabic. I read the documents which you suggest to create a Satellite DLL for each Language. I tried to create Resource File (.rc) for Arabic, but when I run the application I can see garbage. I went to Visual C++ 6.0 Resource Editor to choose the language for the Resource but I couldn't find Arabic.
Also I downloaded a Unicode RC from the Internet, but The Visual C++ Resource Editor can't open this Unicode File, although I can use the Compiled DLL but I can't Modify the Resource File.
What is the Best Method to Create an Arabic Resource File in Visual C++ ??
Arabic needed Software Engineer
Dear, Arabic needed
I understand your frustration since I went thru the same problems before. Here are two possible solutions:
| • | The VC6 editor is not Unicode based (you already know that). If you are running on Windows 2000, you can set your system locale (see locale question later in this article) to Arabic (requires a reboot). Open your resource project and write your resources directly in Arabic. Make sure that you set your resource language to Arabic by right-clicking on the resource type tree-view control (left panel in VC, where you have Dialogs, String Resources...) and choose Properties and then select Arabic. Save your resources and compile your app as Unicode. That should do the work and your app should show Arabic chars just fine even on a Windows 2000 system that has a different system locale other than Arabic. |
| • | Don't change your system locale. Create your resource file as you used to do but also make sure that you set the language of the resource to Arabic (as mentioned above). Now, open your .rc file as a text only within VC. You can now cut & paste your Arabic translation from Notepad into VC editor (characters will show as high ANSI at this point). Save and compile Unicode. Once again you would end-up with the proper display of Arabic. |
Some versions of Windows operating system has a technology called "Mirroring" which reflects the appearance of all windows and controls to the Right-to-Left direction. You can achieve this by using the API function "SetWindowLong". Regardless the RightToLeft property, the Mirror Technology gives you a real RTL direction. As shown in the figure bellow.
Mirror Technology works 100% correct with the Visual C++ and Delphi. But when applying it with Visual Basic, a lot of problems occur, I wrote this code:
Option Explicit Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Const GWL_EXSTYLE = (-20) Private Const WS_EX_LAYOUTRTL As Long = &H400000 Private Sub Form_Load() Dim L As Long L = GetWindowLong(Me.hwnd, GWL_EXSTYLE) SetWindowLong Me.hwnd, GWL_EXSTYLE, L Or WS_EX_LAYOUTRTL End Sub
But it doesn't give me a good results especially when applying to Windows Common Controls L I really need your help for that.
from the internet 2
Dear Internet 2
Setting Window class at run-time is possible, but it is not the best solution for mirroring windows. The reasons are:
| • | First, all child windows (like controls on the dialog/form) have to be re-created, or the window class has to be re-defined for each one of them, and all of them have to be re-positioned. All that is unnecessary if you create your main window with WS_EX_LAYOUTRTL or if before your windows are created, you call SetProcessDefaultLayout (LAYOUT_RTL). |
| • | Second, common controls were not created to support run-time mirroring style changes. Some may support it, but some may be drawn incorrectly. |
| • | Third, VB is a special case; the only recommended way of mirroring of VB forms is by using RightToLeft property of a form/control. |
How can I determine (with APIs) whether the OS version is "Local" Hebrew/Arabic, or it's another version ("Enabled" Middle-East, or non-Middle-East at all)?
Searching for enlightenment
Dear, Searching
Here is how it really works depending on the OS version:
Windows 2000 / Windows XP
| • | Detecting an enabled version: all versions and flavors of these platforms support over 60 different scripts provided the right language packages are installed. You can find out if Arabic or Hebrew support is installed on the system by calling IsValidLocale and specifying the LCID_INSTALLED flag. |
| • | Detecting a localized version: you can use GetUserDefaultUILanguage API to detect the current user UI language (note that on Multilingual User Interface versions one can select that UI language per user). |
Win9x / WinME
| • | Detecting a localized version: the UI language is stored in the registry at: HKCU\Control Panel\Desktop\ResourceLocale. This key will return the language ID (LangID) of the UI in hexadecimal (e.g. 00000409 for English). |
| • | Detecting an enable version: Only Arabic, Hebrew, and Thai shipped an enabled version. You can detect these languages based on the system's active code page (GetACP API). Of course, you also need to make sure that you are not dealing with a localized version of these enabled languages and the UI language is in fact English. |
Windows NT
| • | The absence of a relevant API and consistent registry entries means that the safest way to check the language of the OS is to check the version stamp of NTDLL.DLL The language of this file is the same as the language of the User Interface. Again, the only exception is Arabic, Hebrew, and Thai where the version stamping can help you to detect an enabled OS. Thus the steps are:
|
Here is some sample code on how you might do this (please note that this code is provided as is and is given here as an illustrating example only).
// Load and check the language of version stamping of NTDLL.DLL
// For East Asian countries that might be a multilingual
// version, we only take non-English ones in consideration.
hLib = LoadLibrary(_TEXT("ntdll.dll"));
if (hLib == NULL)
{ // we fail to load the file and exit...
return (FALSE);
}
EnumResourceLanguages(hLib, RT_VERSION, MAKEINTRESOURCE(1),
EnumResLangProc, NULL);
FreeLibrary(hLib);
// we have an English version stamping. We still might
// be dealing with an enabled language (Arabic,
// Hebrew, or Thai)
if (g_wLangID == US_LANG_ID)
{
UINTuiACP;
uiACP = GetACP();
switch (uiACP)
{
case 874: // Thai code page activated, it's a Thai enabled system
g_wLangID = MAKELANGID(LANG_THAI, SUBLANG_DEFAULT);
break;
case 1255: // Hebrew code page activated, it's a Hebrew enabled system
g_wLangID = MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT);
break;
case 1256: // Arabic code page activated, it's a Arabic enabled system
g_wLangID = MAKELANGID(LANG_ARABIC,
SUBLANG_ARABIC_SAUDI_ARABIA);
break;
default:
break;
}
}
/***************
***************/
BOOL CALLBACK EnumResLangProc(HANDLE hModule, LPCTSTR lpszType,
LPCTSTR lpszName, WORD wIDLanguage, LONG_PTR lParam)
{
if (!lpszName)
return FALSE;
if (wIDLanguage != US_LANG_ID)
g_wLangID = wIDLanguage;
return TRUE;
}
How can I set the locale?
anonymous
Dear, Anonymous
I have been asked this question over and over. And the only answer I can give is: which locale are you referring to? So lets have a look together into "locales". I will call this Locale 101.
Michelle is living in the US. Her location is set to the United States because she wants to use a national ISP or she wants to get weather forecasts for the US. Her user locale is set to Spanish-Chile because she wants to see formatted data within her native country's standards.
Michelle is also fluent in Korean. She recently purchased a Korean word-processor (ANSI app!) that she wants to run on her English machine. She sets her system locale to Korean. To start using her app, beside the English keyboard, she installs a Korean IME as a second input locale. Her husband, sharing the same computer and not being comfortable with English, can set the UI language to Spanish for his own account (if running MUI [Multilingual User Interface version of Windows 2000/XP])!
System Locale: Or "Language for non-Unicode programs" in Windows XP. This per system variable does not affect anything but ANSI applications. It allows the OS to emulate ANSI applications by using the selected language's code-page to convert between ANSI/OEM and Unicode encodings. Use GetACP / GetOEMCP APIs to retrieve that value. No API available to set this locale (by design).
| • | In Windows 2000, users can change this by clicking on the "Set default..." button in the "Language settings for the system" field of the "General" tab of the "Regional Options" Control Panel applet (requires a reboot for the change to take effect). |
| • | In Windows XP, users can change it thru the Advanced tab of the Regional and Language Options applet (requires a reboot for the change to take effect). |
User Locale: Or "Standards and formats" in Windows XP. This per user variable defines user's preferences for formatting locale sensitive data (date, time, currency ...). Your application should be using that setting to display formatted data. Use GetUserDefaultLCID to retrieve that value. No API available to set this locale (by design).
| • | In Windows 2000, users can change this in the "Your locale (location)" option in the "Settings for the current user" field of the "General" tab of the "Regional Options" Control Panel applet (can be set on the fly). |
| • | In Windows XP, users can change it thru the Region Options tab of the Regional and Language Options applet (can be set on the fly). |
Input Locale: Called the same in Windows XP.This per process locale is a combination of input language (e.g. Greek) and input method (e.g. keyboard). Use GetKeyboardLayout & LoadKeyboardLayout to retrieve/set that value.
| • | In Windows 2000, users can add/remove input locales thru the Input Locales tab of the "Regional Options" Control Panel applet (can be set on the fly). |
| • | In Windows XP, users can add/remove input locales thru the Languages tab of the Regional and Language Options applet (can be set on the fly). |
Thread Locale: This per thread locale is initialized with the currently selected user locale value. Formerly used to retrieve language specific resources from a multilingual resource file (see GetThreadLocale/SetThreadLocale for more info). Should only be used to synchronize the thread locale of a server application with the user locale of a client machine. This can only be set programmatically.
Location: Or geographic ID. This per user variable is newly introduced in Windows XP to define the country where the user lives. Use GetGeoInfo to retrieve that value. No API is available to set this locale (by design). Users can change it thru the Region Options tab of the Regional and Language Options applet (can be set on the fly).
UI Language: This per user variable defines the language in which menus, dialog boxes, help files ... are translated, and is only found on the MUI (Multilangual User Interface version of Windows 2000/XP). Use Get[User/System]DefaultUILanguage to retrieve its value. No API's are available to set this locale (by design).
| • | In Windows 2000 MUI version, users can change this in the "Menus and dialogs" option in the "Settings for the current user" field of the "General" tab of the "Regional Options" Control Panel applet (requires a log-off/log-on) |
| • | In Windows XP MUI version, users can select the user interface language thru the "Language used in menus and dialogs" option of the Languages tab of the Regional and Language Options applet (requires a log-off/log-on). |
I hope you learned all this because there may be a pop quiz in the next Dr. International article.
I'm concerned about supporting non-ASCII computer names on Win9x and NT4 clients connected to a Windows 2000 Server. Do other Microsoft operating systems support non-ASCII computer names and NET BIOS names if the default system locale is the same on all machines including the server?
Karla in Seattle
Dear, Karla
The same rule applies for both your Win9x and WinNT machines. They only support non-ASCII computer names that are compatible with the system's code page. For example, if you're Windows 2000 is set to the Japanese system locale and is has a Japanese computer name, you can only see that machine from machines running a Japanese version of Win9x or NT.
Suggestion: to allow down-level compatibility and to avoid a computer setting dependency, it's highly suggested to keep ASCII computer names in a multilingual environment.
See you next time and don't forget to study for that possible Locale 101 pop quiz.
Dr. International
Windows Division