Prefer userLanguage cookie over Accept-Language header in detecting locale
authorTusooa Zhu <tusooa@kazv.moe>
Mon, 21 Feb 2022 22:54:18 +0000 (17:54 -0500)
committerFloatingGhost <hannah@coffee-and-dreams.uk>
Wed, 29 Jun 2022 19:43:41 +0000 (20:43 +0100)
https://git.pleroma.social/pleroma/pleroma-meta/-/issues/60

lib/pleroma/web/plugs/set_locale_plug.ex
test/pleroma/web/plugs/set_locale_plug_test.exs

index d77191cffb05b0247e661e9d994e00cd8a83d04e..446baf24b896f19be112ae49b74b7f3ab8ff1b9d 100644 (file)
@@ -6,6 +6,8 @@
 defmodule Pleroma.Web.Plugs.SetLocalePlug do
   import Plug.Conn, only: [get_req_header: 2, assign: 3]
 
+  def frontend_language_cookie_name(), do: "userLanguage"
+
   def init(_), do: nil
 
   def call(conn, _) do
@@ -16,10 +18,35 @@ defmodule Pleroma.Web.Plugs.SetLocalePlug do
 
   defp get_locale_from_header(conn) do
     conn
-    |> extract_accept_language()
+    |> extract_preferred_language()
+    |> normalize_language_codes()
     |> Enum.find(&supported_locale?/1)
   end
 
+  defp normalize_language_codes(codes) do
+    codes
+    |> Enum.map(fn code -> String.replace(code, "-", "_") end)
+  end
+
+  defp extract_preferred_language(conn) do
+    extract_frontend_language(conn) ++ extract_accept_language(conn)
+  end
+
+  defp extract_frontend_language(conn) do
+    %{req_cookies: cookies} =
+      conn
+      |> Plug.Conn.fetch_cookies()
+
+    case cookies[frontend_language_cookie_name()] do
+      nil ->
+        []
+
+      fe_lang ->
+        [fe_lang]
+        |> ensure_language_fallbacks()
+    end
+  end
+
   defp extract_accept_language(conn) do
     case get_req_header(conn, "accept-language") do
       [value | _] ->
index 5261e67aec64b23a49f4f6c29af559273bcac7da..043d7eb1822e5572c55b58a81ca1183b2c0105de 100644 (file)
@@ -33,6 +33,65 @@ defmodule Pleroma.Web.Plugs.SetLocalePlugTest do
     assert %{locale: "ru"} == conn.assigns
   end
 
+  test "use supported locale with specifiers from `accept-language`" do
+    conn =
+      :get
+      |> conn("/cofe")
+      |> Conn.put_req_header(
+        "accept-language",
+        "zh-Hans;q=0.9, en;q=0.8, *;q=0.5"
+      )
+      |> SetLocalePlug.call([])
+
+    assert "zh_Hans" == Gettext.get_locale()
+    assert %{locale: "zh_Hans"} == conn.assigns
+  end
+
+  test "use supported locale from cookie" do
+    conn =
+      :get
+      |> conn("/cofe")
+      |> put_req_cookie(SetLocalePlug.frontend_language_cookie_name(), "zh-Hans")
+      |> Conn.put_req_header(
+        "accept-language",
+        "ru, fr-CH, fr;q=0.9, en;q=0.8, *;q=0.5"
+      )
+      |> SetLocalePlug.call([])
+
+    assert "zh_Hans" == Gettext.get_locale()
+    assert %{locale: "zh_Hans"} == conn.assigns
+  end
+
+  test "fallback to supported locale from `accept-language` if locale in cookie not supported" do
+    conn =
+      :get
+      |> conn("/cofe")
+      |> put_req_cookie(SetLocalePlug.frontend_language_cookie_name(), "x-nonexist")
+      |> Conn.put_req_header(
+        "accept-language",
+        "ru, fr-CH, fr;q=0.9, en;q=0.8, *;q=0.5"
+      )
+      |> SetLocalePlug.call([])
+
+    assert "ru" == Gettext.get_locale()
+    assert %{locale: "ru"} == conn.assigns
+  end
+
+  test "fallback to default if nothing is supported" do
+    conn =
+      :get
+      |> conn("/cofe")
+      |> put_req_cookie(SetLocalePlug.frontend_language_cookie_name(), "x-nonexist")
+      |> Conn.put_req_header(
+        "accept-language",
+        "x-nonexist"
+      )
+      |> SetLocalePlug.call([])
+
+    assert "en" == Gettext.get_locale()
+    assert %{locale: "en"} == conn.assigns
+  end
+
   test "use default locale if locale from `accept-language` is not supported" do
     conn =
       :get