View Source PlugLocale.WebBrowser (plug_locale v0.1.1)

Puts locale into assigns storage for Web browser environment.

The most common way of specifying the desired locale is via the URL. In general, there're three methods to do that:

  1. via domain name - https://<locale>.example.com, such as:
    • https://en.example.com/welcome
    • https://zh.example.com/welcome
  2. via path - https://example.com/<locale>, such as:
    • https://example.com/en/welcome
    • https://example.com/zh/welcome
  3. via querystring - https://example.com?locale=<locale>, such as:
    • https://example.com/welcome?locale=en
    • https://example.com/welcome?locale=zh

Personally, I think method 2 is better,compared to the other two methods:

  • method 1 is tedious for deployment.
  • URLs generated by method 3 look very ugly and unprofessional.

Because of that, this plug will stick on method 2.

Usage

First, we need to integrate this plug with other libraries, or this plug is useless. All you need is to construct a plug pipeline through Plug.Builder. For example:

defmodule DemoWeb.PlugWebBrowserLocalization do
  use Plug.Builder

  plug PlugLocale.WebBrowser,
    default_locale: "en",
    locales: ["en", "zh"],
    route_identifier: :locale,
    assign_key: :locale

  plug :set_locale

  def set_locale(conn, _opts) do
    if locale = conn.assigns[:locale] do
      # integrate with gettext
      Gettext.put_locale(locale)
    end

    conn
  end
end

Then, use it in router (following one is a Phoenix router, but Plug.Router is supported, too):

defmodule DemoWeb.Router do
  use DemoWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]

    # ...

    plug DemoWeb.PlugWebBrowserLocalization

    # ...
  end

  scope "/", DemoWeb do
    pipe_through :browser

    get "/", PageController, :index
    # ...
  end

  # Why using :locale?
  # Because it is specified by `:route_identifier` option.
  scope "/:locale", DemoWeb do
    pipe_through :browser

    get "/", PageController, :index
    # ...
  end
end

Options

  • :default_locale - the default locale.
  • :locales - all the supported locales. Default to [].
  • :sanitize_locale - a function for sanitizing extracted or detected locales. Default to &PlugLocale.Sanitizer.sanitize/1 which does nothing. See PlugLocale.Sanitizer for more details.
  • :route_identifier - the part for identifying locale in route. Default to :locale.
  • :assign_key - the key for putting value into assigns storage. Default to the value of :route_identifier option.
  • :cookie_key - the key for reading locale from cookie. Default to "preferred_locale".

How it works?

This plug will try to:

  1. extract locale from URL, and check if the locale is supported:
    • If it succeeds, put locale into assigns storage。
    • If it fails, jump to step 2.
  2. detect locale from Web browser environment, then redirect to the path corresponding to detected locale.

Extract locale from URL

For example, the locale extracted from https://example.com/en/welcome is en.

Detect locale from Web browser environment

Local is detected from multiple places:

  • cookie (whose key is specified by :cookie_key option)
  • HTTP request header - referer
  • HTTP request header - accept-language
  • default locale (which is specified by :default_locale option)

Examples

When:

  • :default_locale option is set to "en"
  • :locales option is set to ["en", "zh"]

For users in an English-speaking environment:

  • https://example.com/en will be responded directly.
  • https://example.com/ will be redirected to https://example.com/en.
  • https://example.com/path will be redirected to https://example.com/en/path.
  • https://example.com/unknown will be redirected to https://example.com/en.
  • ...

For users in an Chinese-speaking environment:

  • https://example.com/zh will be responded directly.
  • https://example.com/ will be redirected to https://example.com/zh.
  • https://example.com/path will be redirected to https://example.com/zh/path.
  • https://example.com/unknown will be redirected to https://example.com/zh.
  • ...

Summary

Functions