shipped first production liveview last week - I ended up wrapping everything in a liveview that holds state with locale etc - and then render pages (liveview components) depending on the action - so it’s kinda a router as well…
to make matters interesting it’s cookieless - so no passing the locale in the session… had to do:
in my custom plug:
%{req_headers: req_headers} = conn
browser_accept_lang =
with {_key, value} <- Enum.find(req_headers, fn {key, _val} -> key == "accept-language" end),
{:ok, cldr} <- Cldr.AcceptLanguage.best_match(value, MyApp.Cldr)
do
cldr.language
else
_err -> "en"
end
conn
|> assign(:browser_accept_lang, browser_accept_lang)
|> assign(:conn_lang, Cldr.Plug.SetLocale.get_cldr_locale(conn).language)
browser_accept_lang is the browser locale - conn_lang could be different if the user is on /:locale/some_page - the diff is needed to conditionally rewrite uris with /:locale
then in root template: (remember we have no session to pass things through easily)
<meta name="waccept-lang" content="<%= assigns[:conn_lang] %>">
<meta name="browser_accept_lang" content="<%= assigns[:browser_accept_lang] %>">
in the liveview: so that the initial render is in correct lang - and then socket connects with locale params, so we also have them on “the socket” - see below:
@impl true
def mount(_params, _session, socket) do
# get js client connect params
connect_params = get_connect_params(socket)
{conn_assigns, _} = socket.private.assign_new
js_lang =
if connect_params do
Map.get(connect_params, "conn_lang")
else
nil
end
lang = Map.get(conn_assigns, :conn_lang) || js_lang || "en"
browser_accept_lang =
if connect_params do
Map.get(connect_params, "browser_accept_lang")
else
nil
end
browser_accept_lang = Map.get(conn_assigns, :browser_accept_lang) || browser_accept_lang || "en"
latest_post = MyApp.Journal.list_posts(lang) |> List.first()
{:ok,
assign(socket, navigate_counter: 0, original_lang: lang, lang: lang, browser_accept_lang: browser_accept_lang, latest_post: latest_post)}
end
in the js:
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let conn_lang = document.querySelector("meta[name='waccept-lang']").getAttribute("content")
let browser_accept_lang = document.querySelector("meta[name='browser_accept_lang']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks, params: {_csrf_token: csrfToken, conn_lang: conn_lang, browser_accept_lang: browser_accept_lang}})