Localization using ex_cldr

I am trying to use ex_cldr for localization. I want to use path parameters to change languages and it doesn’t work, but works with query parameters. Requesting http://localhost:4000/en will use fa as locale but http://localhost:4000/?locale=en uses en.

I have added this to the endpoint.ex:

plug Cldr.Plug.SetLocale,
    apps: [:cldr, :gettext],
    from: [:path, :query],
    gettext: MyAppWeb.Gettext,
    cldr: MyApp.Cldr

This is the cldr module:

defmodule MyApp.Cldr do
  use Cldr,
    locales: ["en", "fa"],
    default_locale: "fa",
    gettext: MyAppWeb.Gettext
end

And my routes:

scope "/:locale" do
  pipe_through [:browser, :simple_layout]

  pow_routes()
end

scope "/:locale", MyAppWeb do
  pipe_through :browser

  get "/", PageController, :index
end

scope "/:locale/admin", MyAppWeb do
  pipe_through [:browser, :protected, :admin_layout]
end

scope "/" do
  pipe_through [:browser, :simple_layout]

  pow_routes()
end

scope "/", MyAppWeb do
  pipe_through :browser

  get "/", PageController, :index
end

scope "/admin", MyAppWeb do
  pipe_through [:browser, :protected, :admin_layout]
end

@ashkan, I’m the author - I’ll take a look and see if there’s an issue. Feel free to open an issue at https://github.com/elixir-cldr/cldr/issues

Can you confirm that you are using Phoenix version >= 1.3? path_params was added then and its what the plug uses for locale detection in paths.

I am using phoenix 1.5.

I am not sure If I understand correctly but phoenix is able to detect the parameter, this is what I saw in server logs Parameters: %{"locale" => "en"} when I request http://localhost:4000/en and path_params: %{"locale" => "en"} is in conn. I have from: [:path, :query] in SetLocale plug. All ex_cldr variables in conn are set to use fa. I don’t know how to further investigate that.

Wold you kindly check that you have Cldr.Plug.SetLocale configured after plug :match in your endpoint? plug :match is what populates the path_params and therefore its important Plug.Cldr.SetLocale comes after that.

There’s no explicit plug :match in phoenix.

There is no plug :match in my endpoint

Ahhhhhh. OK, in the case I’m looking for help too :slight_smile:

Is there a way to have a user plug run after plug :match and before plug :dispatch or Phoenix equivalents?

Clearly demonstrating my lack of Phoenix knowledge. But it looks like you would need to put Cldr.Plug.SetLocale in your pipeline, not the endpoint. Possible you can try that? As best I can tell from the docs, the pipeline is not run unless a route is found - and I believe when a route is found that path_params is decoded.

So, for example:

  pipeline :browser do
    plug :fetch_session
    plug :accepts, ["html"]
    plug Cldr.Plug.SetLocale, 
      apps: [:cldr, :gettext],
      from: [:path, :query],
      gettext: MyAppWeb.Gettext,
      cldr: MyApp.Cldr
  end
1 Like

That’s true. Pipelines are run after a route is matched, as the matched route determines which pipelines need to run.

1 Like

Thanks that worked.

P.S.
You were right path_params was empty at that point in endpoint. I used another plug to test that. Previously I have check it near the end of processing pipeline.