Localize.Plug.PutLocale (Localize Web v1.3.0)

Copy Markdown View Source

Plug that discovers and sets the locale for the current process.

The locale can be derived from the accept-language header, a query parameter, a URL parameter, a body parameter, a cookie, the route, the session, or the hostname TLD. Sources are checked in the order specified by the :from option, and the first successful match wins.

When a locale is found, Localize.put_locale/1 is always called to set the process locale. If Gettext backends are configured, the locale is also set on each backend.

If a locale is found then conn.private[:localize_locale] is also set. It can be retrieved with Localize.Plug.PutLocale.get_locale/1.

The response gets a vary header for each request header the plug read to find the locale: accept-language for :accept_language, and cookie for :session and :cookie. A source read before the one that decided counts too, because a value there would have changed the locale. Existing vary values are kept. This lets a shared cache store one response per language. A {Module, function} source that reads a request header must add its own vary value.

Options

  • :from is a list specifying where in the request to look for the locale. The default is [:route, :path, :query, :session, :accept_language]: a locale in the URL is an explicit choice, so it wins over the session, which in turn wins over the browser's accept-language header. The valid options are:

    • :accept_language will parse the accept-language header and find the best matched configured locale.

    • :path will look for a locale by examining conn.path_params.

    • :query will look for a locale by examining conn.query_params.

    • :body will look for a locale by examining conn.body_params.

    • :cookie will look for a locale in the request cookie(s). Cookies must be fetched before this plug runs. In Phoenix browser pipelines, fetch_session/1 fetches cookies as part of loading the session.

    • :session will look for a locale in the session. fetch_session/1 must run before this plug when :session is used.

    • :route will look for a locale in the route that was matched under the key private.:localize_locale.

    • :host will attempt to resolve a locale from the hostname top-level domain.

    • {Module, function, args} in which case the indicated function will be called. If it returns {:ok, locale} then the locale is set. locale must be a Localize.LanguageTag.t/0.

    • {Module, function} in which case the function is called with conn and options as its two arguments.

  • :default is the default locale to set if no locale is found by other configured methods. It can be a string like "en" or a Localize.LanguageTag struct. It may also be :none to indicate that no locale is to be set by default. Lastly, it may also be a {Module, function, args} or {Module, function} tuple. The default is Localize.default_locale/0 (resolved at runtime, not compile time).

  • :gettext is a Gettext backend module or a list of Gettext backend modules on which the locale will be set. The default is [] (no Gettext backends).

  • :param is the name of the parameter to look for in the query, path, body, or cookie. The default is "locale".

Examples

plug Localize.Plug.PutLocale,
  from: [:query, :path, :body, :cookie, :accept_language],
  param: "locale",
  gettext: MyApp.Gettext

plug Localize.Plug.PutLocale,
  from: [:route, :session, :accept_language],
  gettext: [MyApp.Gettext, MyOtherApp.Gettext]

Summary

Functions

Returns the locale set by Localize.Plug.PutLocale.

Attempts to resolve a locale from a hostname's top-level domain.

Returns the name of the session key used to store the locale.

Functions

get_locale(conn)

Returns the locale set by Localize.Plug.PutLocale.

Arguments

Returns

locale_from_host(host, options \\ [])

Attempts to resolve a locale from a hostname's top-level domain.

Extracts the TLD, validates it as a territory code, and returns the best matching locale for that territory.

Note what this can and cannot tell you. A TLD identifies a territory, and the language is then inferred from it, so the result is only as good as that inference: Belgium has three official languages, Switzerland four, Canada two. Prefer :host below the sources that carry an actual language — the path, a cookie, the session, accept-language — rather than above them.

Generic top-level domains resolve to nothing, as do country-code domains that are predominantly used generically. See the :generic_tlds option.

Where a domain and a territory code disagree — .uk is the domain while GB is the code — resolution relies on Localize.validate_territory/1 applying CLDR's territory aliases.

Arguments

  • host is a hostname string (e.g., "example.co.uk").

  • options is a keyword list of options.

Options

  • :generic_tlds is a list of lowercase country-code TLDs to treat as generic and resolve to nil. The default is ["ai", "cc", "co", "fm", "gg", "io", "ly", "me", "nu", "sh", "st", "to", "tv", "ws"]. Pass a list without a given entry to have that domain resolve to its territory — appropriate for a site whose .co really is Colombian.

Returns

  • {:ok, Localize.LanguageTag.t()},

  • {:error, reason}, or

  • nil when the host has a generic top-level domain, one that is not a territory, or host is not a string.

Examples

iex> {:ok, locale} = Localize.Plug.PutLocale.locale_from_host("example.de")
iex> locale.territory
:DE

# Generic, so no territory is inferred
iex> Localize.Plug.PutLocale.locale_from_host("example.com")
nil

# A country-code domain used generically
iex> Localize.Plug.PutLocale.locale_from_host("example.co")
nil

# ...unless the caller says otherwise
iex> {:ok, locale} = Localize.Plug.PutLocale.locale_from_host("example.co", generic_tlds: [])
iex> locale.territory
:CO

session_key()

Returns the name of the session key used to store the locale.

Examples

iex> Localize.Plug.PutLocale.session_key()
"localize_locale"