Phoenix Multilingual

Phoenix Multilingual simplifies handling localized routes in Elixir Phoenix applications, with and without LiveView.

Rationale

In Phoenix Multilingual, "view" means a page in an application, which can be rendered in one or more languages.

When a site is localized, it is important to know which paths are the various localizations of a specific view.

For example, a site may have a page about the company, the "about page". This page may be available in multiple languages, such as English and Italian. The English path would be /about and /it/chi-siamo the Italian version.

Localized site commonly need these things:

To achieve all this, somewhere, for each localized view, there needs to be a mapping like this:

This library is based on the idea that it is better to put such localization information directly in the router.

Route Metadata

Fortunately, the Phoenix.Router allows metadata to be added to route declarations.

With Phoenix Multilingual, you add metadata to indicate the locale of each localized view.

You can do this via a helper:

import PhoenixMultilingual.Routes, only: [metadata: 1]

...

get "/", PageController, :index, metadata("zh")

metadata/1 sets the options for the route, specifically, setting the locale as the metadata for this library.

It's the same if you do this:

get "/", PageController, :index, metadata: [multilingual: %{locale: "zh"}]

How Paths Are Grouped

Consider these routes:

get "/", PageController, :index, metadata("en")
get "/zh", PageController, :index, metadata("zh")

As they have the same plug (PageController) and plug_opts (:index), Multilingual groups them to create the mapping that we need between localized versions of the same view.

From the above, we can deduce that "/" and "/zh" are the same view, but in different languages.

So, by default plug_opts is used to identify the view. This has the limitation that only one action is used for each view.

If you want to have multiple actions for the same view, you can use the metadata/2 function in the metadata to override the plug_opts by specifying a view alongside the locale:

import Multilingual.Routes, only: [metadata: 2]

...

get "/", PageController, :index_zh, metadata(:index, "zh")
get "/en", PageController, :index_en, metadata(:index, "en")

So, setting this view in a route's metadata allows routes with different values of plug_opts to be grouped together.

Route Organization

Phoenix Multilingual places no restrictions on how you structure your router declarations.

You can group the localized versions under scopes, with path prefixes:

scope "/", MyAppWeb do
  get "/", PageController, :index, metadata("en")
end

scope "/zh", MyAppWeb do
  get "/", PageController, :index, metadata("zh")
end

Otherwise, you can group the localized versions of a view together:

scope "/", MyAppWeb do
  get "/", PageController, :index, metadata("en")
  get "/zh", PageController, :index, metadata("zh")
end

If the path itself is localized, it's easy to follow what's going on:

scope "/", MyAppWeb do
  get "/about", PageController, :index, metadata("en")
  get "/it/chi-siamo", PageController, :index, metadata("it")
end

mix multilingual.routes

If you want to check how your localized routes are configured, there is a Mix task:

$ mix multilingual.routes
method  module                   view    en      it
get     MyAppWeb.PageController  :index  /about  /it/chi-siamo

Using Multilingual Routes

With you routes set up, you can then make use of the information they give via the following modules and functions.

This works by first storing the current path and locale (the 'LocalizedView') in the conn or, the socket for LiveViews, and then using that information to take further actions.

Plugs for the Router

LiveView Hooks

HTML Generation