How do I display country names in different languages?

Use Intl.DisplayNames to convert country codes into localized country names for international users.

Introduction

When you build a shipping form, a user profile page, or an address selector, you need to display country names. Users see "France" in English, "Francia" in Spanish, "Frankreich" in German, and "フランス" in Japanese. Each user expects to see country names written in their own language.

Your application stores country codes like FR, US, or JP in databases and APIs. These standardized codes work across all systems, but users need human-readable names. The Intl.DisplayNames API converts country codes into localized country names in any language without maintaining translation tables or depending on external libraries.

Understanding country codes

Countries are identified by two-letter codes defined in the ISO 3166-1 alpha-2 standard. Each country receives a unique code that remains constant across all languages and systems.

// Common country codes
// US = United States
// GB = Great Britain (United Kingdom)
// FR = France
// DE = Germany (Deutschland)
// JP = Japan
// CN = China
// BR = Brazil
// IN = India

These codes appear in forms, URLs, databases, and APIs. The code US always means United States, whether your application runs in English, Spanish, Japanese, or any other language. The code provides a stable identifier while the display name changes based on the user's language.

Using Intl.DisplayNames to get country names

The Intl.DisplayNames constructor creates a formatter that converts country codes into country names. You specify a locale and set the type to "region" to get country names.

const countryNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(countryNames.of("US"));
// "United States"

console.log(countryNames.of("FR"));
// "France"

console.log(countryNames.of("JP"));
// "Japan"

The first argument is an array of locale identifiers. The type: "region" option tells the formatter you want country or region names. The of() method takes a country code and returns its localized name.

The term "region" covers countries, territories, and geographic areas. This includes independent countries like France, territories like Puerto Rico, and special regions like the European Union.

Displaying country names in different languages

The same country code produces different names in different languages. Create formatters for different locales to see how country names change.

const englishNames = new Intl.DisplayNames(["en"], { type: "region" });
const spanishNames = new Intl.DisplayNames(["es"], { type: "region" });
const germanNames = new Intl.DisplayNames(["de"], { type: "region" });
const japaneseNames = new Intl.DisplayNames(["ja"], { type: "region" });

console.log(englishNames.of("FR"));
// "France"

console.log(spanishNames.of("FR"));
// "Francia"

console.log(germanNames.of("FR"));
// "Frankreich"

console.log(japaneseNames.of("FR"));
// "フランス"

Each formatter returns the country name in its display locale. This handles all the complexity of maintaining country name translations across languages.

You can create a function that gets country names in any language.

function getCountryName(countryCode, locale) {
  const names = new Intl.DisplayNames([locale], { type: "region" });
  return names.of(countryCode);
}

console.log(getCountryName("US", "en"));
// "United States"

console.log(getCountryName("US", "fr"));
// "États-Unis"

console.log(getCountryName("US", "ar"));
// "الولايات المتحدة"

console.log(getCountryName("DE", "en"));
// "Germany"

console.log(getCountryName("DE", "de"));
// "Deutschland"

console.log(getCountryName("DE", "es"));
// "Alemania"

This function works for any combination of country code and locale. The browser provides the translations automatically.

Building a country selector

A common use case is building a dropdown where users select their country. The country names should appear in the user's language.

function createCountrySelector(locale) {
  const countryNames = new Intl.DisplayNames([locale], { type: "region" });

  const countries = [
    "US", "GB", "CA", "AU", "FR", "DE", "ES", "IT",
    "JP", "CN", "KR", "IN", "BR", "MX", "AR", "RU"
  ];

  const select = document.createElement("select");
  select.id = "country";
  select.name = "country";

  const placeholder = document.createElement("option");
  placeholder.value = "";
  placeholder.textContent = "Select a country";
  select.appendChild(placeholder);

  countries.forEach((code) => {
    const option = document.createElement("option");
    option.value = code;
    option.textContent = countryNames.of(code);
    select.appendChild(option);
  });

  return select;
}

const selector = createCountrySelector("en");
document.body.appendChild(selector);

This creates a dropdown with country names in English. Change the locale to "es" and the same function produces a dropdown with Spanish country names. Change it to "ja" and the names appear in Japanese.

You can make the selector respond to the user's browser language.

function createLocalizedCountrySelector() {
  const userLocale = navigator.language;
  return createCountrySelector(userLocale);
}

const selector = createLocalizedCountrySelector();
document.body.appendChild(selector);

The selector automatically displays country names in the user's preferred language based on their browser settings.

Getting all available countries

The Intl.supportedValuesOf() method returns an array of all supported country codes. This eliminates the need to maintain a hardcoded list.

const allCountries = Intl.supportedValuesOf("region");

console.log(allCountries.length);
// 249 (approximate count as of 2025)

