I like zaljir’s approach! I also just finished doing something like this and used Kip’s ex_cldr_plugs | Hex and ex_cldr_routes | Hex.
I wanted to try to get the user’s accept language header first and default to cldr’s default if not found.
Then I wanted to force all users to have a locale in the route.. then only respect the route’s locale after that.
Router looks like:
scope "/", MyAppWeb do
pipe_through :browser
get "/", PageController, :redirect_to_default_lang
localize do
get "/#{locale}", PageController, :home
live "/#{locale}/videos", VideoLive.Index, :index
live "/#{locale}/videos/new", VideoLive.Index, :new
live "/#{locale}/videos/:id/edit", VideoLive.Index, :edit
live "/#{locale}/videos/:id", VideoLive.Show, :show
live "/#{locale}/videos/:id/show/edit", VideoLive.Show, :edit
end
with this in the pipeline:
plug Cldr.Plug.PutLocale,
apps: [:cldr, :gettext],
from: [:route, :query, :path, :accept_language, :session],
gettext: MyAppWeb.Gettext,
cldr: MyApp.Cldr
So the plug finds the best language for the user based on route/accept language header, etc.
If the user visits the main page, it hits this redirect controller to get the best language and sends them off to the correct route ie. “/fr”. All navigation links after that expect a locale.
defmodule MyAppWeb.PageController do
use MyAppWeb, :controller
def redirect_to_default_lang(conn, _params) do
redirect(conn, to: "/#{MyApp.Cldr.get_locale().cldr_locale_name}")
end
end
and this puts the locale in the session:
defmodule MyAppWeb.RestoreLocale do
def on_mount(:default, _, %{"cldr_locale" => cldr_locale}, socket) do
MyApp.Cldr.put_locale(cldr_locale)
Gettext.put_locale(
MyAppWeb.Gettext,
Atom.to_string(MyApp.Cldr.get_locale().cldr_locale_name)
)
{:cont, socket}
end
def on_mount(:default, _params, _session, socket), do: {:cont, socket}
end






















