Bookstore

Recent

Author Topic: Locale information...  (Read 615 times)

GypsyPrince

  • Jr. Member
  • **
  • Posts: 80
Locale information...
« on: March 26, 2020, 08:16:00 pm »
The locale/cultural I.D. (LCID) for the U.S. version of the English language = 1033.

The LCID for the Spain version of the Spanish language = 1034.

Does anyone know how FreePascal goes about extracting this integer value from the current user's machine setup in Windows?

I'll eventually need to be able to read all of the current user's cultural info for localization.  But for the time being, I need only to acquire the LCID.

Anyone got any ideas? A code sample will suffice, but I'd also like to be pointed in the direction of some associated documentation.
May the (Mass × Acceleration) be with you!

lucamar

  • Hero Member
  • *****
  • Posts: 2572
Re: Locale information...
« Reply #1 on: March 26, 2020, 09:04:59 pm »
IIRC those are constant values that Microsoft took out of a hat*, like the character code-pages, so you should probably head over to MS's documentation site and search there.


* OK, that's not exactly true; there's some sort of order in that chaos, but only they know what it is ;)

ETA: Found as the first result of googling for "LCID": [MS-LCID]: Windows Language Code Identifier (LCID) Reference
« Last Edit: March 26, 2020, 09:09:04 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.6/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

winni

  • Hero Member
  • *****
  • Posts: 1112
Re: Locale information...
« Reply #2 on: March 26, 2020, 09:05:40 pm »
Hi!

There is a Delphi example:

https://www.delphipraxis.net/6349-infos-aus-der-locale-id-lcid-aka-gebietsschema.html

The fuction GetLocaleInfo also exists in Lazarus in the unit Windows.
Good luck!

Winni

ASerge

  • Hero Member
  • *****
  • Posts: 1489
Re: Locale information...
« Reply #3 on: March 27, 2020, 12:08:49 am »
Does anyone know how FreePascal goes about extracting this integer value from the current user's machine setup in Windows?
It is better to use user preferences rather than machine preferences.
Code: Pascal  [Select]
  1. const
  2.   CUS_LANG_ID = LANG_ENGLISH or (SUBLANG_ENGLISH_US shl 10);
  3.  
  4. function EnumResLangProc(hModule: THandle; lpszType, lpszName: PChar;
  5.   wIDLanguage: Word; var lParam: Word): BOOL; stdcall;
  6. begin
  7.   if lpszName = nil then
  8.     Result := False
  9.   else
  10.   begin
  11.     if wIDLanguage <> CUS_LANG_ID then
  12.       lParam := wIDLanguage;
  13.     Result := True;
  14.   end;
  15. end;
  16.  
  17. function GetUserDefaultUILanguageOnWinNT: LANGID;
  18. begin
  19.   Result := CUS_LANG_ID;
  20.   EnumResourceLanguages(GetModuleHandle('ntdll.dll'), RT_VERSION,
  21.     MakeIntResource(1), @EnumResLangProc, LPARAM(@Result));
  22. end;
  23.  
  24. function GetUserDefaultUILanguageOnWin9X: LANGID;
  25. var
  26.   R: TRegistry;
  27.   S: string;
  28. begin
  29.   Result := CUS_LANG_ID;
  30.   R := TRegistry.Create;
  31.   try
  32.     R.RootKey := HKEY_CURRENT_USER;
  33.     if R.OpenKeyReadOnly('Control Panel\Desktop\ResourceLocale') then
  34.     begin
  35.       if R.GetDataType('') = rdString then
  36.       begin
  37.         S := R.ReadString('');
  38.         S := HexDisplayPrefix + S;
  39.         Result := StrToInt(S);
  40.       end;
  41.     end;
  42.   finally
  43.     R.Free;
  44.   end;
  45. end;
  46.  
  47. function GetUserPreferLanguage: LANGID;
  48. var
  49.   GetUserDefaultUILanguage: function: LANGID; stdcall;
  50. begin
  51.   GetUserDefaultUILanguage := GetProcAddress(GetModuleHandle(kernel32),
  52.     'GetUserDefaultUILanguage');
  53.   if Assigned(GetUserDefaultUILanguage) then
  54.     Result := GetUserDefaultUILanguage
  55.   else
  56.     if Win32Platform = VER_PLATFORM_WIN32_NT then
  57.       Result := GetUserDefaultUILanguageOnWinNT
  58.     else
  59.       Result := GetUserDefaultUILanguageOnWin9X;
  60. end;
  61. ...
  62. var
  63.   UserPreferLanguage: LANGID;
  64. ...
  65. UserPreferLanguage := GetUserPreferLanguage;

GypsyPrince

  • Jr. Member
  • **
  • Posts: 80
Re: Locale information...
« Reply #4 on: March 27, 2020, 05:32:27 am »
@ASerge

Yes, I do get the user's preference first.  However, I use a multi-layer mode of assignment.

A. Get user's preferred language/regional settings from the app config file or registry.
B. If "A" fails due to missing or corrupted entry, get the current user's language/regional settings from his OS account settings.
C. If "B" fails due to missing or corrupted entry, get the operating system's global (default) language/regional settings.
D. If "C" also fails, assign default language/regional settings for 1033 (English - U.S.A.)
May the (Mass × Acceleration) be with you!

jwdietrich

  • Hero Member
  • *****
  • Posts: 1071
    • formatio reticularis
