Как отображать названия стран на разных языках?

Используйте Intl.DisplayNames для преобразования кодов стран в локализованные названия стран для международных пользователей.

Введение

Когда вы создаёте форму доставки, страницу профиля пользователя или селектор адресов, вам нужно отображать названия стран. Пользователи видят "France" на английском, "Francia" на испанском, "Frankreich" на немецком и "フランス" на японском. Каждый пользователь ожидает видеть названия стран, написанные на их родном языке.

Ваше приложение хранит коды стран, такие как FR, US или JP, в базах данных и API. Эти стандартизированные коды работают во всех системах, но пользователям нужны читаемые названия. API Intl.DisplayNames преобразует коды стран в локализованные названия стран на любом языке без необходимости поддерживать таблицы переводов или зависеть от внешних библиотек.

Понимание кодов стран

Страны идентифицируются двухбуквенными кодами, определёнными в стандарте ISO 3166-1 alpha-2. Каждая страна получает уникальный код, который остаётся неизменным во всех языках и системах.

// Общие коды стран
// US = Соединённые Штаты
// GB = Великобритания (Соединённое Королевство)
// FR = Франция
// DE = Германия (Deutschland)
// JP = Япония
// CN = Китай
// BR = Бразилия
// IN = Индия

Эти коды используются в формах, URL-адресах, базах данных и API. Код US всегда означает Соединённые Штаты, независимо от того, работает ли ваше приложение на английском, испанском, японском или любом другом языке. Код обеспечивает стабильный идентификатор, в то время как отображаемое название меняется в зависимости от языка пользователя.

Использование Intl.DisplayNames для получения названий стран

Конструктор Intl.DisplayNames создаёт форматтер, который преобразует коды стран в названия стран. Вы указываете локаль и задаёте тип "region", чтобы получить названия стран.

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

console.log(countryNames.of("US"));
// "Соединённые Штаты"

console.log(countryNames.of("FR"));
// "Франция"

console.log(countryNames.of("JP"));
// "Япония"

Первый аргумент — это массив идентификаторов локалей. Опция type: "region" указывает форматтеру, что вы хотите получить названия стран или регионов. Метод of() принимает код страны и возвращает его локализованное название.

Термин "region" охватывает страны, территории и географические области. Это включает независимые страны, такие как Франция, территории, такие как Пуэрто-Рико, и специальные регионы, такие как Европейский Союз.

Отображение названий стран на разных языках

Один и тот же код страны отображает разные названия на разных языках. Создайте форматтеры для разных локалей, чтобы увидеть, как меняются названия стран.

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"));
// "フランス"

Каждый форматтер возвращает название страны в своей локали отображения. Это упрощает задачу поддержания переводов названий стран на разных языках.

Вы можете создать функцию, которая получает названия стран на любом языке.

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"

Эта функция работает с любой комбинацией кода страны и локали. Браузер автоматически предоставляет переводы.

Создание селектора стран

Один из распространенных случаев использования — создание выпадающего списка, где пользователи выбирают свою страну. Названия стран должны отображаться на языке пользователя.

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.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);

Этот код создает выпадающий список с названиями стран на английском языке. Измените локаль на "es", и та же функция создаст список с названиями стран на испанском. Измените на "ja", и названия появятся на японском.

Вы можете сделать так, чтобы селектор реагировал на язык браузера пользователя.

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

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

Селектор автоматически отображает названия стран на предпочитаемом языке пользователя, основываясь на настройках его браузера.

Получение всех доступных стран

Метод Intl.supportedValuesOf() возвращает массив всех поддерживаемых кодов стран. Это исключает необходимость поддерживать жестко заданный список.

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

console.log(allCountries.length);
// 249 (приблизительное количество на 2025 год)

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

Метод возвращает коды в алфавитном порядке по коду, а не по названию страны. Если вы хотите получить алфавитный порядок на определённом языке, необходимо сортировать по локализованным названиям.

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" }
// ]

Порядок сортировки различается в зависимости от языка, так как названия стран сортируются по-разному в разных алфавитах и правилах колlation.

Создание комплексного селектора стран

Объедините Intl.supportedValuesOf() с Intl.DisplayNames, чтобы создать селектор со всеми доступными странами.

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.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);

Этот селектор включает все 249 стран и территорий, поддерживаемых браузером, отсортированных в алфавитном порядке на языке пользователя.

Обработка недопустимых кодов стран

Не все двухбуквенные строки являются допустимыми кодами стран. Метод of() обрабатывает недопустимые коды на основе опции fallback.

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

Опция fallback: "code" возвращает входной код, если страна не существует. Опция fallback: "none" возвращает undefined для недопустимых кодов.

Используйте fallback: "none", если вам нужно обнаруживать недопустимые коды и обрабатывать их явно.

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

  const name = names.of(code);

  if (name === undefined) {
    return "Неизвестная страна";
  }

  return name;
}

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

