Skip to content

Commit

Permalink
Remove cruft and update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
kipcole9 committed Jul 22, 2022
1 parent 2c54881 commit 26fa570
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 100 deletions.
42 changes: 26 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Similarly, localised path and URL helpers are generated that wrap the standard [

A `Cldr` backend module that configures an associated `gettext` backend is required. In addition, a `Gettext` backend must be configured and added to the `Cldr` configuration.

Path parts (the parts between "/") are translated at compile time using `Gettext`. Therefore localization can only be applied to locales that are defined in a [gettext backend module](https://hexdocs.pm/gettext/Gettext.html#module-using-gettext) that is attached to a `Cldr` backend module.
Path parts (the parts between "/") are translated at compile time using `Gettext`. Therefore localization can only be applied to locales that are defined in a [gettext backend module](https://hexdocs.pm/gettext/Gettext.html#module-using-gettext) that is attached to a `Cldr` backend module.

The following steps should be followed to set up the configuration for localized routes and helpers:

Expand Down Expand Up @@ -100,17 +100,7 @@ end

Manually constructing the localized helper names shown in the example above would be tedious. Therefore a `LocalizedHelpers` module is geenrated at compile-time. Assuming the router module is called `MyApp.Router` then the full name of the localized helper module is `MyApp.Router.LocalizedHelpers`.

The functions on this module are the non-localized versions. For example, assuming the same configuration of routes as the earlier example:

```elixir
iex> MyApp.Router.LocalizedHelpers.
helper/5 page_path/3 page_path/4
page_url/3 page_url/4 path/2
static_integrity/2 static_path/2 static_url/2
url/1 user_path/2 user_path/3
user_path/4 user_url/2 user_url/3
user_url/4
```
The functions on this module are the non-localized versions that should be used by applications (they delegate ultimately to the localized routes based upon the current locale).

The functions on the `LocalizedHelpers` module all respect the current locale, based upon `Cldr.get_locale/1`, and will delegate to the appropriate localized function in the `Helpers` function created automatically at compile time. For example:
```elixir
Expand All @@ -124,6 +114,29 @@ iex> MyApp.Router.LocalizedHelpers.page_path %Plug.Conn{}, :show, 1
*Note* The localized helpers translate the path based upon the `:gettext_locale_name` for the currently set `Cldr` locale. It is the developers responsibility to ensure that the locale is set appropriately before calling any localized path helpers.
### Introspecting localized routes
For convenience in introspecting routes, a module called `MyApp.Router.LocalizedRoutes` is generated that can be used with the `mix phx.routes` mix task. For example:
```bash
% cldr_routes % mix phx.routes MyApp.Router.LocalizedRoutes
page_path GET /pages_de/:page PageController :show
page_path GET /pages/:page PageController :show
page_path GET /pages_fr/:page PageController :show
user_path GET /users_de UserController :index
user_path GET /users_de/:id/edit UserController :edit
user_path GET /users_de/new UserController :new
...
```
In addition, each localized path stores the `Cldr` locale in the `:private` field for the route under the `:cldr_locale` key. This allows the developer to recognise which locale was used to generate the localized route.
This information is also used by functions in the [ex_cldr_plugs](https://hex.pm/packages/ex_cldr_plugs) library to:
* Identify the users locale from the route in `Cldr.Plug.PutLocale`
* Store the identified locale in the session in `Cldr.Plug.PutSession`
* Propogate the locale from the session into a LiveView process during the `on_mount/3` callback with `Cldr.Session.put_locale/2`
### Configuring Localized Helpers as default
Since `LocalizedHelpers` have the same semantics and API as the standard `Helpers` module it is possible to update the generated Phoenix configuration to use the `LocalizedHelpers` module by default. Assuming the presence of `myapp_web.ex` defining the module `MyAppWeb` then changing the `view_helpers` function from:
Expand Down Expand Up @@ -174,9 +187,6 @@ Using the example Cldr backend that has "en" and "fr" Gettext locales then the d
The `mix` tasks `gettext.extract` and `gettext.merge` can be used to support the extraction of routing segments and to create new translation locales.
## Assigns
For each localized path, the `Cldr` locale is added to the `:assigns` for the route under the `:cldr_locale` key. This allows the developer to recognise which locale was used to generate the localized route.
## Installation
Expand All @@ -185,7 +195,7 @@ The package can be installed by adding `ex_cldr_routes` to your list of dependen
```elixir
def deps do
[
{:ex_cldr_routes, "~> 0.3.0"}
{:ex_cldr_routes, "~> 0.5.0"}
]
end
```
Expand Down
93 changes: 9 additions & 84 deletions lib/cldr/route.ex
Original file line number Diff line number Diff line change
Expand Up @@ -739,20 +739,17 @@ defmodule Cldr.Route do
[options, last]
end

@doc false
# No assigns, so fabricate one
def put_value(nil, key, value) do
defp put_value(nil, key, value) do
quote do
%{unquote(key) => unquote(Macro.escape(value))}
end
end

# Existing assigns, add to them
def put_value({:%{}, meta, key_values}, key, value) do
defp put_value({:%{}, meta, key_values}, key, value) do
{:%{}, meta, [{key, Macro.escape(value)} | key_values]}
end

# Testing uniqeiness of a routes excluding options
# Testing uniqeness of a routes excluding options
# We use this to eliminate duplicate routes which can occur if
# there is no translation for a term and therefore the original
# term is returned.
Expand All @@ -776,27 +773,26 @@ defmodule Cldr.Route do
def routes(routes) do
routes
|> Enum.map(&strip_locale_from_helper/1)
|> Enum.map(&reconstruct_original_path/1)
|> Enum.map(&add_locales_to_metadata/1)
|> reduce_routes()
|> group_locales_by_path_helper_verb()
|> Enum.map(&Map.take(&1, @route_keys))
end

defp reduce_routes([]) do
defp group_locales_by_path_helper_verb([]) do
[]
end

# When the routes match except for locale
defp reduce_routes([
defp group_locales_by_path_helper_verb([
%{path: path, helper: helper, verb: verb} = first,
%{path: path, helper: helper, verb: verb} = second | rest]) do
locales = Enum.uniq([locale_from_args(second) | first.metadata.locales]) |> Enum.sort()
metadata = Map.put(first.metadata, :locales, locales)
reduce_routes([%{first | metadata: metadata} | rest])
group_locales_by_path_helper_verb([%{first | metadata: metadata} | rest])
end

defp reduce_routes([first | rest]) do
[first | reduce_routes(rest)]
defp group_locales_by_path_helper_verb([first | rest]) do
[first | group_locales_by_path_helper_verb(rest)]
end

# We add the locales for a given route into the metadata field
Expand Down Expand Up @@ -845,77 +841,6 @@ defmodule Cldr.Route do
%{route | helper: helper}
end

defp reconstruct_original_path(%{assigns: %{cldr_locale: _locale}} = route) do
do_reconstruct_original_path(route)
end

defp reconstruct_original_path(%{private: %{cldr_locale: _locale}} = route) do
do_reconstruct_original_path(route)
end

defp reconstruct_original_path(%{private: %{}} = other) do
other
end

defp do_reconstruct_original_path(%{path: path, private: %{original_path: original}} = route) do
if same_segment_length(path, original) do
private = Map.delete(route.private, :original_path)
%{route | private: private, path: original}
else
path = merge_paths(path, original)
private = Map.delete(route.private, :original_path)
%{route | private: private, path: path}
end
end

defp same_segment_length(a, b) do
length(String.split(a, @path_separator)) == length(String.split(b, @path_separator))
end

# Need to take care of routes which have /new, /edit
# When it ends in /new then we patch before the new
# When it ends in /edit then we pathc before the [:id, edit]
# If the segments of the original match the leading segments of
# the path then we do nothing.

# TODO Clean this up

defp merge_paths(path, original) do
path_segs = String.split(path, @path_separator)
orig_segs = String.split(original, @path_separator)

cond do
Enum.take(path_segs, length(orig_segs)) == orig_segs ->
path

Enum.take(path_segs, -1) == ["new"] ->
new_segs = Enum.take(path_segs, -1)
start_segs = Enum.take(path_segs, length(path_segs) - length(orig_segs) - 1)

start_segs ++ tl(orig_segs) ++ new_segs
|> Enum.join(@path_separator)

String.starts_with?(hd(Enum.take(path_segs, -1)), @interpolate) ->
new_segs = Enum.take(path_segs, -1)
start_segs = Enum.take(path_segs, length(path_segs) - length(orig_segs) - 1)

start_segs ++ tl(orig_segs) ++ new_segs
|> Enum.join(@path_separator)

Enum.take(path_segs, -1) == ["edit"] ->
edit_segs = Enum.take(path_segs, -2)
start_segs = Enum.take(path_segs, length(path_segs) - length(orig_segs) - 2)

start_segs ++ tl(orig_segs) ++ edit_segs
|> Enum.join(@path_separator)

true ->
start_segs = Enum.take(path_segs, length(path_segs) - length(orig_segs))
start_segs ++ tl(orig_segs)
|> Enum.join(@path_separator)
end
end

defp locale_from_args(%{assigns: %{cldr_locale: locale}}) do
locale
end
Expand Down

0 comments on commit 26fa570

Please sign in to comment.