Intl.DisplayNames API
Convert language, region, currency, and script codes into human-readable names
Introduction
Your application has the country code US, but users see the text "United States". You have the language code fr, but the language switcher displays "French". You have the currency code EUR, but the checkout page shows "Euro".
Browsers maintain extensive localization data to render their own interfaces in different languages. The Intl.DisplayNames API exposes this data to JavaScript, converting standardized codes into human-readable names localized for any language.
This eliminates the need for third-party libraries or custom lookup tables that require maintenance and localization. The browser handles both the data and the translations.
Converting region codes to country names
The most common use case involves converting ISO country codes into country names. Create a DisplayNames instance with a locale and type, then call the of() method with a country code:
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("US")); // "United States"
console.log(regionNames.of("GB")); // "United Kingdom"
console.log(regionNames.of("JP")); // "Japan"
The first parameter accepts an array of locale codes following the BCP 47 standard. The browser uses the first supported locale from the array. The type option specifies which kind of code you want to convert.
The same codes produce different outputs when localized for different languages:
const englishRegions = new Intl.DisplayNames(["en"], { type: "region" });
const japaneseRegions = new Intl.DisplayNames(["ja"], { type: "region" });
const spanishRegions = new Intl.DisplayNames(["es"], { type: "region" });
console.log(englishRegions.of("FR")); // "France"
console.log(japaneseRegions.of("FR")); // "フランス"
console.log(spanishRegions.of("FR")); // "Francia"
This pattern works for building country selectors, location displays, and any interface element that converts country codes into readable names.
Converting language codes to language names
Language codes use the same pattern as region codes. Set type: "language" to convert language codes into language names:
const languageNames = new Intl.DisplayNames(["en"], { type: "language" });
console.log(languageNames.of("en")); // "English"
console.log(languageNames.of("es")); // "Spanish"
console.log(languageNames.of("zh")); // "Chinese"
console.log(languageNames.of("ar")); // "Arabic"
Language codes can include region subtags for regional variants:
const languageNames = new Intl.DisplayNames(["en"], { type: "language" });
console.log(languageNames.of("en-US")); // "American English"
console.log(languageNames.of("en-GB")); // "British English"
console.log(languageNames.of("fr-CA")); // "Canadian French"
console.log(languageNames.of("pt-BR")); // "Brazilian Portuguese"
This converts language codes into names suitable for language switchers, translation interfaces, and language preference selectors.
Displaying language names in their own language
Language switchers often show each language in its own writing system. Create a separate DisplayNames instance for each target language:
const english = new Intl.DisplayNames(["en"], { type: "language" });
const french = new Intl.DisplayNames(["fr"], { type: "language" });
const japanese = new Intl.DisplayNames(["ja"], { type: "language" });
const arabic = new Intl.DisplayNames(["ar"], { type: "language" });
console.log(english.of("en")); // "English"
console.log(french.of("fr")); // "français"
console.log(japanese.of("ja")); // "日本語"
console.log(arabic.of("ar")); // "العربية"
Users recognize their language more quickly when displayed in its native script.
Converting currency codes to currency names
Currency codes follow the ISO 4217 standard. Set type: "currency" to convert three-letter currency codes into currency names:
const currencyNames = new Intl.DisplayNames(["en"], { type: "currency" });
console.log(currencyNames.of("USD")); // "US Dollar"
console.log(currencyNames.of("EUR")); // "Euro"
console.log(currencyNames.of("GBP")); // "British Pound"
console.log(currencyNames.of("JPY")); // "Japanese Yen"
Currency names localize based on the display locale:
const englishCurrency = new Intl.DisplayNames(["en"], { type: "currency" });
const germanCurrency = new Intl.DisplayNames(["de"], { type: "currency" });
const japaneseCurrency = new Intl.DisplayNames(["ja"], { type: "currency" });
console.log(englishCurrency.of("EUR")); // "Euro"
console.log(germanCurrency.of("EUR")); // "Euro"
console.log(japaneseCurrency.of("EUR")); // "ユーロ"
This pattern works for currency selectors in checkout flows, financial dashboards, and currency conversion interfaces.
Converting script codes to script names
Script codes use the ISO 15924 standard. Set type: "script" to convert four-letter script codes into script names:
const scriptNames = new Intl.DisplayNames(["en"], { type: "script" });
console.log(scriptNames.of("Latn")); // "Latin"
console.log(scriptNames.of("Arab")); // "Arabic"
console.log(scriptNames.of("Cyrl")); // "Cyrillic"
console.log(scriptNames.of("Hans")); // "Simplified Chinese"
console.log(scriptNames.of("Hant")); // "Traditional Chinese"
Script names appear less frequently in user interfaces but become relevant for multilingual content management systems and language selection interfaces that distinguish between writing systems.
Converting calendar codes to calendar names
Calendar systems vary across cultures. Set type: "calendar" to convert calendar identifiers into calendar names:
const calendarNames = new Intl.DisplayNames(["en"], { type: "calendar" });
console.log(calendarNames.of("gregory")); // "Gregorian Calendar"
console.log(calendarNames.of("japanese")); // "Japanese Calendar"
console.log(calendarNames.of("buddhist")); // "Buddhist Calendar"
console.log(calendarNames.of("hebrew")); // "Hebrew Calendar"
console.log(calendarNames.of("islamic")); // "Islamic Calendar"
console.log(calendarNames.of("chinese")); // "Chinese Calendar"
This becomes useful for scheduling applications, date pickers with calendar system selection, and internationalized calendar interfaces.
Converting date and time field codes to field names
Date and time interfaces contain labeled fields like year, month, and day. Set type: "dateTimeField" to convert field identifiers into localized field names:
const dateFields = new Intl.DisplayNames(["en"], { type: "dateTimeField" });
console.log(dateFields.of("year")); // "year"
console.log(dateFields.of("month")); // "month"
console.log(dateFields.of("day")); // "day"
console.log(dateFields.of("hour")); // "hour"
console.log(dateFields.of("minute")); // "minute"
console.log(dateFields.of("weekday")); // "day of the week"
console.log(dateFields.of("dayPeriod")); // "AM/PM"
console.log(dateFields.of("timeZoneName")); // "time zone"
These field names localize for the display language:
const englishFields = new Intl.DisplayNames(["en"], { type: "dateTimeField" });
const spanishFields = new Intl.DisplayNames(["es"], { type: "dateTimeField" });
const japaneseFields = new Intl.DisplayNames(["ja"], { type: "dateTimeField" });
console.log(englishFields.of("month")); // "month"
console.log(spanishFields.of("month")); // "mes"
console.log(japaneseFields.of("month")); // "月"
Valid field identifiers include era, year, quarter, month, weekOfYear, weekday, day, dayPeriod, hour, minute, second, and timeZoneName.
This pattern supports building accessible date pickers, calendar interfaces, and time selection components with properly localized labels.
Controlling display length with style options
The style option controls how verbose the output appears. Three values produce different lengths:
const longNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "long",
});
const shortNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "short",
});
const narrowNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "narrow",
});
console.log(longNames.of("US")); // "United States"
console.log(shortNames.of("US")); // "US"
console.log(narrowNames.of("US")); // "US"
The long style (the default) produces the full name. The short and narrow styles produce abbreviated forms when available, though not all codes have shorter variants.
Style becomes more relevant with language names:
const longLanguages = new Intl.DisplayNames(["en"], {
type: "language",
style: "long",
});
const shortLanguages = new Intl.DisplayNames(["en"], {
type: "language",
style: "short",
});
console.log(longLanguages.of("en-US")); // "American English"
console.log(shortLanguages.of("en-US")); // "US English"
Use long for full labels in forms and detailed interfaces. Use short or narrow for compact displays like mobile navigation or space-constrained UI elements.
Handling regional language variants with languageDisplay
Language codes with region subtags can display as dialects or as standard language names with regional qualifiers. The languageDisplay option controls this behavior and only applies when type: "language":
const dialectNames = new Intl.DisplayNames(["en"], {
type: "language",
languageDisplay: "dialect",
});
const standardNames = new Intl.DisplayNames(["en"], {
type: "language",
languageDisplay: "standard",
});
console.log(dialectNames.of("nl-BE")); // "Flemish"
console.log(standardNames.of("nl-BE")); // "Dutch (Belgium)"
console.log(dialectNames.of("en-AU")); // "Australian English"
console.log(standardNames.of("en-AU")); // "English (Australia)"
The dialect value (the default) displays regional variants using their common names. The standard value always displays the base language with a region qualifier in parentheses.
Choose dialect when regional variants have well-known names that users recognize. Choose standard for consistent formatting or when working with less common language-region combinations.
Controlling fallback behavior for invalid codes
The of() method receives codes that might not have corresponding display names. The fallback option determines what happens:
const withCodeFallback = new Intl.DisplayNames(["en"], {
type: "region",
fallback: "code",
});
const withNoneFallback = new Intl.DisplayNames(["en"], {
type: "region",
fallback: "none",
});
console.log(withCodeFallback.of("ZZ")); // "ZZ"
console.log(withNoneFallback.of("ZZ")); // undefined
The code value (the default) returns the input code when no display name exists. The none value returns undefined for unmapped codes.
Use code when you always need a string value for display, even if it falls back to the code itself. Use none when you need to detect invalid codes and handle them explicitly:
const regionNames = new Intl.DisplayNames(["en"], {
type: "region",
fallback: "none",
});
function getRegionName(code) {
const name = regionNames.of(code);
if (name === undefined) {
return "Unknown region";
}
return name;
}
console.log(getRegionName("US")); // "United States"
console.log(getRegionName("INVALID")); // "Unknown region"
Building a country selector component
The Intl.DisplayNames API integrates directly into interface components. This example builds a country selector that displays country names in the user's language:
function CountrySelector({ locale, value, onChange }) {
const regionNames = new Intl.DisplayNames([locale], { type: "region" });
const countries = [
"US",
"GB",
"CA",
"AU",
"FR",
"DE",
"JP",
"CN",
"BR",
"IN",
];
return (
<select value={value} onChange={(e) => onChange(e.target.value)}>
<option value="">Select a country</option>
{countries.map((code) => (
<option key={code} value={code}>
{regionNames.of(code)}
</option>
))}
</select>
);
}
The component receives a locale prop that controls the display language. Changing the locale prop rerenders the dropdown with translated country names.
Building a language switcher component
Language switchers show each language in its own writing system. Create a DisplayNames instance for each language:
function LanguageSwitcher({ currentLocale, onLocaleChange }) {
const languages = [
{ code: "en", name: "English" },
{ code: "es", name: "Español" },
{ code: "fr", name: "Français" },
{ code: "de", name: "Deutsch" },
{ code: "ja", name: "日本語" },
{ code: "zh", name: "中文" },
];
return (
<div>
{languages.map((lang) => {
const displayNames = new Intl.DisplayNames([lang.code], {
type: "language",
});
const nativeName = displayNames.of(lang.code);
return (
<button
key={lang.code}
onClick={() => onLocaleChange(lang.code)}
className={currentLocale === lang.code ? "active" : ""}
>
{nativeName}
</button>
);
})}
</div>
);
}
Each button displays the language name in its own script. Users recognize their language immediately regardless of the current interface language.
Building a currency selector component
Currency selectors benefit from localized currency names. This example creates a currency selector that adapts to the display language:
function CurrencySelector({ locale, value, onChange }) {
const currencyNames = new Intl.DisplayNames([locale], { type: "currency" });
const currencies = ["USD", "EUR", "GBP", "JPY", "CNY", "CAD", "AUD"];
return (
<select value={value} onChange={(e) => onChange(e.target.value)}>
<option value="">Select currency</option>
{currencies.map((code) => (
<option key={code} value={code}>
{code} - {currencyNames.of(code)}
</option>
))}
</select>
);
}
The dropdown shows both the currency code and the localized currency name. Users in different regions see currency names in their own language.
Getting all supported values
The Intl.supportedValuesOf() method returns arrays of all supported values for each type. This eliminates hardcoded lists of codes:
const regions = Intl.supportedValuesOf("region");
console.log(regions); // ["AD", "AE", "AF", "AG", "AI", ...]
const languages = Intl.supportedValuesOf("language");
console.log(languages); // ["aa", "ab", "ae", "af", "ak", ...]
const currencies = Intl.supportedValuesOf("currency");
console.log(currencies); // ["AED", "AFN", "ALL", "AMD", ...]
const calendars = Intl.supportedValuesOf("calendar");
console.log(calendars); // ["buddhist", "chinese", "coptic", ...]
Build dynamic selectors that automatically include all supported values:
function UniversalCountrySelector({ locale, value, onChange }) {
const regionNames = new Intl.DisplayNames([locale], { type: "region" });
const allRegions = Intl.supportedValuesOf("region");
return (
<select value={value} onChange={(e) => onChange(e.target.value)}>
<option value="">Select a country</option>
{allRegions.map((code) => (
<option key={code} value={code}>
{regionNames.of(code)}
</option>
))}
</select>
);
}
This component includes every region code supported by the browser without maintaining a hardcoded list.
Understanding code format requirements
Each type expects codes in specific formats. Incorrect formats produce fallback behavior rather than display names.
Region codes follow ISO 3166-1 alpha-2 (two letters) or UN M.49 (three digits):
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("US")); // "United States" (ISO 3166-1)
console.log(regionNames.of("001")); // "world" (UN M.49)
console.log(regionNames.of("150")); // "Europe" (UN M.49)
Language codes follow BCP 47, which combines ISO 639 language codes with optional region and script subtags:
const languageNames = new Intl.DisplayNames(["en"], { type: "language" });
console.log(languageNames.of("en")); // "English"
console.log(languageNames.of("en-US")); // "American English"
console.log(languageNames.of("zh-Hans")); // "Simplified Chinese"
console.log(languageNames.of("zh-Hans-CN")); // "Simplified Chinese (China)"
Currency codes follow ISO 4217 (three letters):
const currencyNames = new Intl.DisplayNames(["en"], { type: "currency" });
console.log(currencyNames.of("USD")); // "US Dollar"
console.log(currencyNames.of("EUR")); // "Euro"
Script codes follow ISO 15924 (four letters, capitalized):
const scriptNames = new Intl.DisplayNames(["en"], { type: "script" });
console.log(scriptNames.of("Latn")); // "Latin"
console.log(scriptNames.of("Arab")); // "Arabic"
Code comparison is case-insensitive, but following the standard capitalization improves readability:
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("US")); // "United States"
console.log(regionNames.of("us")); // "United States"
console.log(regionNames.of("Us")); // "United States"
Browser support and compatibility
The Intl.DisplayNames API became available across all major browsers in 2021. Modern applications can use it without polyfills.
The base API with language, region, script, and currency types has universal support. The calendar and dateTimeField types appeared in later browser versions but have broad support as of 2025.
Check feature support at runtime when necessary:
if (typeof Intl.DisplayNames !== "undefined") {
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("US"));
} else {
console.log("Intl.DisplayNames not supported");
}
For applications supporting older browsers, fall back to static lookup tables or third-party libraries when the API is unavailable.
Optimizing performance with caching
Creating DisplayNames instances has minimal overhead, but applications that convert many codes should reuse instances:
const cache = new Map();
function getDisplayNames(locale, type) {
const key = `${locale}-${type}`;
if (!cache.has(key)) {
cache.set(key, new Intl.DisplayNames([locale], { type }));
}
return cache.get(key);
}
function getCountryName(locale, code) {
const displayNames = getDisplayNames(locale, "region");
return displayNames.of(code);
}
console.log(getCountryName("en", "US")); // "United States"
console.log(getCountryName("en", "FR")); // "France"
console.log(getCountryName("es", "US")); // "Estados Unidos"
The cache stores instances keyed by locale and type. Subsequent calls reuse existing instances rather than creating new ones.
This pattern matters most in hot code paths that convert hundreds or thousands of codes, such as rendering large tables of localized data.
Comparing to alternative approaches
Before the Intl.DisplayNames API, applications used several approaches to convert codes into names.
Hardcoded lookup tables required maintenance and only supported predetermined languages:
const countryNames = {
US: "United States",
GB: "United Kingdom",
FR: "France",
};
function getCountryName(code) {
return countryNames[code] || code;
}
This approach breaks when adding new languages because each language needs a separate lookup table.
Third-party libraries provided localization data but increased bundle size:
import countries from "i18n-iso-countries";
import countriesEN from "i18n-iso-countries/langs/en.json";
import countriesES from "i18n-iso-countries/langs/es.json";
countries.registerLocale(countriesEN);
countries.registerLocale(countriesES);
console.log(countries.getName("US", "en")); // "United States"
console.log(countries.getName("US", "es")); // "Estados Unidos"
Libraries add kilobytes of data to the bundle and require updates when new countries appear or names change.
The Intl.DisplayNames API eliminates both problems. The browser maintains the data, keeping it current and eliminating bundle size concerns. The data supports all languages the browser supports without additional downloads.