console.log(allCountries.slice(0, 10));
// ["AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ"]

The method returns codes in alphabetical order by code, not by country name. You need to sort by localized names if you want alphabetical order in a specific language.

function getSortedCountries(locale) {
  const countryNames = new Intl.DisplayNames([locale], { type: "region" });
  const allCountries = Intl.supportedValuesOf("region");

  return allCountries
    .map((code) => ({
      code,
      name: countryNames.of(code)
    }))
    .sort((a, b) => a.name.localeCompare(b.name, locale));
}

const sortedEnglish = getSortedCountries("en");
console.log(sortedEnglish.slice(0, 5));
// [
//   { code: "AF", name: "Afghanistan" },
//   { code: "AX", name: "Åland Islands" },
//   { code: "AL", name: "Albania" },
//   { code: "DZ", name: "Algeria" },
//   { code: "AS", name: "American Samoa" }
// ]

const sortedSpanish = getSortedCountries("es");
console.log(sortedSpanish.slice(0, 5));
// [
//   { code: "AF", name: "Afganistán" },
//   { code: "AL", name: "Albania" },
//   { code: "DE", name: "Alemania" },
//   { code: "AD", name: "Andorra" },
//   { code: "AO", name: "Angola" }
// ]

The sort order differs between languages because country names sort differently in different alphabets and collation rules.

Building a comprehensive country selector

Combine Intl.supportedValuesOf() with Intl.DisplayNames to create a selector with all available countries.

function createComprehensiveCountrySelector(locale) {
  const countryNames = new Intl.DisplayNames([locale], { type: "region" });
  const allCountries = Intl.supportedValuesOf("region");

  const sortedCountries = allCountries
    .map((code) => ({
      code,
      name: countryNames.of(code)
    }))
    .sort((a, b) => a.name.localeCompare(b.name, locale));

  const select = document.createElement("select");
  select.id = "country";
  select.name = "country";

  const placeholder = document.createElement("option");
  placeholder.value = "";
  placeholder.textContent = "Select a country";
  select.appendChild(placeholder);

  sortedCountries.forEach(({ code, name }) => {
    const option = document.createElement("option");
    option.value = code;
    option.textContent = name;
    select.appendChild(option);
  });

  return select;
}

const selector = createComprehensiveCountrySelector("en");
document.body.appendChild(selector);

This selector includes all 249 countries and territories supported by the browser, sorted alphabetically in the user's language.

Handling invalid country codes

Not all two-letter strings are valid country codes. The of() method handles invalid codes based on the fallback option.

const withCodeFallback = new Intl.DisplayNames(["en"], {
  type: "region",
  fallback: "code"
});

const withNoneFallback = new Intl.DisplayNames(["en"], {
  type: "region",
  fallback: "none"
});

console.log(withCodeFallback.of("US"));
// "United States"

console.log(withCodeFallback.of("XX"));
// "XX"

console.log(withNoneFallback.of("US"));
// "United States"

console.log(withNoneFallback.of("XX"));
// undefined

The fallback: "code" option returns the input code when no country exists. The fallback: "none" option returns undefined for invalid codes.

Use fallback: "none" when you need to detect invalid codes and handle them explicitly.

function getValidatedCountryName(code, locale) {
  const names = new Intl.DisplayNames([locale], {
    type: "region",
    fallback: "none"
  });

  const name = names.of(code);

  if (name === undefined) {
    return "Unknown country";
  }

  return name;
}

console.log(getValidatedCountryName("US", "en"));
// "United States"

console.log(getValidatedCountryName("INVALID", "en"));
// "Unknown country"

This pattern helps you validate user input or data from external sources.

Controlling country name length with style

The style option controls how country names appear. Three values produce different output 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 is the default and produces full country names. The short and narrow styles return abbreviated forms when available. For most countries, the short and narrow styles return the country code itself.

Some countries have distinct short forms.

const longNames = new Intl.DisplayNames(["en"], {
  type: "region",
  style: "long"
});

const shortNames = new Intl.DisplayNames(["en"], {
  type: "region",
  style: "short"
});

console.log(longNames.of("GB"));
// "United Kingdom"

console.log(shortNames.of("GB"));
// "UK"

console.log(longNames.of("BO"));
// "Bolivia"

console.log(shortNames.of("BO"));
// "Bolivia"

Use the default long style for most interfaces. Use short or narrow when space is limited, such as in mobile navigation or compact tables.

Displaying region names for territories

The ISO 3166-1 standard includes territories, dependencies, and special areas beyond independent countries. The Intl.DisplayNames API handles these as well.

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("PR"));
// "Puerto Rico"

console.log(regionNames.of("GU"));
// "Guam"

