A rainy Saturday is an opportunity to publish the first release of ex_cldr_routes that supports localised route generation and localised path helpers. Localised routes allow a user to enter URLs in their local language yet still route to the correct controller and action. Similarly, localised path helpers generate paths in the users locale. Here’s a simple example:
Route generators
# First, add the `Cldr.Routes` provider to a `Cldr` backend module configuration
# And ensure that a `Gettext` module is also configured (this is use for the
# translation process)
defmodule MyApp.Cldr do
use Cldr,
locales: ["en", "fr"],
default_locale: "en",
gettext: MyAppWeb.Gettext,
providers: [Cldr.Routes]
end
# Then add `use MyApp.Cldr.Routes` to your router after
# `use Phoenix.Router`
defmodule MyApp.Router do
use Phoenix.Router
use MyApp.Cldr.Routes
# The localize/1 macro wraps the normal route definitions
# and it will generate localised versions of these routes at
# compile time.
localize do
get "/pages/:page", PageController, :show, assigns: %{key: :value}
resources "/users", UserController do
resources "/faces", UserController
end
end
Now we can see what routes have been generated:
% mix phx.routes MyApp.Router
Compiling 3 files (.ex)
Generating MyApp.Cldr for 3 locales named [:en, :fr, :und] with a default locale named :en
page_path GET /pages/:page PageController :show
page_path GET /pages_fr/:page PageController :show
user_path GET /users UserController :index
user_path GET /users/:id/edit UserController :edit
user_path GET /users/new UserController :new
user_path GET /users/:id UserController :show
user_path POST /users UserController :create
user_path PATCH /users/:id UserController :update
PUT /users/:id UserController :update
user_path DELETE /users/:id UserController :delete
user_user_path GET /users/:user_id/faces UserController :index
user_user_path GET /users/:user_id/faces/:id/edit UserController :edit
user_user_path GET /users/:user_id/faces/new UserController :new
user_user_path GET /users/:user_id/faces/:id UserController :show
user_user_path POST /users/:user_id/faces UserController :create
user_user_path PATCH /users/:user_id/faces/:id UserController :update
PUT /users/:user_id/faces/:id UserController :update
user_user_path DELETE /users/:user_id/faces/:id UserController :delete
user_path GET /users_fr UserController :index
user_path GET /users_fr/:id/edit UserController :edit
user_path GET /users_fr/new UserController :new
user_path GET /users_fr/:id UserController :show
user_path POST /users_fr UserController :create
user_path PATCH /users_fr/:id UserController :update
PUT /users_fr/:id UserController :update
user_path DELETE /users_fr/:id UserController :delete
user_user_path GET /users_fr/:user_id/faces_fr UserController :index
user_user_path GET /users_fr/:user_id/faces_fr/:id/edit UserController :edit
user_user_path GET /users_fr/:user_id/faces_fr/new UserController :new
user_user_path GET /users_fr/:user_id/faces_fr/:id UserController :show
user_user_path POST /users_fr/:user_id/faces_fr UserController :create
user_user_path PATCH /users_fr/:user_id/faces_fr/:id UserController :update
PUT /users_fr/:user_id/faces_fr/:id UserController :update
user_user_path DELETE /users_fr/:user_id/faces_fr/:id UserController :delete
Path helpers
Localised path helpers are generated in a module MyApp.Router.LocalizedHelpers
. The helpers have exactly the same API as the standard Phoenix MyApp.Router.Helpers
module that is also generated. The only difference is that if a route is localised, the path helper is also localised. For example:
iex> Gettext.put_locale MyAppWeb.Gettext, "en"
iex> MyApp.Router.LocalizedHelpers.page_path(%Plug.Conn{}, :show, 1)
"/pages/1"
iex> Gettext.put_locale MyAppWeb.Gettext, "fr"
iex> MyApp.Router.LocalizedHelpers.page_path(%Plug.Conn{}, :show, 1)
"/pages_fr/1"
This is quite a simple library that builds upon existing Phoenix macros. There are a couple of capabilities to be completed before a 1.0
release:
- Generate a list of locales and paths suitable to be used in generating a series of
link rel="alternate" href="http://example.com/localized/path" hreflang="locale" />
. The function will generate a list of locales and URLs, not thelink
tag itself. - Consider %-encoding. Given the specific focus on localisation and recognising that the URL specification allows US-ASCII only characters in the URL, there is a higher likelihood of non-ASCII translations of path segments leading to the generation of invalid URLs.