USAGE.md

# Usage

## Requirements

- Elixir >=1.11
- Phoenix >= 1.6.0
- Phoenix LiveView >= 0.16 (optional)


## Installation

You can install this library by adding it to your list of dependencies in `mix.exs`:

```elixir
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.

## Helpers

`Phoenix Localized Routes` adds localization to the helpers created by Phoenix;
no code changes in controllers and (live)views necessary.

```elixir
# file: lib/example_web/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
```


```elixir
# file: lib/example_web/router.ex

# Add to browser pipeline
+   plug(PhxLocalizedRoutes.Plug)
```


## Configuration

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` - a `Map` or `Struct` of values to assign to the `Plug.Conn`
  and/or `Phoenix.Socket`. When using a `Map` 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`)

> #### Note {: .info}
>
> - 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.


```elixir
# 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
```

> #### Note {: .info}
>
> Your visitors may prefer another locale than the one set for the route they
> landed on. Libraries like
> [Cldr.Plug.SetLocale](https://hexdocs.pm/ex_cldr/Cldr.Plug.SetLocale.html) 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.


## Wrapping routes

Wrap the routes within the scope in an `localized` block, providing your created
`LocalizedRoutes` module as argument.

```elixir
# file: router.ex
    scope "/", ExampleWeb do
+     localize ExampleWeb.LocalizedRoutes do
        [...routes]
+     end
    end
```



## Extract translatable segments into `routes.po` files

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

```elixir
def project do
  [
    compilers: [:gettext] ++ Mix.compilers,
  ]
end
```