console.log(regionNames.of("HK"));
// "Hong Kong"

console.log(regionNames.of("MQ"));
// "Martinique"

console.log(regionNames.of("GF"));
// "French Guiana"

These codes work the same way as country codes. Your application can treat them uniformly while the browser provides appropriate localized names.

Using numeric region codes

The ISO 3166-1 standard also defines numeric codes. The Intl.DisplayNames API accepts UN M.49 numeric region codes in addition to two-letter codes.

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("840"));
// "United States"

console.log(regionNames.of("250"));
// "France"

console.log(regionNames.of("392"));
// "Japan"

Numeric codes also represent larger geographic regions.

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("150"));
// "Europe"

console.log(regionNames.of("019"));
// "Americas"

console.log(regionNames.of("142"));
// "Asia"

console.log(regionNames.of("002"));
// "Africa"

console.log(regionNames.of("009"));
// "Oceania"

These codes work across languages.

const englishRegions = new Intl.DisplayNames(["en"], { type: "region" });
const spanishRegions = new Intl.DisplayNames(["es"], { type: "region" });

console.log(englishRegions.of("150"));
// "Europe"

console.log(spanishRegions.of("150"));
// "Europa"

Use numeric codes when you need to avoid character encoding issues or work with systems that use UN M.49 codes.

Caching DisplayNames instances for performance

Creating Intl.DisplayNames instances has minimal overhead, but applications that convert many country codes can benefit from caching formatters.

const displayNamesCache = new Map();

function getDisplayNames(locale, type) {
  const key = `${locale}-${type}`;

  if (!displayNamesCache.has(key)) {
    displayNamesCache.set(
      key,
      new Intl.DisplayNames([locale], { type })
    );
  }

  return displayNamesCache.get(key);
}

function getCountryName(code, locale) {
  const formatter = getDisplayNames(locale, "region");
  return formatter.of(code);
}

console.log(getCountryName("US", "en"));
// "United States"

console.log(getCountryName("FR", "en"));
// "France"

console.log(getCountryName("US", "es"));
// "Estados Unidos"

The cache stores formatters keyed by locale and type. Subsequent calls reuse existing formatters rather than creating new ones.

This optimization matters most when rendering large lists of countries or processing hundreds of country codes in tables or data grids.

Handling locale fallbacks

The Intl.DisplayNames constructor accepts an array of locales. If the first locale is not supported, the browser falls back to the next locale in the array.

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "region" });

console.log(names.of("US"));
// "United States"

The browser tries "xx-XX" first, which does not exist, then falls back to "en". This ensures your code works even when the requested locale is unavailable.

You can check which locale the formatter actually uses.

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "region" });

console.log(names.resolvedOptions().locale);
// "en"

The resolvedOptions() method returns the locale the formatter resolved to after fallback processing.

Comparing country names across languages

Different languages format country names differently. Some languages capitalize country names, others do not. Some languages include articles, others do not.

const english = new Intl.DisplayNames(["en"], { type: "region" });
const french = new Intl.DisplayNames(["fr"], { type: "region" });
const german = new Intl.DisplayNames(["de"], { type: "region" });

console.log(english.of("US"));
// "United States"

console.log(french.of("US"));
// "États-Unis"

console.log(german.of("US"));
// "Vereinigte Staaten"

console.log(english.of("NL"));
// "Netherlands"

console.log(french.of("NL"));
// "Pays-Bas"

console.log(german.of("NL"));
// "Niederlande"

The formatter handles all these linguistic conventions automatically. You do not need to know the grammar rules for each language.

Browser support

The Intl.DisplayNames API with type: "region" is available in all modern browsers. It has been supported since 2021 across major browsers including Chrome, Firefox, Safari, and Edge.

Modern applications can use this API without polyfills or fallbacks. The browser maintains the country name data and keeps it current as countries and territories change.

You can check if the API is available before using it.

if (typeof Intl.DisplayNames !== "undefined") {
  const names = new Intl.DisplayNames(["en"], { type: "region" });
  console.log(names.of("US"));
} else {
  console.log("Intl.DisplayNames is not supported");
}

For applications supporting older browsers, provide a fallback using a static lookup table of country names.

function getCountryName(code, locale) {
  if (typeof Intl.DisplayNames !== "undefined") {
    const names = new Intl.DisplayNames([locale], { type: "region" });
    return names.of(code);
  }

  const fallbackNames = {
    US: "United States",
    GB: "United Kingdom",
    FR: "France",
    DE: "Germany",
    JP: "Japan"
  };

  return fallbackNames[code] || code;
}

console.log(getCountryName("US", "en"));
// "United States"

This ensures your application works in all browsers, though older browsers lose the automatic localization feature.