Skip to main content

CountryFlags

Utilities for turning country, region and language codes into flag emoji, and for finding out which country a player or the server is in. The module is a plain table of functions: there is nothing to construct and no self to pass.

local Players = game:GetService("Players")
local CountryFlags = require(path.to.CountryFlags)

-- Server: greet each player with the flag of the country they are connecting from.
Players.PlayerAdded:Connect(function(player)
	local ok, countryCode = pcall(CountryFlags.GetPlayerRegion, player) -- yields, e.g. "US"
	if not ok then
		return
	end

	local flag = CountryFlags.Flags[countryCode] or CountryFlags.Get("UN")
	print(("Welcome %s %s"):format(player.Name, flag))
end)

-- Anywhere: flags from a region string or a language code.
local language, country = CountryFlags.SplitRegion("en-us") -- "EN", "US"
print(CountryFlags.Flags[country])                          -- "🇺🇸"
print(CountryFlags.FromLanguage(language))                  -- "🇺🇸" (EN is mapped to US)
print(CountryFlags.FromLanguage("ja"))                      -- "🇯🇵"

Codes are compared case-insensitively by the helper functions (they upper-case their input), but the CountryFlags.Flags and CountryFlags.LanguageMap tables themselves are keyed by upper-case codes.

Credits: written by KashTheKing. No third-party dependencies.

Installation and guide: CountryFlags package page.

Types​

LocationData​

interface LocationData {
ip: string--

The public IP address the request was made from, e.g. "2605:c840:402:8bac::8e03".

ip_decimal: number--

The same IP address as a decimal number.

country: string--

Full country name, e.g. "United States".

country_iso: string--

Two-letter ISO 3166-1 country code, e.g. "US". Pass this to CountryFlags.Get.

country_eu: boolean--

Whether the country is a member of the European Union.

region_name: string--

Name of the state, province or region, e.g. "Nevada".

region_code: string--

Short region code, e.g. "NV".

metro_code: number--

Metro (designated market area) code, e.g. 839.

zip_code: string--

Postal code, e.g. "89183".

city: string--

City name, e.g. "Las Vegas".

latitude: number--

Latitude in decimal degrees, e.g. 36.0021.

longitude: number--

Longitude in decimal degrees, e.g. -115.147.

time_zone: string--

IANA time zone name, e.g. "America/Los_Angeles".

}

The JSON body returned by https://ifconfig.co/json, as decoded by CountryFlags.GetLocationData. Because it describes the machine that made the HTTP request, it is the location of the game server, not of any player. Fields are whatever the service returns; some may be missing for IP addresses the service cannot geolocate.

Properties​

Flags​

This item is read only and cannot be modified. Read Only
CountryFlags.Flags: {[string]: string}

Dictionary of upper-case ISO 3166-1 alpha-2 country codes to their flag emoji, e.g. CountryFlags.Flags.GB == "🇬🇧". Besides real countries it also contains EU (European Union) and UN (United Nations), which are handy fallbacks. Indexing an unknown code returns nil.

LanguageMap​

This item is read only and cannot be modified. Read Only
CountryFlags.LanguageMap: {[string]: string}

Maps an upper-case two-letter ISO 639-1 language code to the country code whose flag is conventionally used for that language, e.g. EN -> "US", JA -> "JP", PT -> "BR", AR -> "SA". It is used by CountryFlags.FromLanguage. Only about two dozen common languages are mapped; a language is not a country, so the choice is a convention, not a fact. You may add or override entries at runtime (CountryFlags.LanguageMap.EN = "GB") before calling CountryFlags.FromLanguage.

Functions​

GetCodes​

CountryFlags.GetCodes() → {string}--

Array of upper-case country codes such as "US", including "EU" and "UN".

Returns every code that has a flag in CountryFlags.Flags, as a new array. The order is not defined (it comes from pairs), so sort it yourself if you need a stable list.

