Fix and improve language handling
- Refactor plugs to detect and set language - Translate ecto validation errors - Use Gettext directly, not Mobilizon.Web.Gettext - Set the language in the <html> attribute according to the one loaded on front-end Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
7c943dc09a
commit
a670a7d7a7
|
@ -7,4 +7,5 @@
|
||||||
155A1FB53DE39EC8EFCFD7FB94EA823D
|
155A1FB53DE39EC8EFCFD7FB94EA823D
|
||||||
73B351E4CB3AF715AD450A085F5E6304
|
73B351E4CB3AF715AD450A085F5E6304
|
||||||
BBACD7F0BACD4A6D3010C26604671692
|
BBACD7F0BACD4A6D3010C26604671692
|
||||||
6D4D4A4821B93BCFAC9CDBB367B34C4B
|
6D4D4A4821B93BCFAC9CDBB367B34C4B
|
||||||
|
5674F0D127852889ED0132DC2F442AAB
|
|
@ -39,9 +39,19 @@ const loadedLanguages = [DEFAULT_LOCALE];
|
||||||
|
|
||||||
function setI18nLanguage(lang: string): string {
|
function setI18nLanguage(lang: string): string {
|
||||||
i18n.locale = lang;
|
i18n.locale = lang;
|
||||||
|
setLanguageInDOM(lang);
|
||||||
return lang;
|
return lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setLanguageInDOM(lang: string): void {
|
||||||
|
const fixedLang = lang.replaceAll("_", "-");
|
||||||
|
const html = document.documentElement;
|
||||||
|
const documentLang = html.getAttribute("lang");
|
||||||
|
if (documentLang !== fixedLang) {
|
||||||
|
html.setAttribute("lang", fixedLang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fileForLanguage(matches: Record<string, string>, lang: string) {
|
function fileForLanguage(matches: Record<string, string>, lang: string) {
|
||||||
if (Object.prototype.hasOwnProperty.call(matches, lang)) {
|
if (Object.prototype.hasOwnProperty.call(matches, lang)) {
|
||||||
return matches[lang];
|
return matches[lang];
|
||||||
|
|
|
@ -5,7 +5,8 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
import Mobilizon.Web.Gettext
|
alias Mobilizon.Web.Gettext, as: GettextBackend
|
||||||
|
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
||||||
|
|
||||||
defstruct [:code, :message, :status_code, :field]
|
defstruct [:code, :message, :status_code, :field]
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
|
|
||||||
defp handle(%Ecto.Changeset{} = changeset) do
|
defp handle(%Ecto.Changeset{} = changeset) do
|
||||||
changeset
|
changeset
|
||||||
|> Ecto.Changeset.traverse_errors(fn {err, _opts} -> err end)
|
|> Ecto.Changeset.traverse_errors(&translate_error/1)
|
||||||
|> Enum.map(fn {k, v} ->
|
|> Enum.map(fn {k, v} ->
|
||||||
%Error{
|
%Error{
|
||||||
code: :validation,
|
code: :validation,
|
||||||
|
@ -96,4 +97,27 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
Logger.warn("Unhandled error code: #{inspect(code)}")
|
Logger.warn("Unhandled error code: #{inspect(code)}")
|
||||||
{422, to_string(code)}
|
{422, to_string(code)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Translates an error message using gettext.
|
||||||
|
defp translate_error({msg, opts}) do
|
||||||
|
# Because error messages were defined within Ecto, we must
|
||||||
|
# call the Gettext module passing our Gettext backend. We
|
||||||
|
# also use the "errors" domain as translations are placed
|
||||||
|
# in the errors.po file.
|
||||||
|
# Ecto will pass the :count keyword if the error message is
|
||||||
|
# meant to be pluralized.
|
||||||
|
# On your own code and templates, depending on whether you
|
||||||
|
# need the message to be pluralized or not, this could be
|
||||||
|
# written simply as:
|
||||||
|
#
|
||||||
|
# dngettext "errors", "1 file", "%{count} files", count
|
||||||
|
# dgettext "errors", "is invalid"
|
||||||
|
#
|
||||||
|
|
||||||
|
if count = opts[:count] do
|
||||||
|
Gettext.dngettext(GettextBackend, "errors", msg, msg, count, opts)
|
||||||
|
else
|
||||||
|
Gettext.dgettext(GettextBackend, "errors", msg, opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,7 +9,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Actor do
|
||||||
alias Mobilizon.Federation.ActivityPub
|
alias Mobilizon.Federation.ActivityPub
|
||||||
alias Mobilizon.Service.Workers.Background
|
alias Mobilizon.Service.Workers.Background
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
import Mobilizon.Web.Gettext
|
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
|
@ -348,8 +348,7 @@ defmodule Mobilizon.Config do
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_terms(locale) do
|
def generate_terms(locale) do
|
||||||
import Mobilizon.Web.Gettext
|
Gettext.put_locale(locale)
|
||||||
put_locale(locale)
|
|
||||||
|
|
||||||
Phoenix.View.render_to_string(
|
Phoenix.View.render_to_string(
|
||||||
Mobilizon.Web.APIView,
|
Mobilizon.Web.APIView,
|
||||||
|
@ -363,8 +362,7 @@ defmodule Mobilizon.Config do
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_privacy(locale) do
|
def generate_privacy(locale) do
|
||||||
import Mobilizon.Web.Gettext
|
Gettext.put_locale(locale)
|
||||||
put_locale(locale)
|
|
||||||
|
|
||||||
Phoenix.View.render_to_string(
|
Phoenix.View.render_to_string(
|
||||||
Mobilizon.Web.APIView,
|
Mobilizon.Web.APIView,
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Comment do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Discussion do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Event do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Group do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Member do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Post do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Service.Activity.Renderer.Resource do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Service.Activity.Renderer
|
alias Mobilizon.Service.Activity.Renderer
|
||||||
alias Mobilizon.Web.{Endpoint, Gettext}
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
import Mobilizon.Web.Gettext, only: [dgettext: 3]
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ defmodule Mobilizon.Service.Metadata.Utils do
|
||||||
alias Mobilizon.Service.{Address, DateTime}
|
alias Mobilizon.Service.{Address, DateTime}
|
||||||
alias Mobilizon.Service.Formatter.HTML, as: HTMLFormatter
|
alias Mobilizon.Service.Formatter.HTML, as: HTMLFormatter
|
||||||
alias Phoenix.HTML
|
alias Phoenix.HTML
|
||||||
import Mobilizon.Web.Gettext
|
import Mobilizon.Web.Gettext, only: [gettext: 1]
|
||||||
|
|
||||||
@slice_limit 200
|
@slice_limit 200
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,19 @@ defmodule Mobilizon.Web.Auth.Context do
|
||||||
def set_user_information_in_context(conn) do
|
def set_user_information_in_context(conn) do
|
||||||
context = %{ip: conn.remote_ip |> :inet.ntoa() |> to_string()}
|
context = %{ip: conn.remote_ip |> :inet.ntoa() |> to_string()}
|
||||||
|
|
||||||
context =
|
{conn, context} =
|
||||||
case Guardian.Plug.current_resource(conn) do
|
case Guardian.Plug.current_resource(conn) do
|
||||||
%User{id: user_id, email: user_email} = user ->
|
%User{id: user_id, email: user_email} = user ->
|
||||||
if SentryAdapter.enabled?() do
|
if SentryAdapter.enabled?() do
|
||||||
Sentry.Context.set_user_context(%{id: user_id, name: user_email})
|
Sentry.Context.set_user_context(%{id: user_id, name: user_email})
|
||||||
end
|
end
|
||||||
|
|
||||||
Map.put(context, :current_user, user)
|
context = Map.put(context, :current_user, user)
|
||||||
|
conn = assign(conn, :user_locale, user.locale)
|
||||||
|
{conn, context}
|
||||||
|
|
||||||
nil ->
|
nil ->
|
||||||
context
|
{conn, context}
|
||||||
end
|
end
|
||||||
|
|
||||||
context =
|
context =
|
||||||
|
|
|
@ -10,7 +10,7 @@ defmodule Mobilizon.Web.Email.Activity do
|
||||||
alias Mobilizon.Activities.Activity
|
alias Mobilizon.Activities.Activity
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Config
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
@spec direct_activity(String.t(), list(), String.t()) ::
|
@spec direct_activity(String.t(), list(), String.t()) ::
|
||||||
Bamboo.Email.t()
|
Bamboo.Email.t()
|
||||||
|
|
|
@ -13,7 +13,7 @@ defmodule Mobilizon.Web.Email.Admin do
|
||||||
alias Mobilizon.Reports.Report
|
alias Mobilizon.Reports.Report
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
|
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
@spec report(User.t(), Report.t(), String.t()) :: Bamboo.Email.t()
|
@spec report(User.t(), Report.t(), String.t()) :: Bamboo.Email.t()
|
||||||
def report(%User{email: email} = user, %Report{} = report, default_locale \\ "en") do
|
def report(%User{email: email} = user, %Report{} = report, default_locale \\ "en") do
|
||||||
|
|
|
@ -16,7 +16,6 @@ defmodule Mobilizon.Web.Email.Event do
|
||||||
alias Mobilizon.Users.{Setting, User}
|
alias Mobilizon.Users.{Setting, User}
|
||||||
|
|
||||||
alias Mobilizon.Web.Email
|
alias Mobilizon.Web.Email
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
|
||||||
|
|
||||||
@important_changes [:title, :begins_on, :ends_on, :status, :physical_address]
|
@important_changes [:title, :begins_on, :ends_on, :status, :physical_address]
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ defmodule Mobilizon.Web.Email.Event do
|
||||||
timezone \\ "Etc/UTC",
|
timezone \\ "Etc/UTC",
|
||||||
locale \\ "en"
|
locale \\ "en"
|
||||||
) do
|
) do
|
||||||
GettextBackend.put_locale(locale)
|
Gettext.put_locale(locale)
|
||||||
|
|
||||||
subject =
|
subject =
|
||||||
gettext(
|
gettext(
|
||||||
|
|
|
@ -11,7 +11,7 @@ defmodule Mobilizon.Web.Email.Follow do
|
||||||
alias Mobilizon.Actors.{Actor, Follower}
|
alias Mobilizon.Actors.{Actor, Follower}
|
||||||
alias Mobilizon.Federation.ActivityPub.Relay
|
alias Mobilizon.Federation.ActivityPub.Relay
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Send follow notification to admins if the followed actor
|
Send follow notification to admins if the followed actor
|
||||||
|
|
|
@ -10,7 +10,7 @@ defmodule Mobilizon.Web.Email.Group do
|
||||||
alias Mobilizon.{Actors, Config, Users}
|
alias Mobilizon.{Actors, Config, Users}
|
||||||
alias Mobilizon.Actors.{Actor, Member}
|
alias Mobilizon.Actors.{Actor, Member}
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Send emails to local user
|
Send emails to local user
|
||||||
|
|
|
@ -9,7 +9,7 @@ defmodule Mobilizon.Web.Email.Notification do
|
||||||
|
|
||||||
alias Mobilizon.Events.{Event, Participant}
|
alias Mobilizon.Events.{Event, Participant}
|
||||||
alias Mobilizon.Users.{Setting, User}
|
alias Mobilizon.Users.{Setting, User}
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
@spec before_event_notification(String.t(), Participant.t(), String.t()) ::
|
@spec before_event_notification(String.t(), Participant.t(), String.t()) ::
|
||||||
Bamboo.Email.t()
|
Bamboo.Email.t()
|
||||||
|
|
|
@ -12,7 +12,7 @@ defmodule Mobilizon.Web.Email.Participation do
|
||||||
alias Mobilizon.Events.{Event, Participant}
|
alias Mobilizon.Events.{Event, Participant}
|
||||||
alias Mobilizon.Users
|
alias Mobilizon.Users
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Send participation emails to local user
|
Send participation emails to local user
|
||||||
|
|
|
@ -7,13 +7,13 @@ defmodule Mobilizon.Web.Email.User do
|
||||||
|
|
||||||
import Bamboo.Phoenix
|
import Bamboo.Phoenix
|
||||||
|
|
||||||
import Mobilizon.Web.Gettext
|
import Mobilizon.Web.Gettext, only: [gettext: 2]
|
||||||
|
|
||||||
alias Mobilizon.{Config, Crypto, Users}
|
alias Mobilizon.{Config, Crypto, Users}
|
||||||
alias Mobilizon.Storage.Repo
|
alias Mobilizon.Storage.Repo
|
||||||
alias Mobilizon.Users.User
|
alias Mobilizon.Users.User
|
||||||
|
|
||||||
alias Mobilizon.Web.{Email, Gettext}
|
alias Mobilizon.Web.Email
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ defmodule Mobilizon.Web.Endpoint do
|
||||||
use Phoenix.Endpoint, otp_app: :mobilizon
|
use Phoenix.Endpoint, otp_app: :mobilizon
|
||||||
use Absinthe.Phoenix.Endpoint
|
use Absinthe.Phoenix.Endpoint
|
||||||
|
|
||||||
plug(Mobilizon.Web.Plugs.SetLocalePlug)
|
plug(Mobilizon.Web.Plugs.DetectLocalePlug)
|
||||||
|
|
||||||
if Application.fetch_env!(:mobilizon, :env) !== :dev do
|
if Application.fetch_env!(:mobilizon, :env) !== :dev do
|
||||||
plug(Mobilizon.Web.Plugs.HTTPSecurityPlug)
|
plug(Mobilizon.Web.Plugs.HTTPSecurityPlug)
|
||||||
|
|
|
@ -21,30 +21,4 @@ defmodule Mobilizon.Web.Gettext do
|
||||||
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
|
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
|
||||||
"""
|
"""
|
||||||
use Gettext, otp_app: :mobilizon
|
use Gettext, otp_app: :mobilizon
|
||||||
|
|
||||||
def put_locale(locale) do
|
|
||||||
locale = determine_best_locale(locale)
|
|
||||||
Gettext.put_locale(__MODULE__, locale)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec determine_best_locale(String.t()) :: String.t()
|
|
||||||
def determine_best_locale(locale) do
|
|
||||||
locale = String.trim(locale)
|
|
||||||
locales = Gettext.known_locales(__MODULE__)
|
|
||||||
default = Keyword.get(Mobilizon.Config.instance_config(), :default_language, "en") || "en"
|
|
||||||
|
|
||||||
cond do
|
|
||||||
# Default if nothing provided
|
|
||||||
locale == "" -> default
|
|
||||||
# Either it matches directly, eg: "en" => "en", "fr" => "fr"
|
|
||||||
locale in locales -> locale
|
|
||||||
# Either the first part matches, "fr_CA" => "fr"
|
|
||||||
split_locale(locale) in locales -> split_locale(locale)
|
|
||||||
# Otherwise set to default
|
|
||||||
true -> default
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Keep only the first part of the locale
|
|
||||||
defp split_locale(locale), do: locale |> String.split("_", trim: true, parts: 2) |> hd
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,7 +40,6 @@ defmodule Mobilizon.Web do
|
||||||
use Phoenix.HTML
|
use Phoenix.HTML
|
||||||
|
|
||||||
import Mobilizon.Web.Router.Helpers
|
import Mobilizon.Web.Router.Helpers
|
||||||
import Mobilizon.Web.ErrorHelpers
|
|
||||||
import Mobilizon.Web.Gettext
|
import Mobilizon.Web.Gettext
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
67
lib/web/plugs/detect_locale_plug.ex
Normal file
67
lib/web/plugs/detect_locale_plug.ex
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# Portions of this file are derived from Pleroma:
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
# NOTE: this module is based on https://github.com/smeevil/set_locale
|
||||||
|
defmodule Mobilizon.Web.Plugs.DetectLocalePlug do
|
||||||
|
@moduledoc """
|
||||||
|
Plug to set locale for Gettext
|
||||||
|
"""
|
||||||
|
import Plug.Conn, only: [get_req_header: 2, assign: 3]
|
||||||
|
alias Mobilizon.Web.Gettext, as: GettextBackend
|
||||||
|
|
||||||
|
def init(_), do: nil
|
||||||
|
|
||||||
|
def call(conn, _) do
|
||||||
|
locale = get_locale_from_header(conn)
|
||||||
|
assign(conn, :detected_locale, locale)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_locale_from_header(conn) do
|
||||||
|
conn
|
||||||
|
|> extract_accept_language()
|
||||||
|
|> Enum.find(&supported_locale?/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp extract_accept_language(conn) do
|
||||||
|
case get_req_header(conn, "accept-language") do
|
||||||
|
[value | _] ->
|
||||||
|
value
|
||||||
|
|> String.split(",")
|
||||||
|
|> Enum.map(&parse_language_option/1)
|
||||||
|
|> Enum.sort(&(&1.quality > &2.quality))
|
||||||
|
|> Enum.map(& &1.tag)
|
||||||
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|> ensure_language_fallbacks()
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp supported_locale?(locale) do
|
||||||
|
GettextBackend
|
||||||
|
|> Gettext.known_locales()
|
||||||
|
|> Enum.member?(locale)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse_language_option(string) do
|
||||||
|
captures = Regex.named_captures(~r/^\s?(?<tag>[\w\-]+)(?:;q=(?<quality>[\d\.]+))?$/i, string)
|
||||||
|
|
||||||
|
quality =
|
||||||
|
case Float.parse(captures["quality"] || "1.0") do
|
||||||
|
{val, _} -> val
|
||||||
|
:error -> 1.0
|
||||||
|
end
|
||||||
|
|
||||||
|
%{tag: captures["tag"], quality: quality}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp ensure_language_fallbacks(tags) do
|
||||||
|
Enum.flat_map(tags, fn tag ->
|
||||||
|
[language | _] = String.split(tag, "-")
|
||||||
|
if Enum.member?(tags, language), do: [tag], else: [tag, language]
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,61 +8,55 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlug do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Plug to set locale for Gettext
|
Plug to set locale for Gettext
|
||||||
"""
|
"""
|
||||||
import Plug.Conn, only: [get_req_header: 2, assign: 3]
|
import Plug.Conn, only: [assign: 3]
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
alias Mobilizon.Web.Gettext, as: GettextBackend
|
||||||
|
|
||||||
def init(_), do: nil
|
def init(_), do: nil
|
||||||
|
|
||||||
def call(conn, _) do
|
def call(conn, _) do
|
||||||
locale = get_locale_from_header(conn)
|
locale =
|
||||||
GettextBackend.put_locale(locale)
|
[
|
||||||
|
conn.assigns[:user_locale],
|
||||||
|
conn.assigns[:detected_locale],
|
||||||
|
default_locale(),
|
||||||
|
"en"
|
||||||
|
]
|
||||||
|
|> Enum.map(&determine_best_locale/1)
|
||||||
|
|> Enum.filter(&supported_locale?/1)
|
||||||
|
|> hd()
|
||||||
|
|
||||||
|
Gettext.put_locale(locale)
|
||||||
assign(conn, :locale, locale)
|
assign(conn, :locale, locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_locale_from_header(conn) do
|
|
||||||
conn
|
|
||||||
|> extract_accept_language()
|
|
||||||
|> Enum.find("", &supported_locale?/1)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp extract_accept_language(conn) do
|
|
||||||
case get_req_header(conn, "accept-language") do
|
|
||||||
[value | _] ->
|
|
||||||
value
|
|
||||||
|> String.split(",")
|
|
||||||
|> Enum.map(&parse_language_option/1)
|
|
||||||
|> Enum.sort(&(&1.quality > &2.quality))
|
|
||||||
|> Enum.map(& &1.tag)
|
|
||||||
|> Enum.reject(&is_nil/1)
|
|
||||||
|> ensure_language_fallbacks()
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp supported_locale?(locale) do
|
defp supported_locale?(locale) do
|
||||||
GettextBackend
|
GettextBackend
|
||||||
|> Gettext.known_locales()
|
|> Gettext.known_locales()
|
||||||
|> Enum.member?(locale)
|
|> Enum.member?(locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_language_option(string) do
|
defp default_locale do
|
||||||
captures = Regex.named_captures(~r/^\s?(?<tag>[\w\-]+)(?:;q=(?<quality>[\d\.]+))?$/i, string)
|
Keyword.get(Mobilizon.Config.instance_config(), :default_language, "en")
|
||||||
|
|
||||||
quality =
|
|
||||||
case Float.parse(captures["quality"] || "1.0") do
|
|
||||||
{val, _} -> val
|
|
||||||
:error -> 1.0
|
|
||||||
end
|
|
||||||
|
|
||||||
%{tag: captures["tag"], quality: quality}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp ensure_language_fallbacks(tags) do
|
@spec determine_best_locale(String.t()) :: String.t()
|
||||||
Enum.flat_map(tags, fn tag ->
|
def determine_best_locale(locale) when is_binary(locale) do
|
||||||
[language | _] = String.split(tag, "-")
|
locale = String.trim(locale)
|
||||||
if Enum.member?(tags, language), do: [tag], else: [tag, language]
|
locales = Gettext.known_locales(GettextBackend)
|
||||||
end)
|
|
||||||
|
cond do
|
||||||
|
locale == "" -> nil
|
||||||
|
# Either it matches directly, eg: "en" => "en", "fr" => "fr"
|
||||||
|
locale in locales -> locale
|
||||||
|
# Either the first part matches, "fr_CA" => "fr"
|
||||||
|
split_locale(locale) in locales -> split_locale(locale)
|
||||||
|
# Otherwise set to default
|
||||||
|
true -> nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def determine_best_locale(_), do: nil
|
||||||
|
|
||||||
|
# Keep only the first part of the locale
|
||||||
|
defp split_locale(locale), do: locale |> String.split("_", trim: true, parts: 2) |> hd
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,10 +7,12 @@ defmodule Mobilizon.Web.Router do
|
||||||
pipeline :graphql do
|
pipeline :graphql do
|
||||||
# plug(:accepts, ["json"])
|
# plug(:accepts, ["json"])
|
||||||
plug(Mobilizon.Web.Auth.Pipeline)
|
plug(Mobilizon.Web.Auth.Pipeline)
|
||||||
|
plug(Mobilizon.Web.Plugs.SetLocalePlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
pipeline :graphiql do
|
pipeline :graphiql do
|
||||||
plug(Mobilizon.Web.Auth.Pipeline)
|
plug(Mobilizon.Web.Auth.Pipeline)
|
||||||
|
plug(Mobilizon.Web.Plugs.SetLocalePlug)
|
||||||
|
|
||||||
plug(Mobilizon.Web.Plugs.HTTPSecurityPlug,
|
plug(Mobilizon.Web.Plugs.HTTPSecurityPlug,
|
||||||
script_src: ["cdn.jsdelivr.net"],
|
script_src: ["cdn.jsdelivr.net"],
|
||||||
|
@ -46,6 +48,8 @@ defmodule Mobilizon.Web.Router do
|
||||||
plug(:accepts, ["html", "activity-json"])
|
plug(:accepts, ["html", "activity-json"])
|
||||||
plug(:put_secure_browser_headers)
|
plug(:put_secure_browser_headers)
|
||||||
|
|
||||||
|
plug(Mobilizon.Web.Plugs.SetLocalePlug)
|
||||||
|
|
||||||
plug(Cldr.Plug.AcceptLanguage,
|
plug(Cldr.Plug.AcceptLanguage,
|
||||||
cldr_backend: Mobilizon.Cldr,
|
cldr_backend: Mobilizon.Cldr,
|
||||||
no_match_log_level: :debug
|
no_match_log_level: :debug
|
||||||
|
@ -60,6 +64,8 @@ defmodule Mobilizon.Web.Router do
|
||||||
pipeline :browser do
|
pipeline :browser do
|
||||||
plug(Plug.Static, at: "/", from: "priv/static")
|
plug(Plug.Static, at: "/", from: "priv/static")
|
||||||
|
|
||||||
|
plug(Mobilizon.Web.Plugs.SetLocalePlug)
|
||||||
|
|
||||||
plug(Cldr.Plug.AcceptLanguage,
|
plug(Cldr.Plug.AcceptLanguage,
|
||||||
cldr_backend: Mobilizon.Cldr,
|
cldr_backend: Mobilizon.Cldr,
|
||||||
no_match_log_level: :debug
|
no_match_log_level: :debug
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
defmodule Mobilizon.Web.ChangesetView do
|
|
||||||
@moduledoc """
|
|
||||||
View for changesets in case of errors
|
|
||||||
"""
|
|
||||||
use Mobilizon.Web, :view
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Traverses and translates changeset errors.
|
|
||||||
|
|
||||||
See `Ecto.Changeset.traverse_errors/2` and
|
|
||||||
`Mobilizon.Web.ErrorHelpers.translate_error/1` for more details.
|
|
||||||
"""
|
|
||||||
def translate_errors(changeset) do
|
|
||||||
Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
|
|
||||||
end
|
|
||||||
|
|
||||||
def render("error.json", %{changeset: changeset}) do
|
|
||||||
# When encoded, the changeset returns its errors
|
|
||||||
# as a JSON object. So we just pass it forward.
|
|
||||||
%{errors: translate_errors(changeset)}
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -5,15 +5,6 @@ defmodule Mobilizon.Web.ErrorHelpers do
|
||||||
|
|
||||||
use Phoenix.HTML
|
use Phoenix.HTML
|
||||||
|
|
||||||
@doc """
|
|
||||||
Generates tag for inlined form input errors.
|
|
||||||
"""
|
|
||||||
def error_tag(form, field) do
|
|
||||||
Enum.map(Keyword.get_values(form.errors, field), fn error ->
|
|
||||||
content_tag(:span, translate_error(error), class: "help-block")
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Translates an error message using gettext.
|
Translates an error message using gettext.
|
||||||
"""
|
"""
|
||||||
|
@ -31,6 +22,7 @@ defmodule Mobilizon.Web.ErrorHelpers do
|
||||||
# dngettext "errors", "1 file", "%{count} files", count
|
# dngettext "errors", "1 file", "%{count} files", count
|
||||||
# dgettext "errors", "is invalid"
|
# dgettext "errors", "is invalid"
|
||||||
#
|
#
|
||||||
|
|
||||||
if count = opts[:count] do
|
if count = opts[:count] do
|
||||||
Gettext.dngettext(Mobilizon.Web.Gettext, "errors", msg, msg, count, opts)
|
Gettext.dngettext(Mobilizon.Web.Gettext, "errors", msg, msg, count, opts)
|
||||||
else
|
else
|
||||||
|
|
|
@ -53,27 +53,6 @@ defmodule Mobilizon.Web.Views.Utils do
|
||||||
|
|
||||||
@spec get_locale(Plug.Conn.t()) :: String.t()
|
@spec get_locale(Plug.Conn.t()) :: String.t()
|
||||||
def get_locale(%Plug.Conn{assigns: assigns}) do
|
def get_locale(%Plug.Conn{assigns: assigns}) do
|
||||||
assigns
|
Map.get(assigns, :locale)
|
||||||
|> Map.get(:locale)
|
|
||||||
|> check_locale()
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_locale(_), do: default_locale()
|
|
||||||
|
|
||||||
defp check_locale(nil) do
|
|
||||||
default_locale()
|
|
||||||
|> check_locale()
|
|
||||||
end
|
|
||||||
|
|
||||||
defp check_locale("") do
|
|
||||||
check_locale(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp check_locale(locale) when is_binary(locale), do: locale
|
|
||||||
|
|
||||||
defp default_locale do
|
|
||||||
Mobilizon.Config.instance_config()
|
|
||||||
|> Keyword.get(:default_language, "en")
|
|
||||||
|> Kernel.||("en")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
1
mix.exs
1
mix.exs
|
@ -300,7 +300,6 @@ defmodule Mobilizon.Mixfile do
|
||||||
Mobilizon.Web.ChangesetView,
|
Mobilizon.Web.ChangesetView,
|
||||||
Mobilizon.Web.JsonLD.ObjectView,
|
Mobilizon.Web.JsonLD.ObjectView,
|
||||||
Mobilizon.Web.EmailView,
|
Mobilizon.Web.EmailView,
|
||||||
Mobilizon.Web.ErrorHelpers,
|
|
||||||
Mobilizon.Web.ErrorView,
|
Mobilizon.Web.ErrorView,
|
||||||
Mobilizon.Web.LayoutView,
|
Mobilizon.Web.LayoutView,
|
||||||
Mobilizon.Web.PageView,
|
Mobilizon.Web.PageView,
|
||||||
|
|
|
@ -374,7 +374,7 @@ defmodule Mobilizon.Web.Resolvers.EventTest do
|
||||||
)
|
)
|
||||||
|
|
||||||
assert hd(res["errors"])["message"] == %{
|
assert hd(res["errors"])["message"] == %{
|
||||||
"maximum_attendee_capacity" => ["must be greater than or equal to %{number}"]
|
"maximum_attendee_capacity" => ["must be greater than or equal to 0"]
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -308,6 +308,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
||||||
test "create_user/3 doesn't allow two users with the same email", %{conn: conn} do
|
test "create_user/3 doesn't allow two users with the same email", %{conn: conn} do
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
|
|> put_req_header("accept-language", "fr")
|
||||||
|> AbsintheHelpers.graphql_query(
|
|> AbsintheHelpers.graphql_query(
|
||||||
query: @create_user_mutation,
|
query: @create_user_mutation,
|
||||||
variables: @user_creation
|
variables: @user_creation
|
||||||
|
@ -397,6 +398,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
||||||
|
|
||||||
test "register_person/3 doesn't register a profile from an unknown email", %{conn: conn} do
|
test "register_person/3 doesn't register a profile from an unknown email", %{conn: conn} do
|
||||||
conn
|
conn
|
||||||
|
|> put_req_header("accept-language", "fr")
|
||||||
|> AbsintheHelpers.graphql_query(
|
|> AbsintheHelpers.graphql_query(
|
||||||
query: @create_user_mutation,
|
query: @create_user_mutation,
|
||||||
variables: @user_creation
|
variables: @user_creation
|
||||||
|
@ -416,6 +418,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
||||||
|
|
||||||
test "register_person/3 can't be called with an existing profile", %{conn: conn} do
|
test "register_person/3 can't be called with an existing profile", %{conn: conn} do
|
||||||
conn
|
conn
|
||||||
|
|> put_req_header("accept-language", "fr")
|
||||||
|> AbsintheHelpers.graphql_query(
|
|> AbsintheHelpers.graphql_query(
|
||||||
query: @create_user_mutation,
|
query: @create_user_mutation,
|
||||||
variables: @user_creation
|
variables: @user_creation
|
||||||
|
@ -423,6 +426,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
||||||
|
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
|
|> put_req_header("accept-language", "fr")
|
||||||
|> AbsintheHelpers.graphql_query(
|
|> AbsintheHelpers.graphql_query(
|
||||||
query: @register_person_mutation,
|
query: @register_person_mutation,
|
||||||
variables: @user_creation
|
variables: @user_creation
|
||||||
|
@ -447,6 +451,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
||||||
insert(:actor, preferred_username: "myactor")
|
insert(:actor, preferred_username: "myactor")
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|
|> put_req_header("accept-language", "fr")
|
||||||
|> AbsintheHelpers.graphql_query(
|
|> AbsintheHelpers.graphql_query(
|
||||||
query: @create_user_mutation,
|
query: @create_user_mutation,
|
||||||
variables: @user_creation
|
variables: @user_creation
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
defmodule Mobilizon.Web.GettextTest do
|
|
||||||
use ExUnit.Case, async: true
|
|
||||||
|
|
||||||
alias Mobilizon.Config
|
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
|
||||||
|
|
||||||
describe "test determine_best_locale/1" do
|
|
||||||
setup do
|
|
||||||
Config.put([:instance, :default_language], "en")
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with empty string returns the default locale" do
|
|
||||||
assert GettextBackend.determine_best_locale("") == "en"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with empty string returns the default configured locale" do
|
|
||||||
Config.put([:instance, :default_language], "es")
|
|
||||||
assert GettextBackend.determine_best_locale("") == "es"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "with empty string returns english as a proper fallback if the default configured locale is nil" do
|
|
||||||
Config.put([:instance, :default_language], nil)
|
|
||||||
assert GettextBackend.determine_best_locale("") == "en"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns fallback with an unexisting locale" do
|
|
||||||
assert GettextBackend.determine_best_locale("yolo") == "en"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "maps the correct part if the locale has multiple ones" do
|
|
||||||
assert GettextBackend.determine_best_locale("fr_CA") == "fr"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns the locale if valid" do
|
|
||||||
assert GettextBackend.determine_best_locale("es") == "es"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
35
test/web/plugs/detect_locale_plug_test.exs
Normal file
35
test/web/plugs/detect_locale_plug_test.exs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Portions of this file are derived from Pleroma:
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Mobilizon.Web.Plugs.DetectLocalePlugTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
use Plug.Test
|
||||||
|
|
||||||
|
alias Mobilizon.Web.Plugs.DetectLocalePlug
|
||||||
|
alias Plug.Conn
|
||||||
|
|
||||||
|
test "use supported locale from `accept-language`" do
|
||||||
|
conn =
|
||||||
|
:get
|
||||||
|
|> conn("/cofe")
|
||||||
|
|> Conn.put_req_header(
|
||||||
|
"accept-language",
|
||||||
|
"ru, fr-CH, fr;q=0.9, en;q=0.8, *;q=0.5"
|
||||||
|
)
|
||||||
|
|> DetectLocalePlug.call([])
|
||||||
|
|
||||||
|
assert %{detected_locale: "ru"} == conn.assigns
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns empty string if `accept-language` header is empty" do
|
||||||
|
conn =
|
||||||
|
:get
|
||||||
|
|> conn("/cofe")
|
||||||
|
|> Conn.put_req_header("accept-language", "tlh")
|
||||||
|
|> DetectLocalePlug.call([])
|
||||||
|
|
||||||
|
assert %{detected_locale: nil} == conn.assigns
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,42 +7,87 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlugTest do
|
||||||
use ExUnit.Case, async: true
|
use ExUnit.Case, async: true
|
||||||
use Plug.Test
|
use Plug.Test
|
||||||
|
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
alias Mobilizon.Config
|
||||||
alias Mobilizon.Web.Plugs.SetLocalePlug
|
alias Mobilizon.Web.Plugs.SetLocalePlug
|
||||||
alias Plug.Conn
|
alias Plug.Conn
|
||||||
|
|
||||||
test "default locale is `en`" do
|
describe "test assigning locale to conn" do
|
||||||
conn =
|
test "use supported locale from `accept-language`" do
|
||||||
:get
|
conn =
|
||||||
|> conn("/cofe")
|
:get
|
||||||
|> SetLocalePlug.call([])
|
|> conn("/cofe")
|
||||||
|
|> assign(:detected_locale, "ru")
|
||||||
|
|> SetLocalePlug.call([])
|
||||||
|
|
||||||
assert "en" == Gettext.get_locale()
|
assert "ru" == Gettext.get_locale()
|
||||||
assert %{locale: ""} == conn.assigns
|
assert %{locale: "ru", detected_locale: "ru"} == conn.assigns
|
||||||
|
end
|
||||||
|
|
||||||
|
test "use default locale if locale from `accept-language` is not supported" do
|
||||||
|
conn =
|
||||||
|
:get
|
||||||
|
|> conn("/cofe")
|
||||||
|
|> Conn.put_req_header("accept-language", "tlh")
|
||||||
|
|> SetLocalePlug.call([])
|
||||||
|
|
||||||
|
assert "en" == Gettext.get_locale()
|
||||||
|
assert %{locale: "en"} == conn.assigns
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "use supported locale from `accept-language`" do
|
describe "test getting default locale from instance" do
|
||||||
conn =
|
test "default locale is `en`" do
|
||||||
:get
|
conn =
|
||||||
|> conn("/cofe")
|
:get
|
||||||
|> Conn.put_req_header(
|
|> conn("/cofe")
|
||||||
"accept-language",
|
|> SetLocalePlug.call([])
|
||||||
"ru, fr-CH, fr;q=0.9, en;q=0.8, *;q=0.5"
|
|
||||||
)
|
|
||||||
|> SetLocalePlug.call([])
|
|
||||||
|
|
||||||
assert "ru" == Gettext.get_locale(GettextBackend)
|
assert "en" == Gettext.get_locale()
|
||||||
assert %{locale: "ru"} == conn.assigns
|
assert %{locale: "en"} == conn.assigns
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with empty string returns the default configured locale" do
|
||||||
|
Config.put([:instance, :default_language], "es")
|
||||||
|
|
||||||
|
conn =
|
||||||
|
:get
|
||||||
|
|> conn("/cofe")
|
||||||
|
|> SetLocalePlug.call([])
|
||||||
|
|
||||||
|
assert %{locale: "es"} == conn.assigns
|
||||||
|
|
||||||
|
Config.put([:instance, :default_language], "en")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with empty string returns english as a proper fallback if the default configured locale is nil" do
|
||||||
|
Config.put([:instance, :default_language], nil)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
:get
|
||||||
|
|> conn("/cofe")
|
||||||
|
|> SetLocalePlug.call([])
|
||||||
|
|
||||||
|
assert %{locale: "en"} == conn.assigns
|
||||||
|
|
||||||
|
Config.put([:instance, :default_language], "en")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "use default locale if locale from `accept-language` is not supported" do
|
describe "test determine_best_locale/1" do
|
||||||
conn =
|
test "with empty string returns the default locale" do
|
||||||
:get
|
assert SetLocalePlug.determine_best_locale("") == nil
|
||||||
|> conn("/cofe")
|
end
|
||||||
|> Conn.put_req_header("accept-language", "tlh")
|
|
||||||
|> SetLocalePlug.call([])
|
|
||||||
|
|
||||||
assert "en" == Gettext.get_locale(GettextBackend)
|
test "returns fallback with an unexisting locale" do
|
||||||
assert %{locale: ""} == conn.assigns
|
assert SetLocalePlug.determine_best_locale("yolo") == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
test "maps the correct part if the locale has multiple ones" do
|
||||||
|
assert SetLocalePlug.determine_best_locale("fr_CA") == "fr"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns the locale if valid" do
|
||||||
|
assert SetLocalePlug.determine_best_locale("es") == "es"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue