国名を異なる言語で表示するにはどうすればよいですか?

Intl.DisplayNamesを使用して、国コードを国際的なユーザー向けにローカライズされた国名に変換します。

はじめに

配送フォーム、ユーザープロフィールページ、または住所セレクターを構築する際、国名を表示する必要があります。ユーザーは英語では「France」、スペイン語では「Francia」、ドイツ語では「Frankreich」、日本語では「フランス」と表示されることを期待します。各ユーザーは自分の言語で書かれた国名を見ることを期待しています。

アプリケーションはデータベースやAPIにFRUSJPなどの国コードを保存します。これらの標準化されたコードはすべてのシステムで機能しますが、ユーザーには人間が読める名前が必要です。Intl.DisplayNames APIは、翻訳テーブルを維持したり外部ライブラリに依存したりすることなく、国コードをどの言語でもローカライズされた国名に変換します。

国コードについて理解する

国はISO 3166-1 alpha-2規格で定義された2文字のコードで識別されます。各国には、すべての言語とシステムで一定のままである固有のコードが割り当てられています。

// 一般的な国コード
// US = United States(アメリカ合衆国)
// GB = Great Britain(イギリス/英国)
// FR = France(フランス)
// DE = Germany(ドイツ)
// JP = Japan(日本)
// CN = China(中国)
// BR = Brazil(ブラジル)
// IN = India(インド)

これらのコードはフォーム、URL、データベース、APIに表示されます。コードUSは、アプリケーションが英語、スペイン語、日本語、またはその他の言語で実行されているかどうかにかかわらず、常にアメリカ合衆国を意味します。コードはユーザーの言語に基づいて表示名が変わる中で、安定した識別子を提供します。

Intl.DisplayNamesを使用して国名を取得する

Intl.DisplayNamesコンストラクタは、国コードを国名に変換するフォーマッタを作成します。ロケールを指定し、タイプを"region"`に設定して国名を取得します。

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"

最初の引数はロケール識別子の配列です。type: "region"オプションは、国または地域の名前が必要であることをフォーマッタに伝えます。of()メソッドは国コードを受け取り、そのローカライズされた名前を返します。

「地域」という用語は、国、領土、地理的領域をカバーします。これにはフランスのような独立国、プエルトリコのような領土、欧州連合のような特別な地域が含まれます。

異なる言語での国名の表示

同じ国コードでも、異なる言語では異なる名前が生成されます。異なるロケールのフォーマッターを作成して、国名がどのように変化するかを確認しましょう。

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

これにより、英語の国名を持つドロップダウンが作成されます。ロケールを"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" }
// ]

言語によってソート順が異なるのは、国名が異なるアルファベットや照合規則で異なる方法でソートされるためです。

包括的な国セレクターの構築

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の国と地域がすべて含まれており、ユーザーの言語でアルファベット順にソートされています。

無効な国コードの処理

すべての2文字の文字列が有効な国コードというわけではありません。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 "Unknown country";
  }

  return name;
}

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

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

このパターンは、ユーザー入力や外部ソースからのデータを検証するのに役立ちます。

スタイルによる国名の長さの制御

styleオプションは国名の表示方法を制御します。3つの値で異なる出力長が生成されます。

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スタイルがデフォルトで、完全な国名を生成します。shortnarrowスタイルは、利用可能な場合に省略形を返します。ほとんどの国では、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規格には、独立国家以外にも領土、属国、特別地域が含まれています。Intl.DisplayNames APIはこれらも同様に処理します。

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"

これらのコードは国コードと同じように機能します。アプリケーションはこれらを均一に扱いながら、ブラウザが適切にローカライズされた名前を提供します。

数値地域コードの使用

ISO 3166-1規格では数値コードも定義されています。Intl.DisplayNames APIは2文字コードに加えて、国連M.49数値地域コードも受け付けます。

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"

数値コードはより大きな地理的地域も表します。

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"

これらのコードは言語を超えて機能します。

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"

文字エンコーディングの問題を回避したい場合や、国連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"));
// "United States"

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

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"

フォーマッタはこれらの言語的慣習をすべて自動的に処理します。各言語の文法規則を知る必要はありません。

ブラウザサポート

type: "region"を使用したIntl.DisplayNames APIはすべての最新ブラウザで利用可能です。Chrome、Firefox、Safari、Edgeなどの主要ブラウザでは2021年以降サポートされています。

最新のアプリケーションではポリフィルやフォールバックなしでこの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 is not supported");
}

古いブラウザをサポートするアプリケーションでは、国名の静的ルックアップテーブルを使用してフォールバックを提供します。

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"

これにより、すべてのブラウザでアプリケーションが機能することが保証されますが、古いブラウザでは自動ローカライゼーション機能が失われます。