From 26fa5703e84039c1e91a5c72d135d827d73e01bf Mon Sep 17 00:00:00 2001 From: Kip Cole Date: Fri, 22 Jul 2022 08:38:33 +0800 Subject: [PATCH] Remove cruft and update readme --- README.md | 42 +++++++++++++-------- lib/cldr/route.ex | 93 +++++------------------------------------------ 2 files changed, 35 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index b1cca5a..7fb7e48 100644 --- a/README.md +++ b/README.md @@ -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: @@ -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 @@ -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: @@ -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 @@ -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 ``` diff --git a/lib/cldr/route.ex b/lib/cldr/route.ex index d25a3e3..8ce085c 100644 --- a/lib/cldr/route.ex +++ b/lib/cldr/route.ex @@ -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. @@ -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 @@ -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