I18n段路由器Phoenix

时间:2017-05-17 08:48:23

标签: internationalization elixir phoenix-framework

我有一个Elixir / Phoenix应用程序,根据域(也称为租户)的不同反应。

租户具有特定的区域设置,例如“fr_FR”,“en_US”等。

我想根据当前区域设置翻译路由器的URI:

# EN
get "/classifieds/new", ClassifiedController, :new

# FR
get "/annonces/ajout", ClassifiedController, :new

到目前为止,我认为可以做类似的事情(伪代码):

if locale() == :fr do

    scope "/", Awesome.App, as: :app do
        pipe_through :browser # Use the default browser stack
        get "/annonces/ajout", ClassifiedController, :new
    end

else

    scope "/", Awesome.App, as: :app do
        pipe_through :browser # Use the default browser stack
        get "/classifieds/new", ClassifiedController, :new
    end

end

由于路由器是在服务器启动期间编译的,所以它不起作用,因此您没有当前连接的上下文(语言环境,域,主机等)。

到目前为止,我的解决方案(可行)是创建两个带有两个别名的范围:

scope "/", Awesome.App, as: :fr_app do
  pipe_through :browser # Use the default browser stack
  get "/annonces/ajout", ClassifiedController, :new
end

scope "/", Awesome.App, as: :app do
  pipe_through :browser # Use the default browser stack
  get "/classifieds/new", ClassifiedController, :new
end

和一个帮手相关:

localized_path(conn, path, action)

如果当前区域设置为“ fr”,则路径为(:app_classified_new_path),前缀为 fr :fr_app_classified_new_path “(例如)。如果当前区域设置的路径不存在,我将回退到默认区域设置“en”。)

它运作良好,但我看到了一些痛点:

  1. 每次使用“something_foo_path()”助手必须由新的“localized_pa​​th()”替换

  2. 该应用程序将接受每个本地化细分(fr,en,it,等等)并且它不是我想要的(我想只有fr段才能在租户上工作“fr”

  3. 我应该能够直接在路由器中获取当前的locale / conn信息(feature / bugfix?)并避免出现类似黑客攻击。

1 个答案:

答案 0 :(得分:3)

看一下这篇文章Practical i18n with Phoenix and Elixir。我相信它应该能满足你的需求。

或者,您可以使用一些宏来创建已翻译路径的块。由于您仍需要在内部转换路径,因此下面的代码无法满足您的所有要求。但是,它可能会给你一些想法。

defmodule LocalRoutes.Web.Router do
  use LocalRoutes.Web, :router

  @locales ~w(en fr)
  import LocalRoutes.Web.Gettext
  use LocalRoutes.LocalizedRouter

  def locale(conn, locale) do
    Plug.Conn.assign conn, :locale, locale
  end

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", LocalRoutes.Web do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end
  for locale <- @locales do
    Gettext.put_locale(LocalRoutes.Web.Gettext, locale)

    pipeline String.to_atom(locale) do
      plug :accepts, ["html"]
      plug :fetch_session
      plug :fetch_flash
      plug :protect_from_forgery
      plug :put_secure_browser_headers
      plug :locale, locale
    end

    scope "/", LocalRoutes.Web do
      pipe_through String.to_atom(locale) 
      get "/#{~g"classifieds"}", ClassifiedController, :index
      get "/#{~g"classifieds"}/#{~g"new"}", ClassifiedController, :new
      get "/#{~g"classifieds"}/:id", ClassifiedController, :show
      get "/#{~g"classifieds"}/:id/#{~g"edit"}", ClassifiedController, :edit
      post "/#{~g"classifieds"}", ClassifiedController, :create
      patch "/#{~g"classifieds"}/:id", ClassifiedController, :update
      put "/#{~g"classifieds"}/:id", ClassifiedController, :update
      delete "/#{~g"classifieds"}/:id", ClassifiedController, :delete
    end
  end
end

defmodule LocalRoutes.LocalizedRouter do

  defmacro __using__(opts) do
    quote do
      import unquote(__MODULE__)
    end
  end

  defmacro sigil_g(string, _) do
    quote do
      dgettext "routes", unquote(string) 
    end
  end
end