Redirect on a default language?

How do I make my default language Hungarian not being present in the URL? Only /en/rolunk but /rolunk when it’s in Hungarian (by default). I guess in router.ex file I have to add some condition in scope “/” part. But I have no idea how. How to do that?

I would like to redirect all /hu/* stuff to /* as well.

But /en/* to stay as /en/*.

Right now my router files looks like this:

defmodule HelloWeb.Router do use HelloWeb, :router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_live_flash plug :put_root_layout, html: {HelloWeb.Layouts, :root} plug :protect_from_forgery plug :put_secure_browser_headers end pipeline :api do plug :accepts, ["json"] end scope "/", HelloWeb do pipe_through :browser get "/", PageController, :home end # Other scopes may use custom stacks. # scope "/api", HelloWeb do # pipe_through :api # end # Enable LiveDashboard and Swoosh mailbox preview in development if Application.compile_env(:hello, :dev_routes) do # If you want to use the LiveDashboard in production, you should put # it behind authentication and allow only admins to access it. # If your application does not have an admins-only section yet, # you can use Plug.BasicAuth to set up some basic authentication # as long as you are also using SSL (which you should anyway). import Phoenix.LiveDashboard.Router scope "/dev" do pipe_through :browser live_dashboard "/dashboard", metrics: HelloWeb.Telemetry forward "/mailbox", Plug.Swoosh.MailboxPreview end end end 

Isn’t that better dealt in a Plug?
This is an example of plugs dealing with locales in the request. Not exactly what you are trying to do, but it can give some ideas for coding your own plug:

For others still searching… A simple possible solution is something like this:

 scope "/en", MyWeb do pipe_through :browser live_session :set_locale_en, on_mount: {MyWeb.SetLocale, :en} do live "/", DocumentLive, :home live "/:parent_slug/:slug", DocumentLive, :document live "/:slug", DocumentLive, :document end end scope "/", MyWeb do pipe_through :browser live_session :set_locale_nl, on_mount: {MyWeb.SetLocale, :nl} do live "/nl/*rest", DocumentLive, :redirect live "/", DocumentLive, :home live "/:parent_slug/:slug", DocumentLive, :document live "/:slug", DocumentLive, :document end end 

Just define a scope for all languages and for the main language redirect to the URL without locale prefix.
MyWeb.SetLocale just assigns the locale as variable to the live view.

This can be simplified even further with macros for example, but you get the idea.

3 Likes

Kudos to your approach of handling the situation!

1 Like

I like zaljir’s approach! I also just finished doing something like this and used Kip’s ex_cldr_plugs | Hex and ex_cldr_routes | Hex.

I wanted to try to get the user’s accept language header first and default to cldr’s default if not found.
Then I wanted to force all users to have a locale in the route… then only respect the route’s locale after that.

Router looks like:

 scope "/", MyAppWeb do pipe_through :browser get "/", PageController, :redirect_to_default_lang localize do get "/#{locale}", PageController, :home live "/#{locale}/videos", VideoLive.Index, :index live "/#{locale}/videos/new", VideoLive.Index, :new live "/#{locale}/videos/:id/edit", VideoLive.Index, :edit live "/#{locale}/videos/:id", VideoLive.Show, :show live "/#{locale}/videos/:id/show/edit", VideoLive.Show, :edit end 

with this in the pipeline:

 plug Cldr.Plug.PutLocale, apps: [:cldr, :gettext], from: [:route, :query, :path, :accept_language, :session], gettext: MyAppWeb.Gettext, cldr: MyApp.Cldr 

So the plug finds the best language for the user based on route/accept language header, etc.
If the user visits the main page, it hits this redirect controller to get the best language and sends them off to the correct route ie. “/fr”. All navigation links after that expect a locale.

defmodule MyAppWeb.PageController do use MyAppWeb, :controller def redirect_to_default_lang(conn, _params) do redirect(conn, to: "/#{MyApp.Cldr.get_locale().cldr_locale_name}") end end 

and this puts the locale in the session:

defmodule MyAppWeb.RestoreLocale do def on_mount(:default, _, %{"cldr_locale" => cldr_locale}, socket) do MyApp.Cldr.put_locale(cldr_locale) Gettext.put_locale( MyAppWeb.Gettext, Atom.to_string(MyApp.Cldr.get_locale().cldr_locale_name) ) {:cont, socket} end def on_mount(:default, _params, _session, socket), do: {:cont, socket} end 
2 Likes