local codes = CountryFlags.GetCodes()
table.sort(codes)
print(#codes, codes[1]) -- 231 AD

IsA​

CountryFlags.IsA(
t: T--

Any value; non-strings return false.

) → boolean--

true if the value passes the country-code shape check.

Tells whether value looks like a two-letter country code. It only checks the shape of the value (a string of length two once letters are accounted for); it does not check that the code exists in CountryFlags.Flags, so IsA returning true does not guarantee that CountryFlags.Get will find a flag.

CAUTION

The current implementation strips the letters with gsub("%a", "") and then requires the remaining string to be two characters long. A plain code such as "US" therefore returns false, and CountryFlags.Get (which asserts on this function) errors for it. Until this is fixed, index CountryFlags.Flags directly for lookups.

Get​

CountryFlags.Get(
countryCode: string--

Two-letter country code, any case.

) → string--

The flag emoji, or nil when the code is unknown.

Returns the flag emoji for a country code. The code is upper-cased before the lookup, so "gb" and "GB" both work. If the code passes CountryFlags.IsA but has no entry in CountryFlags.Flags, the result is nil even though the declared return type is string.

print(CountryFlags.Get("de")) -- "🇩🇪"

Errors

TypeDescription
"Invalid country code"When `countryCode` does not satisfy [CountryFlags.IsA] (see the caution there).

GetPlayerRegion​

This item only works when running on the server. ServerThis is a yielding function. When called, it will pause the Lua thread that called the function until a result is ready to be returned, without interrupting other scripts. Yields
CountryFlags.GetPlayerRegion(
player: Player--

The player to look up; must still be in the game.

) → string--

Upper-case country/region code such as "US".

Returns the two-letter country/region code the player is connecting from, e.g. "US", by calling LocalizationService:GetCountryRegionForPlayerAsync. Despite the name, the result is a country code, not a language-COUNTRY locale string, so it can be used directly with CountryFlags.Flags. Wrap the call in pcall: the underlying Roblox API yields and raises an error if the request fails or the player has already left.

local ok, code = pcall(CountryFlags.GetPlayerRegion, player)
if ok then
	print(CountryFlags.Flags[code])
end

Errors

TypeDescription
stringPropagated from `GetCountryRegionForPlayerAsync` when the lookup fails.

GetLocationData​

This item only works when running on the server. ServerThis is a yielding function. When called, it will pause the Lua thread that called the function until a result is ready to be returned, without interrupting other scripts. Yields
CountryFlags.GetLocationData() → LocationData--

The decoded location of the server.

Fetches the geolocation of the game server by requesting https://ifconfig.co/json with HttpService:GetAsync and decoding the JSON body into a LocationData table. This is the server's public IP location (the data centre the server runs in), not a player's location; use CountryFlags.GetPlayerRegion for players.

Requirements and failure modes:

  • Server only: the function asserts RunService:IsServer().
  • HTTP requests must be enabled in Game Settings, otherwise GetAsync errors.
  • The request yields and can fail (network error, rate limit, service down), so call it in a pcall and cache the result rather than calling it per player.
local ok, location = pcall(CountryFlags.GetLocationData)
if ok then
	print(location.country, location.country_iso, CountryFlags.Flags[location.country_iso])
end

Errors

TypeDescription
"You must be on the server"When called from a client.
stringAny error raised by `HttpService:GetAsync` or `HttpService:JSONDecode`.

SplitRegion​

CountryFlags.SplitRegion(
regionString: string--

A locale string containing at least one -, e.g. "en-us".

) → (
string,--

The language code in upper case, e.g. "EN".

string--

The country/region code in upper case, e.g. "US".

)

Splits a language-COUNTRY locale string such as "en-us" (the format of LocalizationService.RobloxLocaleId or Player.LocaleId) into its language and country codes, both upper-cased. Only the first two segments are returned, so "zh-Hans-CN" gives "ZH", "HANS".

local language, country = CountryFlags.SplitRegion(player.LocaleId) -- "EN", "US"
local flag = CountryFlags.Flags[country] or CountryFlags.FromLanguage(language)

Errors

TypeDescription
"Invalid region string"When the string does not contain a `-`.

FromLanguage​

CountryFlags.FromLanguage(
languageCode: string--

Two-letter ISO 639-1 language code, any case.

) → string?--

The flag emoji of the mapped country, or nil if the language is not mapped.

Returns a representative flag for a language code by looking the upper-cased code up in CountryFlags.LanguageMap and then in CountryFlags.Flags. Returns nil when the language has no mapping, which is the case for most of the world's languages, so always handle nil.

print(CountryFlags.FromLanguage("ko")) -- "🇰🇷"
print(CountryFlags.FromLanguage("eo")) -- nil (Esperanto is not mapped)
Show raw api
{
    "functions": [
        {
            "name": "GetCodes",
            "desc": "Returns every code that has a flag in [CountryFlags.Flags], as a new array. The order is not\ndefined (it comes from `pairs`), so sort it yourself if you need a stable list.\n\n```lua\nlocal codes = CountryFlags.GetCodes()\ntable.sort(codes)\nprint(#codes, codes[1]) -- 231 AD\n```",
            "params": [],
            "returns": [
                {
                    "desc": "Array of upper-case country codes such as `\"US\"`, including `\"EU\"` and `\"UN\"`.",
                    "lua_type": "{ string }"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 187,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "IsA",
            "desc": "Tells whether `value` looks like a two-letter country code. It only checks the shape of the\nvalue (a string of length two once letters are accounted for); it does **not** check that the\ncode exists in [CountryFlags.Flags], so `IsA` returning `true` does not guarantee that\n[CountryFlags.Get] will find a flag.\n\n:::caution\nThe current implementation strips the letters with `gsub(\"%a\", \"\")` and then requires the\n**remaining** string to be two characters long. A plain code such as `\"US\"` therefore\nreturns `false`, and [CountryFlags.Get] (which asserts on this function) errors for it. Until\nthis is fixed, index [CountryFlags.Flags] directly for lookups.\n:::",
            "params": [
                {
                    "name": "t",
                    "desc": "Any value; non-strings return `false`.",
                    "lua_type": "T"
                }
            ],
            "returns": [
                {
                    "desc": "`true` if the value passes the country-code shape check.",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 216,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "Get",
            "desc": "Returns the flag emoji for a country code. The code is upper-cased before the lookup, so\n`\"gb\"` and `\"GB\"` both work. If the code passes [CountryFlags.IsA] but has no entry in\n[CountryFlags.Flags], the result is `nil` even though the declared return type is `string`.\n\n```lua\nprint(CountryFlags.Get(\"de\")) -- \"🇩🇪\"\n```",
            "params": [
                {
                    "name": "countryCode",
                    "desc": "Two-letter country code, any case.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "The flag emoji, or `nil` when the code is unknown.",
                    "lua_type": "string"
                }
            ],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "\"Invalid country code\"",
                    "desc": "When `countryCode` does not satisfy [CountryFlags.IsA] (see the caution there)."
                }
            ],
            "source": {
                "line": 236,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "GetPlayerRegion",
            "desc": "Returns the two-letter country/region code the player is connecting from, e.g. `\"US\"`, by\ncalling `LocalizationService:GetCountryRegionForPlayerAsync`. Despite the name, the result is\na country code, not a `language-COUNTRY` locale string, so it can be used directly with\n[CountryFlags.Flags]. Wrap the call in `pcall`: the underlying Roblox API yields and raises an\nerror if the request fails or the player has already left.\n\n```lua\nlocal ok, code = pcall(CountryFlags.GetPlayerRegion, player)\nif ok then\n\tprint(CountryFlags.Flags[code])\nend\n```",
            "params": [
                {
                    "name": "player",
                    "desc": "The player to look up; must still be in the game.",
                    "lua_type": "Player"
                }
            ],
            "returns": [
                {
                    "desc": "Upper-case country/region code such as `\"US\"`.",
                    "lua_type": "string"
                }
            ],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "string",
                    "desc": "Propagated from `GetCountryRegionForPlayerAsync` when the lookup fails."
                }
            ],
            "realm": [
                "Server"
            ],
            "yields": true,
            "source": {
                "line": 265,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "GetLocationData",
            "desc": "Fetches the geolocation of the **game server** by requesting `https://ifconfig.co/json` with\n`HttpService:GetAsync` and decoding the JSON body into a [LocationData] table. This is the\nserver's public IP location (the data centre the server runs in), not a player's location;\nuse [CountryFlags.GetPlayerRegion] for players.\n\nRequirements and failure modes:\n- Server only: the function asserts `RunService:IsServer()`.\n- HTTP requests must be enabled in Game Settings, otherwise `GetAsync` errors.\n- The request yields and can fail (network error, rate limit, service down), so call it in a\n  `pcall` and cache the result rather than calling it per player.\n\n```lua\nlocal ok, location = pcall(CountryFlags.GetLocationData)\nif ok then\n\tprint(location.country, location.country_iso, CountryFlags.Flags[location.country_iso])\nend\n```",
            "params": [],
            "returns": [
                {
                    "desc": "The decoded location of the server.",
                    "lua_type": "LocationData"
                }
            ],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "\"You must be on the server\"",
                    "desc": "When called from a client."
                },
                {
                    "lua_type": "string",
                    "desc": "Any error raised by `HttpService:GetAsync` or `HttpService:JSONDecode`."
                }
            ],
            "realm": [
                "Server"
            ],
            "yields": true,
            "source": {
                "line": 299,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "SplitRegion",
            "desc": "Splits a `language-COUNTRY` locale string such as `\"en-us\"` (the format of\n`LocalizationService.RobloxLocaleId` or `Player.LocaleId`) into its language and country codes,\nboth upper-cased. Only the first two segments are returned, so `\"zh-Hans-CN\"` gives\n`\"ZH\", \"HANS\"`.\n\n```lua\nlocal language, country = CountryFlags.SplitRegion(player.LocaleId) -- \"EN\", \"US\"\nlocal flag = CountryFlags.Flags[country] or CountryFlags.FromLanguage(language)\n```",
            "params": [
                {
                    "name": "regionString",
                    "desc": "A locale string containing at least one `-`, e.g. `\"en-us\"`.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "The language code in upper case, e.g. `\"EN\"`.",
                    "lua_type": "string"
                },
                {
                    "desc": "The country/region code in upper case, e.g. `\"US\"`.",
                    "lua_type": "string"
                }
            ],
            "function_type": "static",
            "errors": [
                {
                    "lua_type": "\"Invalid region string\"",
                    "desc": "When the string does not contain a `-`."
                }
            ],
            "source": {
                "line": 328,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "FromLanguage",
            "desc": "Returns a representative flag for a **language** code by looking the upper-cased code up in\n[CountryFlags.LanguageMap] and then in [CountryFlags.Flags]. Returns `nil` when the language\nhas no mapping, which is the case for most of the world's languages, so always handle `nil`.\n\n```lua\nprint(CountryFlags.FromLanguage(\"ko\")) -- \"🇰🇷\"\nprint(CountryFlags.FromLanguage(\"eo\")) -- nil (Esperanto is not mapped)\n```",
            "params": [
                {
                    "name": "languageCode",
                    "desc": "Two-letter ISO 639-1 language code, any case.",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "The flag emoji of the mapped country, or `nil` if the language is not mapped.",
                    "lua_type": "string?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 352,
                "path": "packages/src/CountryFlags/init.luau"
            }
        }
    ],
    "properties": [
        {
            "name": "Flags",
            "desc": "Dictionary of upper-case ISO 3166-1 alpha-2 country codes to their flag emoji, e.g.\n`CountryFlags.Flags.GB == \"🇬🇧\"`. Besides real countries it also contains `EU` (European Union)\nand `UN` (United Nations), which are handy fallbacks. Indexing an unknown code returns `nil`.",
            "lua_type": "{ [string]: string }",
            "readonly": true,
            "source": {
                "line": 159,
                "path": "packages/src/CountryFlags/init.luau"
            }
        },
        {
            "name": "LanguageMap",
            "desc": "Maps an upper-case two-letter ISO 639-1 **language** code to the **country** code whose flag\nis conventionally used for that language, e.g. `EN -> \"US\"`, `JA -> \"JP\"`, `PT -> \"BR\"`,\n`AR -> \"SA\"`. It is used by [CountryFlags.FromLanguage]. Only about two dozen common languages\nare mapped; a language is not a country, so the choice is a convention, not a fact. You may\nadd or override entries at runtime (`CountryFlags.LanguageMap.EN = \"GB\"`) before calling\n[CountryFlags.FromLanguage].",
            "lua_type": "{ [string]: string }",
            "readonly": true,
            "source": {
                "line": 171,
                "path": "packages/src/CountryFlags/init.luau"
            }
        }
    ],
    "types": [
        {
            "name": "LocationData",
            "desc": "The JSON body returned by `https://ifconfig.co/json`, as decoded by [CountryFlags.GetLocationData].\nBecause it describes the machine that made the HTTP request, it is the location of the **game\nserver**, not of any player. Fields are whatever the service returns; some may be missing for\nIP addresses the service cannot geolocate.",
            "fields": [
                {
                    "name": "ip",
                    "lua_type": "string",
                    "desc": "The public IP address the request was made from, e.g. `\"2605:c840:402:8bac::8e03\"`."
                },
                {
                    "name": "ip_decimal",
                    "lua_type": "number",
                    "desc": "The same IP address as a decimal number."
                },
                {
                    "name": "country",
                    "lua_type": "string",
                    "desc": "Full country name, e.g. `\"United States\"`."
                },
                {
                    "name": "country_iso",
                    "lua_type": "string",
                    "desc": "Two-letter ISO 3166-1 country code, e.g. `\"US\"`. Pass this to [CountryFlags.Get]."
                },
                {
                    "name": "country_eu",
                    "lua_type": "boolean",
                    "desc": "Whether the country is a member of the European Union."
                },
                {
                    "name": "region_name",
                    "lua_type": "string",
                    "desc": "Name of the state, province or region, e.g. `\"Nevada\"`."
                },
                {
                    "name": "region_code",
                    "lua_type": "string",
                    "desc": "Short region code, e.g. `\"NV\"`."
                },
                {
                    "name": "metro_code",
                    "lua_type": "number",
                    "desc": "Metro (designated market area) code, e.g. `839`."
                },
                {
                    "name": "zip_code",
                    "lua_type": "string",
                    "desc": "Postal code, e.g. `\"89183\"`."
                },
                {
                    "name": "city",
                    "lua_type": "string",
                    "desc": "City name, e.g. `\"Las Vegas\"`."
                },
                {
                    "name": "latitude",
                    "lua_type": "number",
                    "desc": "Latitude in decimal degrees, e.g. `36.0021`."
                },
                {
                    "name": "longitude",
                    "lua_type": "number",
                    "desc": "Longitude in decimal degrees, e.g. `-115.147`."
                },
                {
                    "name": "time_zone",
                    "lua_type": "string",
                    "desc": "IANA time zone name, e.g. `\"America/Los_Angeles\"`."
                }
            ],
            "source": {
                "line": 32,
                "path": "packages/src/CountryFlags/init.luau"
            }
        }
    ],
    "name": "CountryFlags",
    "desc": "Utilities for turning country, region and language codes into flag emoji, and for finding out\nwhich country a player or the server is in. The module is a plain table of functions: there is\nnothing to construct and no `self` to pass.\n\n```lua\nlocal Players = game:GetService(\"Players\")\nlocal CountryFlags = require(path.to.CountryFlags)\n\n-- Server: greet each player with the flag of the country they are connecting from.\nPlayers.PlayerAdded:Connect(function(player)\n\tlocal ok, countryCode = pcall(CountryFlags.GetPlayerRegion, player) -- yields, e.g. \"US\"\n\tif not ok then\n\t\treturn\n\tend\n\n\tlocal flag = CountryFlags.Flags[countryCode] or CountryFlags.Get(\"UN\")\n\tprint((\"Welcome %s %s\"):format(player.Name, flag))\nend)\n\n-- Anywhere: flags from a region string or a language code.\nlocal language, country = CountryFlags.SplitRegion(\"en-us\") -- \"EN\", \"US\"\nprint(CountryFlags.Flags[country])                          -- \"🇺🇸\"\nprint(CountryFlags.FromLanguage(language))                  -- \"🇺🇸\" (EN is mapped to US)\nprint(CountryFlags.FromLanguage(\"ja\"))                      -- \"🇯🇵\"\n```\n\nCodes are compared case-insensitively by the helper functions (they upper-case their input),\nbut the [CountryFlags.Flags] and [CountryFlags.LanguageMap] tables themselves are keyed by\n**upper-case** codes.\n\n**Credits:** written by KashTheKing. No third-party dependencies.\n\nInstallation and guide: [CountryFlags package page](/docs/packages/country-flags).",
    "source": {
        "line": 146,
        "path": "packages/src/CountryFlags/init.luau"
    }
}