README.md

# Multilingual

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

# Rationale

When a site is localized, it is important to know which paths
should be used for the various localizations of a specific view.

Maybe the "about page" is `/about` in English and `/it/chi-siamo` in
Italian.

One common need is a "language selector", where you can jump to the same view
in another language.

Somewhere, for *each* localized view, there needs to be a mapping like this:

* "en" -> "/about"
* "it" -> "/it/chi-siamo"

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](https://hexdocs.pm/phoenix/Phoenix.Router.html)
allows [metadata](https://hexdocs.pm/phoenix/Phoenix.Router.html#match/5-options)
to be added to route declarations.

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

You can do this via a helper:

```ex
import Multilingual.Routes, only: [metadata: 1]

...

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

`metadata/1` returns the [`options`](https://hexdocs.pm/phoenix/Phoenix.Router.html#match/5-options)
for the route, specifically, setting the locale as the metadata for this library.

It's the same if you do this:

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

# How Paths Are Grouped

Consider these routes:

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

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

From the above, we can deduce this:

* "en" -> "/"
* "zh" -> "/zh"

And that's all is needed to carry out all the tasks we need when
handling the views of a localized site.

# Route Organization

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

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

```ex
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:

```ex
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:

```ex
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:

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

# Using Multilingual Routes

With you routes set up, you get the following:

* a [Plug](lib/multilingual/plugs/store_view.ex) to store view information for classic Phoenix views,
* an [on_mount hook](lib/multilingual/live_view/hook.ex) to do the same to LiveViews,
* a [Plug](lib/multilingual/plugs/redirect_incoming.ex) for incoming links,
  which checks the 'accept-langauge' header
  and redirects to the correct view for the user's needs,
* a [rel links builder](lib/multilingual/html.ex) for the document head,
  with the canonical URL and links to localized views,
* [localized_path/3](lib/multilingual/routes.ex) takes any path and
  a locale and returns the equivalent path for that locale,
* a [locales to paths mapping builder](lib/multilingual/routes.ex)
  to aid the creation of language selectors.