Page MenuHomePhorge

No OneTemporary

Size
12 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/pleroma/web/gettext.ex b/lib/pleroma/web/gettext.ex
index 51e56939e..7afcd38f0 100644
--- a/lib/pleroma/web/gettext.ex
+++ b/lib/pleroma/web/gettext.ex
@@ -1,205 +1,220 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Gettext do
@moduledoc """
A module providing Internationalization with a gettext-based API.
By using [Gettext](https://hexdocs.pm/gettext),
your module gains a set of macros for translations, for example:
import Pleroma.Web.Gettext
# Simple translation
gettext "Here is the string to translate"
# Plural translation
ngettext "Here is the string to translate",
"Here are the strings to translate",
3
# Domain-based translation
dgettext "errors", "Here is the error message to translate"
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
"""
use Gettext, otp_app: :pleroma
def language_tag do
# Naive implementation: HTML lang attribute uses BCP 47, which
# uses - as a separator.
# https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang
Gettext.get_locale()
|> String.replace("_", "-", global: true)
end
def normalize_locale(locale) do
if is_binary(locale) do
String.replace(locale, "-", "_", global: true)
else
nil
end
end
def supports_locale?(locale) do
Pleroma.Web.Gettext
|> Gettext.known_locales()
|> Enum.member?(locale)
end
def variant?(locale), do: String.contains?(locale, "_")
def language_for_variant(locale) do
Enum.at(String.split(locale, "_"), 0)
end
def ensure_fallbacks(locales) do
locales
|> Enum.flat_map(fn locale ->
others =
other_supported_variants_of_locale(locale)
|> Enum.filter(fn l -> not Enum.member?(locales, l) end)
[locale] ++ others
end)
end
def other_supported_variants_of_locale(locale) do
cond do
supports_locale?(locale) ->
[]
variant?(locale) ->
lang = language_for_variant(locale)
if supports_locale?(lang), do: [lang], else: []
true ->
Gettext.known_locales(Pleroma.Web.Gettext)
|> Enum.filter(fn l -> String.starts_with?(l, locale <> "_") end)
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
else
Gettext.get_locale()
end
end
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})
Process.delete(Gettext)
end
end
end
defmacro with_locales(locales, do: fun) do
quote do
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
defp next_locale(locale, list) do
index = Enum.find_index(list, fn item -> item == locale end)
if not is_nil(index) do
Enum.at(list, index + 1)
else
nil
end
end
+ # We do not yet have a proper English translation. The "English"
+ # version is currently but the fallback msgid. However, this
+ # will not work if the user puts English as the first language,
+ # and at the same time specifies other languages, as gettext will
+ # think the English translation is missing, and call
+ # handle_missing_translation functions. This may result in
+ # text in other languages being shown even if English is preferred
+ # by the user.
+ #
+ # To prevent this, we do not allow fallbacking when the current
+ # locale missing a translation is English.
+ defp should_fallback?(locale) do
+ locale != "en"
+ end
+
def handle_missing_translation(locale, domain, msgctxt, msgid, bindings) do
next = next_locale(locale, get_locales())
- if is_nil(next) do
+ if is_nil(next) or not should_fallback?(locale) do
super(locale, domain, msgctxt, msgid, bindings)
else
{:ok,
Gettext.with_locale(next, fn ->
Gettext.dpgettext(Pleroma.Web.Gettext, domain, msgctxt, msgid, bindings)
end)}
end
end
def handle_missing_plural_translation(
locale,
domain,
msgctxt,
msgid,
msgid_plural,
n,
bindings
) do
next = next_locale(locale, get_locales())
- if is_nil(next) do
+ if is_nil(next) or not should_fallback?(locale) do
super(locale, domain, msgctxt, msgid, msgid_plural, n, bindings)
else
{:ok,
Gettext.with_locale(next, fn ->
Gettext.dpngettext(
Pleroma.Web.Gettext,
domain,
msgctxt,
msgid,
msgid_plural,
n,
bindings
)
end)}
end
end
end
diff --git a/test/pleroma/web/gettext_test.exs b/test/pleroma/web/gettext_test.exs
index 9ede4827e..e186f1ab3 100644
--- a/test/pleroma/web/gettext_test.exs
+++ b/test/pleroma/web/gettext_test.exs
@@ -1,162 +1,173 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.GettextTest do
use ExUnit.Case
require Pleroma.Web.Gettext
test "put_locales/1: set the first in the list to Gettext's locale" do
Pleroma.Web.Gettext.put_locales(["zh_Hans", "en_test"])
assert "zh_Hans" == Gettext.get_locale(Pleroma.Web.Gettext)
end
test "with_locales/2: reset locale on exit" do
old_first_locale = Gettext.get_locale(Pleroma.Web.Gettext)
old_locales = Pleroma.Web.Gettext.get_locales()
Pleroma.Web.Gettext.with_locales ["zh_Hans", "en_test"] do
assert "zh_Hans" == Gettext.get_locale(Pleroma.Web.Gettext)
assert ["zh_Hans", "en_test"] == Pleroma.Web.Gettext.get_locales()
end
assert old_first_locale == Gettext.get_locale(Pleroma.Web.Gettext)
assert old_locales == Pleroma.Web.Gettext.get_locales()
end
describe "handle_missing_translation/5" do
test "fallback to next locale if some translation is not available" do
Pleroma.Web.Gettext.with_locales ["x_unsupported", "en_test"] do
assert "xxYour account is awaiting approvalxx" ==
Pleroma.Web.Gettext.dpgettext(
"static_pages",
"approval pending email subject",
"Your account is awaiting approval"
)
end
end
+ test "putting en locale at the front should not make gettext fallback unexpectedly" do
+ Pleroma.Web.Gettext.with_locales ["en", "en_test"] do
+ assert "Your account is awaiting approval" ==
+ Pleroma.Web.Gettext.dpgettext(
+ "static_pages",
+ "approval pending email subject",
+ "Your account is awaiting approval"
+ )
+ end
+ end
+
test "duplicated locale in list should not result in infinite loops" do
Pleroma.Web.Gettext.with_locales ["x_unsupported", "x_unsupported", "en_test"] do
assert "xxYour account is awaiting approvalxx" ==
Pleroma.Web.Gettext.dpgettext(
"static_pages",
"approval pending email subject",
"Your account is awaiting approval"
)
end
end
test "direct interpolation" do
Pleroma.Web.Gettext.with_locales ["en_test"] do
assert "xxYour digest from some instancexx" ==
Pleroma.Web.Gettext.dpgettext(
"static_pages",
"digest email subject",
"Your digest from %{instance_name}",
instance_name: "some instance"
)
end
end
test "fallback with interpolation" do
Pleroma.Web.Gettext.with_locales ["x_unsupported", "en_test"] do
assert "xxYour digest from some instancexx" ==
Pleroma.Web.Gettext.dpgettext(
"static_pages",
"digest email subject",
"Your digest from %{instance_name}",
instance_name: "some instance"
)
end
end
test "fallback to msgid" do
Pleroma.Web.Gettext.with_locales ["x_unsupported"] do
assert "Your digest from some instance" ==
Pleroma.Web.Gettext.dpgettext(
"static_pages",
"digest email subject",
"Your digest from %{instance_name}",
instance_name: "some instance"
)
end
end
end
describe "handle_missing_plural_translation/7" do
test "direct interpolation" do
Pleroma.Web.Gettext.with_locales ["en_test"] do
assert "xx1 New Followerxx" ==
Pleroma.Web.Gettext.dpngettext(
"static_pages",
"new followers count header",
"%{count} New Follower",
"%{count} New Followers",
1,
count: 1
)
assert "xx5 New Followersxx" ==
Pleroma.Web.Gettext.dpngettext(
"static_pages",
"new followers count header",
"%{count} New Follower",
"%{count} New Followers",
5,
count: 5
)
end
end
test "fallback with interpolation" do
Pleroma.Web.Gettext.with_locales ["x_unsupported", "en_test"] do
assert "xx1 New Followerxx" ==
Pleroma.Web.Gettext.dpngettext(
"static_pages",
"new followers count header",
"%{count} New Follower",
"%{count} New Followers",
1,
count: 1
)
assert "xx5 New Followersxx" ==
Pleroma.Web.Gettext.dpngettext(
"static_pages",
"new followers count header",
"%{count} New Follower",
"%{count} New Followers",
5,
count: 5
)
end
end
test "fallback to msgid" do
Pleroma.Web.Gettext.with_locales ["x_unsupported"] do
assert "1 New Follower" ==
Pleroma.Web.Gettext.dpngettext(
"static_pages",
"new followers count header",
"%{count} New Follower",
"%{count} New Followers",
1,
count: 1
)
assert "5 New Followers" ==
Pleroma.Web.Gettext.dpngettext(
"static_pages",
"new followers count header",
"%{count} New Follower",
"%{count} New Followers",
5,
count: 5
)
end
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 9, 8:59 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1784603
Default Alt Text
(12 KB)

Event Timeline