I’ve been playing with Macro’s after reading Metaprogramming Elixir by @chrismccord.
As a result :phx_alt_routes
was born, albeit in a private repository. First I want to validate the concept. It already works with dead views and live views. Simply by
- creating one config module (adapter)
- replacing alias
MyWebApp.Router.Helpers
withuse MyWebApp.AltRoutes.Router.Helpers, MyWebApp.Router.Helpers
in my_web_app.ex - adding
Phx.AltRoutes.MountHelper
to the :live_view set. - adding
Phx.AltRoutes.Plug
to the connection plug set
Phx.AltRoutes.Router
Provides a set of macros for generating alternative Phoenix routes with configurable assignments.
When a Gettext
module is defined in the configuration, the alt_scope/2
macro uses it to build the alternative routes using the Gettext
module. This allows routes to be translated along with other Gettext
messages.
To summarize the process.
- The
alt_scope/2
macro splits the path of every nested route. - The segments are extracted into
routes.po
files usingmix gettext.extract
. - The individual segments are translated
- The translations are used to create additional alternative routes with path
{prefix}/{translated_segment1}/{translated_segment2}/
and helper{prefix}_{original_helper}
- For every alternative route the configured bindings are added to
assigns
andsession
. - A few helper assignments are also added, which can be used by
Phx.AltRoutes.Router.Helpers
Example
Given this configuration:
defmodule MyAppWeb.Phx.AltRoutes do
use Phx.AltRoutes,
routes: %{
"dutch" => %{
path_prefix: "nl",
bindings: %{locale: "nl_NL"},
},
"english" => %{
path_prefix: "en",
bindings: %{ocale: "en_GB"},
},
},
gettext_module: MyAppWeb.Gettext
To generate alternative routes for routes, those routes are nested in a alt_scope
.
defmodule MyAppWeb.Router do
use Phoenix.Router
alt_scope MyAppWeb.Phx.AltRoutes do
get "/users/:id/edit", UserController, :edit
get "/users/show/:id", UserController, :show
end
end
This will generate routes.po
files including the entries for users
, edit
and show
. You can translate the segments. The macro expand the routes during compile time with alternative variants. The example above is equal to:
defmodule MyAppWeb.Router do
use Phoenix.Router
scope "/" do
get "/users/:id/edit", UserController, :edit
get "/users/show/:id", UserController, :show
scope "/en" do
get "/users/:id/edit", UserController, :edit, assigns: %{locale: "en_GB", helper_prefix: "en"}, session: %{"locale": "en_GB", helper_prefix: "en"}, as: :en_user_edit_path
get "/users/show/:id", UserController, :show, assigns: %{locale: "en_GB", helper_prefix: "en"}, session: %{"locale": "en_GB", helper_prefix: "en"} , as: :en_user_show_path
end
scope "/nl" do
get "/gebruikers/:id/bewerken", UserController, :edit, assigns: %{locale: "nl_NL", helper_prefix: "nl"}, session: %{"locale": "nl_NL", helper_prefix: "nl"}, as: :nl_user_edit_path
get "/gebruikers/tonen/:id", UserController, :show, :edit, assigns: %{locale: "nl_NL", helper_prefix: "nl"}, session: %{"locale": "nl_NL", helper_prefix: "nl"}, as: :nl_user_show_path
end
end
The routes can be nested, which makes it easy to create /region/sub-region/
routes.
Phx.AltRoutes.Router.Helpers
Provides a macro that wraps Phoenix.Router.Helpers functions in order to generates the correct alternative route. It uses the helper_prefix assignment added to the session by Phx.AltRoutes.Router.
Thinking of it…the assignments can probably be fetched using only the helper_prefix key…