Support multiple locales formally
elixir gettext current does not fully support fallback to another language [0]. But it might in the future. We adapt it so that all languages in Accept-Language headers are received by Pleroma.Web.Gettext. User.languages is now a comma-separated list. [0]: https://github.com/elixir-gettext/gettext/issues/303
This commit is contained in:
parent
ef1a046a2d
commit
f3b7ee7836
3 changed files with 89 additions and 17 deletions
|
@ -65,6 +65,24 @@ def supported_variants_of_locale(locale) do
|
|||
end
|
||||
end
|
||||
|
||||
def get_locales() do
|
||||
Process.get({Pleroma.Web.Gettext, :locales}, [])
|
||||
end
|
||||
|
||||
def is_locale_list(locales) do
|
||||
Enum.all?(locales, &is_binary/1)
|
||||
end
|
||||
|
||||
def put_locales(locales) do
|
||||
if is_locale_list(locales) do
|
||||
Process.put({Pleroma.Web.Gettext, :locales}, Enum.uniq(locales))
|
||||
Gettext.put_locale(Enum.at(locales, 0, Gettext.get_locale()))
|
||||
:ok
|
||||
else
|
||||
{:error, :not_locale_list}
|
||||
end
|
||||
end
|
||||
|
||||
def locale_or_default(locale) do
|
||||
if supports_locale?(locale) do
|
||||
locale
|
||||
|
@ -73,11 +91,46 @@ def locale_or_default(locale) do
|
|||
end
|
||||
end
|
||||
|
||||
defmacro with_locale_or_default(locale, do: fun) do
|
||||
def with_locales_func(locales, fun) do
|
||||
prev_locales = Process.get({Pleroma.Web.Gettext, :locales})
|
||||
put_locales(locales)
|
||||
|
||||
try do
|
||||
fun.()
|
||||
after
|
||||
if prev_locales do
|
||||
put_locales(prev_locales)
|
||||
else
|
||||
Process.delete({Pleroma.Web.Gettext, :locales})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmacro with_locales(locales, do: fun) do
|
||||
quote do
|
||||
Gettext.with_locale(Pleroma.Web.Gettext.locale_or_default(unquote(locale)), fn ->
|
||||
Pleroma.Web.Gettext.with_locales_func(unquote(locales), fn ->
|
||||
unquote(fun)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
def to_locale_list(locale) when is_binary(locale) do
|
||||
locale
|
||||
|> String.split(",")
|
||||
|> Enum.filter(&supports_locale?/1)
|
||||
end
|
||||
|
||||
def to_locale_list(_), do: []
|
||||
|
||||
defmacro with_locale_or_default(locale, do: fun) do
|
||||
quote do
|
||||
Pleroma.Web.Gettext.with_locales_func(
|
||||
Pleroma.Web.Gettext.to_locale_list(unquote(locale))
|
||||
|> Enum.concat(Pleroma.Web.Gettext.get_locales()),
|
||||
fn ->
|
||||
unquote(fun)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,22 +11,27 @@ def frontend_language_cookie_name, do: "userLanguage"
|
|||
def init(_), do: nil
|
||||
|
||||
def call(conn, _) do
|
||||
locale = get_locale_from_header(conn) || Gettext.get_locale()
|
||||
Gettext.put_locale(locale)
|
||||
assign(conn, :locale, locale)
|
||||
locales = get_locales_from_header(conn)
|
||||
first_locale = Enum.at(locales, 0, Gettext.get_locale())
|
||||
|
||||
Pleroma.Web.Gettext.put_locales(locales)
|
||||
|
||||
conn
|
||||
|> assign(:locale, first_locale)
|
||||
|> assign(:locales, locales)
|
||||
end
|
||||
|
||||
defp get_locale_from_header(conn) do
|
||||
defp get_locales_from_header(conn) do
|
||||
conn
|
||||
|> extract_preferred_language()
|
||||
|> normalize_language_codes()
|
||||
|> first_supported()
|
||||
|> all_supported()
|
||||
end
|
||||
|
||||
defp first_supported(locales) do
|
||||
defp all_supported(locales) do
|
||||
locales
|
||||
|> Enum.flat_map(&Pleroma.Web.Gettext.supported_variants_of_locale/1)
|
||||
|> Enum.find(&supported_locale?/1)
|
||||
|> Enum.filter(&supported_locale?/1)
|
||||
end
|
||||
|
||||
defp normalize_language_codes(codes) do
|
||||
|
|
|
@ -16,7 +16,7 @@ test "default locale is `en`" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "en" == Gettext.get_locale()
|
||||
assert %{locale: "en"} == conn.assigns
|
||||
assert %{locale: "en"} = conn.assigns
|
||||
end
|
||||
|
||||
test "use supported locale from `accept-language`" do
|
||||
|
@ -30,7 +30,7 @@ test "use supported locale from `accept-language`" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "ru" == Gettext.get_locale()
|
||||
assert %{locale: "ru"} == conn.assigns
|
||||
assert %{locale: "ru"} = conn.assigns
|
||||
end
|
||||
|
||||
test "fallback to the general language if a variant is not supported" do
|
||||
|
@ -44,7 +44,7 @@ test "fallback to the general language if a variant is not supported" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "ru" == Gettext.get_locale()
|
||||
assert %{locale: "ru"} == conn.assigns
|
||||
assert %{locale: "ru"} = conn.assigns
|
||||
end
|
||||
|
||||
test "use supported locale with specifiers from `accept-language`" do
|
||||
|
@ -58,7 +58,21 @@ test "use supported locale with specifiers from `accept-language`" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "zh_Hans" == Gettext.get_locale()
|
||||
assert %{locale: "zh_Hans"} == conn.assigns
|
||||
assert %{locale: "zh_Hans"} = conn.assigns
|
||||
end
|
||||
|
||||
test "it assigns all supported locales" do
|
||||
conn =
|
||||
:get
|
||||
|> conn("/cofe")
|
||||
|> Conn.put_req_header(
|
||||
"accept-language",
|
||||
"ru, fr-CH, fr;q=0.9, en;q=0.8, x-unsupported;q=0.8, *;q=0.5"
|
||||
)
|
||||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "ru" == Gettext.get_locale()
|
||||
assert %{locale: "ru", locales: ["ru", "fr", "en"]} = conn.assigns
|
||||
end
|
||||
|
||||
test "fallback to some variant of the language if the unqualified language is not supported" do
|
||||
|
@ -87,7 +101,7 @@ test "use supported locale from cookie" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "zh_Hans" == Gettext.get_locale()
|
||||
assert %{locale: "zh_Hans"} == conn.assigns
|
||||
assert %{locale: "zh_Hans"} = conn.assigns
|
||||
end
|
||||
|
||||
test "fallback to supported locale from `accept-language` if locale in cookie not supported" do
|
||||
|
@ -102,7 +116,7 @@ test "fallback to supported locale from `accept-language` if locale in cookie no
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "ru" == Gettext.get_locale()
|
||||
assert %{locale: "ru"} == conn.assigns
|
||||
assert %{locale: "ru"} = conn.assigns
|
||||
end
|
||||
|
||||
test "fallback to default if nothing is supported" do
|
||||
|
@ -117,7 +131,7 @@ test "fallback to default if nothing is supported" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "en" == Gettext.get_locale()
|
||||
assert %{locale: "en"} == conn.assigns
|
||||
assert %{locale: "en"} = conn.assigns
|
||||
end
|
||||
|
||||
test "use default locale if locale from `accept-language` is not supported" do
|
||||
|
@ -128,6 +142,6 @@ test "use default locale if locale from `accept-language` is not supported" do
|
|||
|> SetLocalePlug.call([])
|
||||
|
||||
assert "en" == Gettext.get_locale()
|
||||
assert %{locale: "en"} == conn.assigns
|
||||
assert %{locale: "en"} = conn.assigns
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue