Is there a way to convert the two-letter Country Codes into their readable counterparts without using external ressources?
e.g. DE -> Germany
, AD -> Andorra
It would be great if I could select the target language or it's using the system language, because I'd like to have them in German.
The country codes can be represented either as a two-letter code (alpha-2) which is recommended as the general-purpose code, a three-letter code (alpha-3) which is more closely related to the country name and a three-digit numeric code (numeric-3) which can be useful if you need to avoid using Latin script.
The A1 (Anonymous proxy), AP (Asian Pacific region), EU (Europe) and A2 (Satellite providers) codes refer to IP addresses of which the country of origin is uncertain. EU, for example, means that the precise IP country is uncertain but it belongs to Europe.
MY is the two-letter country abbreviation for Malaysia.
As @Uwe mentioned in his comment, you can use the EnumSystemGeoID
and GetGeoInfo
functions. The principle is that with EnumSystemGeoID
function you'll enumerate geographical location identifiers and by the GetGeoInfo
function query if the enumerated identifier's ISO 2-letter country / region code (info type GEO_ISO2
) equals to the one of your interest. If so, then you can query for this identifier with the same function either a friendly name (info type GEO_FRIENDLYNAME
), or the official name (info type GEO_OFFICIALNAME
), return the result and stop the enumeration.
Here is an example code, which might do that (unfortunately, the enumeration function does not support passing custom data, so I've used a global record variable for passing values):
type
TEnumData = record
GeoCode: string;
GeoName: string;
Success: Boolean;
end;
GEOID = type LONG;
GEOTYPE = type DWORD;
GEOCLASS = type DWORD;
SYSGEOTYPE = (
GEO_NATION = $0001,
GEO_LATITUDE = $0002,
GEO_LONGITUDE = $0003,
GEO_ISO2 = $0004,
GEO_ISO3 = $0005,
GEO_RFC1766 = $0006,
GEO_LCID = $0007,
GEO_FRIENDLYNAME= $0008,
GEO_OFFICIALNAME= $0009,
GEO_TIMEZONES = $000A,
GEO_OFFICIALLANGUAGES = $000B,
GEO_ISO_UN_NUMBER = $000C,
GEO_PARENT = $000D
);
SYSGEOCLASS = (
GEOCLASS_NATION = 16,
GEOCLASS_REGION = 14,
GEOCLASS_ALL = 0
);
GEO_ENUMPROC = function(GeoId: GEOID): BOOL; stdcall;
function EnumSystemGeoID(GeoClass: GEOCLASS;
ParentGeoId: GEOID; lpGeoEnumProc: GEO_ENUMPROC): BOOL; stdcall;
external kernel32 name 'EnumSystemGeoID';
function GetGeoInfo(Location: GEOID; GeoType: GEOTYPE;
lpGeoData: LPTSTR; cchData: Integer; LangId: LANGID): Integer; stdcall;
external kernel32 name {$IFDEF UNICODE}'GetGeoInfoW'{$ELSE}'GetGeoInfoA'{$ENDIF};
implementation
var
// I have used this global variable due to a lack of user data parameter for the callback function
EnumData: TEnumData;
function TryGetGeoInfo(GeoId: GEOID; GeoType: GEOTYPE; out Value: string): Boolean;
var
Buffer: string;
BufferLen: Integer;
begin
Result := False;
BufferLen := GetGeoInfo(GeoId, GeoType, LPTSTR(Buffer), 0, 0);
if BufferLen <> 0 then
begin
SetLength(Buffer, BufferLen);
Result := GetGeoInfo(GeoId, GeoType, LPTSTR(Buffer), BufferLen, 0) <> 0;
if Result then
Value := Trim(Buffer);
end;
end;
function EnumGeoInfoProc(GeoId: GEOID): BOOL; stdcall;
var
S: string;
begin
Result := TryGetGeoInfo(GeoId, GEOTYPE(GEO_ISO2), S);
if Result and (S = EnumData.GeoCode) then
begin
// stop the enumeration since we've found the country by its ISO code
Result := False;
// return the success flag and try to return the friendly name of the country to the
// EnumData.GeoName record field; you can optionally query the GEO_OFFICIALNAME
EnumData.Success := TryGetGeoInfo(GeoId, GEOTYPE(GEO_FRIENDLYNAME), EnumData.GeoName);
end;
end;
function TryGetCountryNameByISO2(const Code: string; out Name: string): Boolean;
begin
// here is the brainless part using global record variable (because the function used
// here with its callback does not support passing user data); no, you cannot tune it
// up by making the callback function nested
EnumData.GeoCode := Code;
EnumData.Success := False;
if not EnumSystemGeoID(GEOCLASS(GEOCLASS_NATION), 0, EnumGeoInfoProc) then
RaiseLastOSError;
Result := EnumData.Success;
if Result then
Name := EnumData.GeoName;
end;
And a possible usage:
var
S: string;
begin
if TryGetCountryNameByISO2('DE', S) then
ShowMessage(S);
end;
You can iterate Languages
(from Sysutils) and check the Ext
property. The corresponding Name
property will give you the localized language name.
for I := 0 to Languages.Count - 1 do begin
Writeln(Languages.Ext[I], '=', Languages.Name[I]);
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With