console.log(getValidatedCountryName("INVALID", "en"));
// "Неизвестная страна"

Этот подход помогает проверять пользовательский ввод или данные из внешних источников.

Управление длиной названий стран с помощью стиля

Опция style управляет тем, как отображаются названия стран. Три значения дают разную длину вывода.

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"

Стиль long используется по умолчанию и выводит полные названия стран. Стили short и narrow возвращают сокращенные формы, если они доступны. Для большинства стран стили short и narrow возвращают сам код страны.

Некоторые страны имеют отдельные сокращенные формы.

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"

Используйте стиль long по умолчанию для большинства интерфейсов. Используйте short или narrow, если пространство ограничено, например, в мобильной навигации или компактных таблицах.

Отображение названий регионов для территорий

Стандарт ISO 3166-1 включает территории, зависимые и специальные области за пределами независимых стран. API Intl.DisplayNames также обрабатывает их.

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

console.log(regionNames.of("PR"));
// "Пуэрто-Рико"

console.log(regionNames.of("GU"));
// "Гуам"

console.log(regionNames.of("HK"));
// "Гонконг"

console.log(regionNames.of("MQ"));
// "Мартиника"

console.log(regionNames.of("GF"));
// "Французская Гвиана"

Эти коды работают так же, как и коды стран. Ваше приложение может обрабатывать их одинаково, в то время как браузер предоставляет соответствующие локализованные названия.

Использование числовых кодов регионов

Стандарт ISO 3166-1 также определяет числовые коды. API Intl.DisplayNames принимает числовые коды регионов UN M.49 в дополнение к двухбуквенным кодам.

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

console.log(regionNames.of("840"));
// "Соединенные Штаты"

console.log(regionNames.of("250"));
// "Франция"

console.log(regionNames.of("392"));
// "Япония"

Числовые коды также представляют более крупные географические регионы.

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

console.log(regionNames.of("150"));
// "Европа"

console.log(regionNames.of("019"));
// "Америка"

console.log(regionNames.of("142"));
// "Азия"

console.log(regionNames.of("002"));
// "Африка"

console.log(regionNames.of("009"));
// "Океания"

Эти коды работают на разных языках.

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"

Используйте числовые коды, если вам нужно избежать проблем с кодировкой символов или работать с системами, использующими коды UN M.49.

Кэширование экземпляров DisplayNames для повышения производительности

Создание экземпляров Intl.DisplayNames имеет минимальные накладные расходы, но приложения, которые преобразуют множество кодов стран, могут выиграть от кэширования форматтеров.

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"));
// "Соединенные Штаты"

console.log(getCountryName("FR", "en"));
// "Франция"

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

Кэш хранит форматтеры, привязанные к локали и типу. Последующие вызовы повторно используют существующие форматтеры вместо создания новых.

Эта оптимизация наиболее важна при отображении больших списков стран или обработке сотен кодов стран в таблицах или сетках данных.

Обработка резервных локалей

Конструктор Intl.DisplayNames принимает массив локалей. Если первая локаль не поддерживается, браузер переходит к следующей локали в массиве.

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

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

Браузер сначала пытается использовать "xx-XX", которая не существует, затем переходит к "en". Это гарантирует, что ваш код будет работать, даже если запрашиваемая локаль недоступна.

Вы можете проверить, какую локаль на самом деле использует форматтер.

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

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

Метод resolvedOptions() возвращает локаль, к которой форматтер пришел после обработки резервных вариантов.

Сравнение названий стран на разных языках

Разные языки по-разному форматируют названия стран. В некоторых языках названия стран пишутся с заглавной буквы, в других — нет. В некоторых языках используются артикли, в других — нет.

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"

Форматтер автоматически обрабатывает все эти языковые особенности. Вам не нужно знать грамматические правила для каждого языка.

Поддержка браузерами

API Intl.DisplayNames с параметром type: "region" доступно во всех современных браузерах. Оно поддерживается с 2021 года в основных браузерах, включая Chrome, Firefox, Safari и Edge.

Современные приложения могут использовать это API без полифилов или резервных вариантов. Браузер поддерживает данные о названиях стран и обновляет их по мере изменения стран и территорий.

Вы можете проверить доступность API перед его использованием.

if (typeof Intl.DisplayNames !== "undefined") {
  const names = new Intl.DisplayNames(["en"], { type: "region" });
  console.log(names.of("US"));
} else {
  console.log("Intl.DisplayNames не поддерживается");
}

Для приложений, поддерживающих старые браузеры, предоставьте резервный вариант с использованием статической таблицы названий стран.

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"

Это гарантирует, что ваше приложение будет работать во всех браузерах, хотя в старых браузерах будет отсутствовать функция автоматической локализации.