357 words, 2 min read

Unlike JavaScript's Intl.DisplayNames, Elixir doesn't provide built-in localization for country names. However, with the help of the excellent ex_cldr_countries package, you can easily achieve dynamic, localized country translations backed by official Unicode CLDR data.

Installation

Add the package to your mix.exs:

defp deps do
  [
    {:ex_cldr_countries, "~> 2.0"}
  ]
end

Then fetch it:

mix deps.get

Setting Up a Backend

Most examples online show calling Cldr.Countries.from_iso/2 directly, but modern ex_cldr usage requires a backend module. Without one, you're relying on a default backend that may not be configured — and you lose control over which locales get compiled in.

Create a backend module in your app:

# lib/my_app/cldr.ex
defmodule MyApp.Cldr do
  use Cldr,
    locales: ["en", "fr", "nl"],
    default_locale: "en",
    providers: [Cldr.Countries]
end

The locales list determines which translations get compiled into your app. Keep it to what you actually need — CLDR data is large and including everything will bloat your build.

Translating Country Codes

With the backend in place, translating a country code is straightforward:

MyApp.Cldr.Countries.from_iso(:BE, locale: "fr")
# => {:ok, "Belgique"}

MyApp.Cldr.Countries.from_iso(:NL, locale: "en")
# => {:ok, "Netherlands"}

MyApp.Cldr.Countries.from_iso(:DE, locale: "nl")
# => {:ok, "Duitsland"}
  • The first argument is the ISO 3166-1 Alpha-2 code as an atom (:BE, :NL, :DE, …)
  • The locale option sets the output language
  • If the translation can't be found, it returns an {:error, reason} tuple, so it's safe to pattern match on

Why This Approach

The backend module gives you three concrete benefits:

  1. Scoped locale compilation — only the locales you list get compiled, keeping your build lean
  2. Explicit and testable — the backend is a real module you can reference directly in tests
  3. No global state surprises — the bare Cldr.* namespace is just a shim that delegates to whichever backend is configured as the default; using your own backend is always more predictable

For most Phoenix applications, dropping this into a lib/my_app/cldr.ex file is all the setup you need.