Re: Locale information...
« Reply #5 on: March 27, 2020, 08:25:34 am »
If information about the language is sufficient for your purposes then the following code, which I use in my apps, may be helpful, too. It has the advantage of supporting Linux and macOS as well. See https://www.freepascal.org/docs-html/current/fcl/gettext/getlanguageids.html for a documantation of GetLanguageIDs.

Code: Pascal  [Select]
  1. function GetOSLanguage: string;
  2.   {platform-independent method to read the language of the user interface}
  3. var
  4.   l, fbl: string;
  5.   {$IFDEF Darwin}
  6.   theLocaleRef: CFLocaleRef;
  7.   locale: CFStringRef;
  8.   buffer: StringPtr;
  9.   bufferSize: CFIndex;
  10.   encoding: CFStringEncoding;
  11.   success: boolean;
  12.   {$ENDIF}
  13. begin
  14.   {$IFDEF Darwin}
  15.   theLocaleRef := CFLocaleCopyCurrent;
  16.   locale := CFLocaleGetIdentifier(theLocaleRef);
  17.   encoding := 0;
  18.   bufferSize := 256;
  19.   buffer := new(StringPtr);
  20.   success := CFStringGetPascalString(locale, buffer, bufferSize, encoding);
  21.   if success then
  22.     l := string(buffer^)
  23.   else
  24.     l := '';
  25.   fbl := Copy(l, 1, 2);
  26.   dispose(buffer);
  27.   {$ELSE}
  28.   {$IFDEF UNIX}
  29.   fbl := Copy(GetEnvironmentVariable('LC_CTYPE'), 1, 2);
  30.   {$ELSE}
  31.   GetLanguageIDs(l, fbl);
  32.   {$ENDIF}
  33.   {$ENDIF}
  34.   Result := fbl;
  35. end;
  36.  
« Last Edit: March 27, 2020, 08:28:06 am by jwdietrich »
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.0.6 | FPC 3.0.4 | PPC, Intel, ARM | macOS, Windows, Linux

MoCityMM

  • Jr. Member
  • **
  • Posts: 73
Re: Locale information...
« Reply #6 on: March 27, 2020, 01:05:42 pm »
Just throwing something into the hat here...

HKCU\Control Panel\International > Locale & LocaleName registry keys will supply the LCID hexadecimal codes you are looking for.

-Mo

GypsyPrince

  • Jr. Member
  • **
  • Posts: 80
Re: Locale information...
« Reply #7 on: March 27, 2020, 04:37:06 pm »
@MoCityMM

Thank you very much for that info. Unfortunately, it only applies to MS Windows, which is completely my fault because I wrote

Quote
...the current user's machine setup in Windows?

in the original post.  My brain was fried at the moment and what I should have said is...

does Lazarus already contain its own class or group of functions for the very purpose of acquiring this info from the user's system regardless of what operating system the user is currently logged into on his/her system, or at least for the top mainstream operating systems such as MS Windows, macOS/iOS, Linux, etc.

While, thankfully, Lazarus is nowhere near as bloated as .NET, such a class feature does seem a bit important and useful in our increasingly global environment, especially if Lazarus is going to purport to be cross-platform.

I think jwdietrich and winni gave me the information I needed, but I'm not sure because I haven't yet tinkered with it.
May the (Mass × Acceleration) be with you!

winni

  • Hero Member
  • *****
  • Posts: 1112
Re: Locale information...
« Reply #8 on: March 27, 2020, 05:21:07 pm »
Hi!

In the fpc unit gettext there exists a procedure

Code: Pascal  [Select]
  1. procedure GetLanguageIDs(var Lang, FallbackLang: string);

It is definded for Linux and Windows. I don't know about Mac.

Winni

GypsyPrince

  • Jr. Member
  • **
  • Posts: 80
Re: Locale information...
« Reply #9 on: March 27, 2020, 06:01:17 pm »
@winni

Even more great information. Thank you!!!  I'll dabble with it.
May the (Mass × Acceleration) be with you!

jwdietrich

  • Hero Member
  • *****
  • Posts: 1071
    • formatio reticularis
Re: Locale information...
« Reply #10 on: March 27, 2020, 06:14:45 pm »
It is definded for Linux and Windows. I don't know about Mac.

See my post above for a working solution for macOS.
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.0.6 | FPC 3.0.4 | PPC, Intel, ARM | macOS, Windows, Linux

GypsyPrince

  • Jr. Member
  • **
  • Posts: 80
Re: Locale information...
« Reply #11 on: March 27, 2020, 06:16:02 pm »
@jwdietrich and @winni

You guys are great!! Thanks again!
May the (Mass × Acceleration) be with you!

ASerge

  • Hero Member
  • *****
  • Posts: 1489
Re: Locale information...
« Reply #12 on: March 27, 2020, 06:46:04 pm »
Yes, I do get the user's preference first.  However, I use a multi-layer mode of assignment.
A. Get user's preferred language/regional settings from the app config file or registry.
B. If "A" fails due to missing or corrupted entry, get the current user's language/regional settings from his OS account settings.
C. If "B" fails due to missing or corrupted entry, get the operating system's global (default) language/regional settings.
D. If "C" also fails, assign default language/regional settings for 1033 (English - U.S.A.)
GetUserDefaultUILanguage do it all for you. See also Get Language OS.