- Elixir >=1.11
- Phoenix >= 1.6.0
- Phoenix LiveView >= 0.16 (optional)
You can install this library by adding it to your list of dependencies in mix.exs
:
def deps do
[
{:phoenix_localized_routes, "~> 0.1.0"}
]
end
We pressed on making the installation as non-intrusive as possible. The following modules / files need changes.
Phoenix Localized Routes
adds localization to the helpers created by Phoenix;
no code changes in controllers and (live)views necessary.
# file: lib/example_web.ex
# in controller
- alias ExampleWeb.Router.Helpers, as: Routes
+ unquote(loc_helpers())
# in live_view
+ on_mount(ExampleWeb.LocalizedRoutes.LiveHelpers)
# in router
+ import PhxLocalizedRoutes.Router
+ use PhxLocalizedRoutes.Router
# in view_helpers
- alias ExampleWeb.Router.Helpers, as: Routes
+ unquote(loc_helpers())
# insert new private function
+ defp loc_helpers do
+ quote do
+ import PhxLocalizedRoutes.Helpers
+ alias ExampleWeb.Router.Helpers, as: OriginalRoutes
+ alias ExampleWeb.Router.Helpers.Localized, as: Routes
+ alias ExampleWeb.LocalizedRoutes, as: Loc
+ end
+ end
# file: lib/example_web/router.ex
# Add to browser pipeline
+ plug(PhxLocalizedRoutes.Plug)
Create the module [MyAppWeb].LocalizedRoutes
in the directory of your web
application. The example shows a nested configuration using the default
[MyAppWeb].Gettext
module for multilingual URLs.
It is possible to set:
:scopes
- scopes as map of maps, keys are used as URL segments (slugs).:gettext_module
-Gettext
module to extract URL segments and translate them.
For each local scope you can set.
:assign
- aMap
orStruct
of values to assign to thePlug.Conn
and/orPhoenix.Socket
. When using aMap
nested scopes inherit assigns from their parent.:scopes
- nested scopes
Assigns are namespaced with :loc
. Templates can access them with
@loc.{key_name}
(e.g. @loc.contact
)
- using a
Struct
for:assign
's improves the developer experience.- when using a
Struct
for assigns it should not be nested in the configuration module; but it can be in the same file as shown in the example.- when a
Gettext
module is provided, the assigns must include a value for:locale
.During compilation the configuration is validated.
# file /lib/example_web/localized_routes.ex
# This example uses a `Struct` for assign, so there is no assign inheritance;
# only struct defaults. When using maps, nested scopes will inherit key/values
# from their parent.
defmodule ExampleWeb.LocalizedRoutes.Assigns do
@moduledoc false
defstruct [:contact, locale: "en"]
end
defmodule ExampleWeb.LocalizedRoutes do
alias Exampleeb.LocalizedRoutes.Assigns
use PhxLocalizedRoutes,
scopes: %{
"/" => %{
assign: %Assigns{contact: "root@example.com"},
scopes: %{
"/europe" => %{
assign: %Assigns{contact: "europe@example.com"},
scopes: %{
"/nl" => %{assigns: %Assigns{locale: "nl", contact: "verkoop@example.nl"}},
"/be" => %{assigns: %Assigns{locale: "nl", contact: "handel@example.be"}}
}
},
"/gb" => %{assign: %Assigns{contact: "sales@example.com"}
}
},
gettext_module: ExampleWeb.Gettext
end
Your visitors may prefer another locale than the one set for the route they landed on. Libraries like Cldr.Plug.SetLocale can detect their preferences. You can combine the value set by the route and the value set by a third party library to detect mismatches and guide your visitors accordingly.
Wrap the routes within the scope in an localized
block, providing your created
LocalizedRoutes
module as argument.
# file: router.ex
scope "/", ExampleWeb do
+ localize ExampleWeb.LocalizedRoutes do
[...routes]
+ end
end
- Run
mix gettext.merge priv/gettext --locale {locale}
to create a locales' folder - Run
mix gettext.extract --merge
after you updated routes.
Now, we have created new routes PO file in our structure:
web_app/priv/gettext
└─ nl
| └─ LC_MESSAGES
| | └─ default.po
| | └─ errors.po
| | └─ routes.po <---- new!
└─ en
| └─ LC_MESSAGES
| | └─ default.po
| | └─ errors.po
| | └─ routes.po <---- new!
└─ default.pot
└─ errors.pot
└─ routes.pot <---- new!
You can translate the route segments in the .po
-file and recompile the Router
module to generate the new multilingual routes.
Finally, Phoenix Localized Routes is able to recompile routes whenever PO files change. To enable this feature, the :gettext compiler needs to be added to the list of Mix compilers.
In mix.exs:
def project do
[
compilers: [:gettext] ++ Mix.compilers,
]
end