Skip to content

Commit

Permalink
Merge pull request #4481 from esl/translations_as_a_service
Browse files Browse the repository at this point in the history
Translations as a service
  • Loading branch information
arcusfelis authored Feb 6, 2025
2 parents 249ba9e + 8f4011d commit 704a926
Show file tree
Hide file tree
Showing 65 changed files with 122 additions and 99 deletions.
5 changes: 5 additions & 0 deletions doc/configuration/Services.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ The number of seconds between cleaning attempts of the `domain_events` table.

The number of seconds after an event must be deleted from the `domain_events` table.

## service_translations

Enables translations for system messages.
Support is minimal, you can check `priv/translations/` for translated messages.

## Example configuration

```toml
Expand Down
2 changes: 1 addition & 1 deletion include/mod_vcard.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
-export_type([vcard_search/0]).

-define(TLFIELD(Type, Label, Var),
#{var => Var, type => Type, label => translate:translate(Lang, Label)}).
#{var => Var, type => Type, label => service_translations:do(Lang, Label)}).

-define(FIELD(Var, Val),
#{var => Var, values => [Val]}).
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
3 changes: 2 additions & 1 deletion src/config/mongoose_config_spec.erl
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,8 @@ services() ->

configurable_services() ->
[service_mongoose_system_metrics,
service_domain_db].
service_domain_db,
service_translations].

%% path: (host_config[].)modules
modules() ->
Expand Down
1 change: 0 additions & 1 deletion src/ejabberd_app.erl
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ do_start() ->
mongoose_config:start(),
mongoose_internal_databases:init(),
mongoose_graphql:init(),
translate:start(),
mongoose_graphql_commands:start(),
mongoose_logs:set_global_loglevel(mongoose_config:get_opt(loglevel)),
mongoose_deprecations:start(),
Expand Down
2 changes: 1 addition & 1 deletion src/http_upload/mod_http_upload.erl
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ subdomain_pattern(HostType) ->

-spec my_disco_name(ejabberd:lang()) -> binary().
my_disco_name(Lang) ->
translate:translate(Lang, <<"HTTP File Upload">>).
service_translations:do(Lang, <<"HTTP File Upload">>).


-spec compose_iq_reply(IQ :: jlib:iq(),
Expand Down
4 changes: 2 additions & 2 deletions src/jlib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ stanza_error(Code, Type, Condition) ->
, Lang :: ejabberd:lang()
, Text :: binary()) -> exml:element().
stanza_errort(Code, Type, Condition, Lang, Text) ->
Txt = translate:translate(Lang, Text),
Txt = service_translations:do(Lang, Text),
#xmlel{ name = <<"error">>
, attrs = #{<<"code">> => Code, <<"type">> => Type}
, children = [ #xmlel{ name = Condition
Expand All @@ -432,7 +432,7 @@ stream_error(Condition) ->
, Lang :: ejabberd:lang()
, Text :: binary()) -> exml:element().
stream_errort(Condition, Lang, Text) ->
Txt = translate:translate(Lang, Text),
Txt = service_translations:do(Lang, Text),
#xmlel{ name = <<"stream:error">>
, children = [ #xmlel{ name = Condition
, attrs = #{<<"xmlns">> => ?NS_STREAMS} }
Expand Down
8 changes: 4 additions & 4 deletions src/mod_adhoc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ are_commands_visible(HostType) ->
gen_mod:get_module_opt(HostType, ?MODULE, report_commands_node).

item(LServer, Node, Name, Lang) ->
#{jid => LServer, node => Node, name => translate:translate(Lang, Name)}.
#{jid => LServer, node => Node, name => service_translations:do(Lang, Name)}.

%%-------------------------------------------------------------------------

Expand Down Expand Up @@ -211,12 +211,12 @@ disco_sm_identity(Acc, _, _) ->
ping_identity(Lang) ->
#{category => <<"automation">>,
type => <<"command-node">>,
name => translate:translate(Lang, <<"Ping">>)}.
name => service_translations:do(Lang, <<"Ping">>)}.

command_list_identity(Lang) ->
#{category => <<"automation">>,
type => <<"command-list">>,
name => translate:translate(Lang, <<"Commands">>)}.
name => service_translations:do(Lang, <<"Commands">>)}.

%%-------------------------------------------------------------------------

Expand Down Expand Up @@ -266,7 +266,7 @@ ping_command(empty,
node = Node,
session_id = SessionID,
status = completed,
notes = [{<<"info">>, translate:translate(Lang, <<"Pong">>)}]});
notes = [{<<"info">>, service_translations:do(Lang, <<"Pong">>)}]});
false ->
{error, mongoose_xmpp_errors:bad_request()}
end,
Expand Down
2 changes: 1 addition & 1 deletion src/mod_register.erl
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ process_iq_get(_HostType, From, _To, #iq{lang = Lang, sub_el = Child} = IQ, _Sou
_ ->
{false, [], []}
end,
TranslatedMsg = translate:translate(
TranslatedMsg = service_translations:do(
Lang, <<"Choose a username and password to register with this server">>),
IQ#iq{type = result,
sub_el = [#xmlel{name = <<"query">>,
Expand Down
12 changes: 6 additions & 6 deletions src/muc/mod_muc.erl
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ default_host() ->
identity(Lang) ->
#{category => <<"conference">>,
type => <<"text">>,
name => translate:translate(Lang, <<"Chatrooms">>)}.
name => service_translations:do(Lang, <<"Chatrooms">>)}.

features() ->
[?NS_DISCO_INFO, ?NS_DISCO_ITEMS, ?NS_MUC, ?NS_MUC_UNIQUE, ?NS_REGISTER, ?NS_RSM, ?NS_VCARD, ?NS_CONFERENCE].
Expand Down Expand Up @@ -1049,15 +1049,15 @@ iq_get_register_info(HostType, MucHost, From, Lang) ->
{ok, N} ->
{N, [#xmlel{name = <<"registered">>}]}
end,
ClientReqText = translate:translate(
ClientReqText = service_translations:do(
Lang, <<"You need a client that supports x:data to register the nickname">>),
ClientReqEl = #xmlel{name = <<"instructions">>,
children = [#xmlcdata{content = ClientReqText}]},
EnterNicknameText = translate:translate(Lang, <<"Enter nickname you want to register">>),
TitleText = <<(translate:translate(Lang, <<"Nickname Registration at ">>))/binary,
EnterNicknameText = service_translations:do(Lang, <<"Enter nickname you want to register">>),
TitleText = <<(service_translations:do(Lang, <<"Nickname Registration at ">>))/binary,
MucHost/binary>>,
NickField = #{type => <<"text-single">>,
label => translate:translate(Lang, <<"Nickname">>),
label => service_translations:do(Lang, <<"Nickname">>),
var => <<"nick">>,
values => [Nick]},
Registered ++ [ClientReqEl, mongoose_data_forms:form(#{title => TitleText,
Expand Down Expand Up @@ -1136,7 +1136,7 @@ iq_get_vcard(Lang) ->
#xmlel{name = <<"URL">>, children = [#xmlcdata{content = ?MONGOOSE_URI}]},
#xmlel{name = <<"DESC">>,
children = [#xmlcdata{content =
<<(translate:translate(Lang, <<"ejabberd MUC module">>))/binary,
<<(service_translations:do(Lang, <<"ejabberd MUC module">>))/binary,
"\nCopyright (c) 2003-2011 ProcessOne">>}]}].

-spec broadcast_service_message(muc_host(), binary() | string()) -> ok.
Expand Down
2 changes: 1 addition & 1 deletion src/muc/mod_muc_log.erl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
-include("mod_muc_room.hrl").
-include("mongoose_config_spec.hrl").

-define(T(Text), translate:translate(Lang, Text)).
-define(T(Text), service_translations:do(Lang, Text)).
-define(PROCNAME, ejabberd_mod_muc_log).

-record(room, {jid, title, subject, subject_author, config}).
Expand Down
50 changes: 25 additions & 25 deletions src/muc/mod_muc_room.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ process_presence_error(From, Packet, Lang, StateData) ->
true ->
ErrorText
= <<"This participant is kicked from the room because he sent an error presence">>,
expulse_participant(Packet, From, StateData, translate:translate(Lang, ErrorText));
expulse_participant(Packet, From, StateData, service_translations:do(Lang, ErrorText));
_ ->
StateData
end.
Expand Down Expand Up @@ -2862,8 +2862,8 @@ get_affected_jid(Item, Lang, StateData) ->
{S, _} when undefined =/= S ->
case jid:from_binary(S) of
error ->
ErrText = <<(translate:translate(Lang, <<"Jabber ID ">>))/binary,
S/binary, (translate:translate(Lang, <<" is invalid">>))/binary>>,
ErrText = <<(service_translations:do(Lang, <<"Jabber ID ">>))/binary,
S/binary, (service_translations:do(Lang, <<" is invalid">>))/binary>>,
{error, mongoose_xmpp_errors:not_acceptable(Lang, ErrText)};
J ->
{value, J}
Expand All @@ -2872,8 +2872,8 @@ get_affected_jid(Item, Lang, StateData) ->
case find_jids_by_nick(N, StateData) of
[] ->
ErrText
= <<(translate:translate(Lang, <<"Nickname ">>))/binary, N/binary,
(translate:translate(Lang, <<" does not exist in the room">>))/binary>>,
= <<(service_translations:do(Lang, <<"Nickname ">>))/binary, N/binary,
(service_translations:do(Lang, <<" does not exist in the room">>))/binary>>,
{error, mongoose_xmpp_errors:not_acceptable(Lang, ErrText)};
[FirstSessionJid | _RestOfSessions] ->
{value, FirstSessionJid}
Expand Down Expand Up @@ -2945,7 +2945,7 @@ which_property_changed(Item, Lang) ->
{undefined, BAffiliation} ->
case catch binary_to_affiliation(BAffiliation) of
{'EXIT', _} ->
ErrText1 = <<(translate:translate(Lang, <<"Invalid affiliation ">>))/binary,
ErrText1 = <<(service_translations:do(Lang, <<"Invalid affiliation ">>))/binary,
BAffiliation/binary>>,
{error, mongoose_xmpp_errors:not_acceptable(Lang, ErrText1)};
Affiliation ->
Expand All @@ -2954,7 +2954,7 @@ which_property_changed(Item, Lang) ->
{BRole, _} ->
case catch binary_to_role(BRole) of
{'EXIT', _} ->
ErrText1 = <<(translate:translate(Lang, <<"Invalid role ">>))/binary,
ErrText1 = <<(service_translations:do(Lang, <<"Invalid role ">>))/binary,
BRole/binary>>,
{error, mongoose_xmpp_errors:bad_request(Lang, ErrText1)};
Role ->
Expand Down Expand Up @@ -3178,7 +3178,7 @@ process_authorized_iq_owner(From, get, Lang, SubEl, StateData, _StateName) ->
BAffiliation ->
case catch binary_to_affiliation(BAffiliation) of
{'EXIT', _} ->
InvAffT = translate:translate(Lang, <<"Invalid affiliation ">>),
InvAffT = service_translations:do(Lang, <<"Invalid affiliation ">>),
ErrText = <<InvAffT/binary, BAffiliation/binary>>,
{error, mongoose_xmpp_errors:not_acceptable(Lang, ErrText)};
Affiliation ->
Expand Down Expand Up @@ -3294,7 +3294,7 @@ get_default_room_maxusers(RoomState) ->
get_config(Lang, StateData, From) ->
AccessPersistent = access_persistent(StateData),
Config = StateData#state.config,
TitleTxt = translate:translate(Lang, <<"Configuration of room ">>),
TitleTxt = service_translations:do(Lang, <<"Configuration of room ">>),
Title = <<TitleTxt/binary, (jid:to_binary(StateData#state.jid))/binary>>,
Fields =
[stringxfield(<<"Room title">>,
Expand Down Expand Up @@ -3370,18 +3370,18 @@ get_config(Lang, StateData, From) ->
Config#config.logging, Lang)];
_ -> []
end,
InstructionsTxt = translate:translate(
InstructionsTxt = service_translations:do(
Lang, <<"You need an x:data capable client to configure room">>),
{result, [#xmlel{name = <<"instructions">>, children = [#xmlcdata{content = InstructionsTxt}]},
mongoose_data_forms:form(#{title => Title, ns => ?NS_MUC_CONFIG, fields => Fields})],
StateData}.

-spec getmemberlist_field(Lang :: ejabberd:lang()) -> mongoose_data_forms:field().
getmemberlist_field(Lang) ->
LabelTxt = translate:translate(
LabelTxt = service_translations:do(
Lang, <<"Roles and affiliations that may retrieve member list">>),
Values = [<<"moderator">>, <<"participant">>, <<"visitor">>],
Options = [{translate:translate(Lang, Opt), Opt} || Opt <- Values],
Options = [{service_translations:do(Lang, Opt), Opt} || Opt <- Values],
#{type => <<"list-multi">>, label => LabelTxt,
var => <<"muc#roomconfig_getmemberlist">>, values => Values, options => Options}.

Expand All @@ -3394,10 +3394,10 @@ maxusers_field(Lang, StateData) ->
{N, integer_to_binary(N)};
_ -> {0, <<"none">>}
end,
LabelTxt = translate:translate(Lang, <<"Maximum Number of Occupants">>),
LabelTxt = service_translations:do(Lang, <<"Maximum Number of Occupants">>),
Options = if
is_integer(ServiceMaxUsers) -> [];
true -> {translate:translate(Lang, <<"No limit">>), <<"none">>}
true -> {service_translations:do(Lang, <<"No limit">>), <<"none">>}
end ++
[integer_to_binary(N) ||
N <- lists:usort([ServiceMaxUsers, DefaultRoomMaxUsers, MaxUsersRoomInteger |
Expand All @@ -3410,9 +3410,9 @@ whois_field(Lang, Config) ->
Value = if Config#config.anonymous -> <<"moderators">>;
true -> <<"anyone">>
end,
Options = [{translate:translate(Lang, <<"moderators only">>), <<"moderators">>},
{translate:translate(Lang, <<"anyone">>), <<"anyone">>}],
#{type => <<"list-single">>, label => translate:translate(Lang, <<"moderators only">>),
Options = [{service_translations:do(Lang, <<"moderators only">>), <<"moderators">>},
{service_translations:do(Lang, <<"anyone">>), <<"anyone">>}],
#{type => <<"list-single">>, label => service_translations:do(Lang, <<"moderators only">>),
var => <<"muc#roomconfig_whois">>, values => [Value], options => Options}.

-spec set_config([{binary(), [binary()]}], state()) -> any().
Expand Down Expand Up @@ -3792,7 +3792,7 @@ iq_disco_info_extras(Lang, StateData) ->

-spec info_field(binary(), binary(), binary(), ejabberd:lang()) -> mongoose_disco:info_field().
info_field(Label, Var, Value, Lang) ->
#{label => translate:translate(Lang, Label), var => Var, values => [Value]}.
#{label => service_translations:do(Lang, Label), var => Var, values => [Value]}.

-spec process_iq_disco_items(jid:jid(), 'get' | 'set', ejabberd:lang(),
state()) -> {'error', exml:element()}
Expand Down Expand Up @@ -3845,7 +3845,7 @@ get_roomdesc_tail(StateData, Lang) ->
true ->
<<>>;
_ ->
translate:translate(Lang, <<"private, ">>)
service_translations:do(Lang, <<"private, ">>)
end,
Count = count_users(StateData),
CountBin = integer_to_binary(Count),
Expand Down Expand Up @@ -4026,11 +4026,11 @@ invite_body_text(FromJID, Reason, Lang,
password=Password}}) ->
BFromJID = jid:to_binary(FromJID),
BRoomJID = jid:to_binary(RoomJID),
ITranslate = translate:translate(Lang, <<" invites you to the room ">>),
ITranslate = service_translations:do(Lang, <<" invites you to the room ">>),
IMessage = <<BFromJID/binary, ITranslate/binary, BRoomJID/binary>>,
BPassword = case IsProtected of
true ->
PTranslate = translate:translate(Lang, <<"the password is">>),
PTranslate = service_translations:do(Lang, <<"the password is">>),
<<", ", PTranslate/binary, " '", Password/binary, "'">>;
_ ->
<<>>
Expand Down Expand Up @@ -4232,7 +4232,7 @@ route_message(#routed_message{allowed = true, type = <<"error">>, from = From,
true ->
ErrorText
= <<"This participant is kicked from the room because he sent an error message">>,
expulse_participant(Packet, From, StateData, translate:translate(Lang, ErrorText));
expulse_participant(Packet, From, StateData, service_translations:do(Lang, ErrorText));
_ ->
StateData
end;
Expand Down Expand Up @@ -4433,7 +4433,7 @@ route_nick_message(#routed_nick_message{decide = {expulse_sender, _Reason},
"sent an error message to another participant">>,
?LOG_DEBUG(ls(#{what => muc_expulse_sender, text => ErrorText,
user => From#jid.luser, exml_packet => Packet}, StateData)),
expulse_participant(Packet, From, StateData, translate:translate(Lang, ErrorText));
expulse_participant(Packet, From, StateData, service_translations:do(Lang, ErrorText));
route_nick_message(#routed_nick_message{decide = forget_message}, StateData) ->
StateData;
route_nick_message(#routed_nick_message{decide = continue_delivery, allow_pm = true,
Expand Down Expand Up @@ -4537,7 +4537,7 @@ make_voice_approval_form(From, Nick, Role) ->

-spec xfield(binary(), any(), binary(), binary(), ejabberd:lang()) -> mongoose_data_forms:field().
xfield(Type, Label, Var, Val, Lang) ->
#{type => Type, label => translate:translate(Lang, Label), var => Var, values => [Val]}.
#{type => Type, label => service_translations:do(Lang, Label), var => Var, values => [Val]}.

-spec boolxfield(any(), binary(), any(), ejabberd:lang()) -> mongoose_data_forms:field().
boolxfield(Label, Var, Val, Lang) ->
Expand Down Expand Up @@ -4584,7 +4584,7 @@ maybe_add_x_element(#xmlel{children = Children} = Msg) ->
kick_stanza_for_old_protocol(Packet) ->
Lang = exml_query:attr(Packet, <<"xml:lang">>, <<>>),
ErrText = <<"You are not in the room.">>,
ErrText2 = translate:translate(Lang, ErrText),
ErrText2 = service_translations:do(Lang, ErrText),
Response = #xmlel{name = <<"presence">>, attrs = #{<<"type">> => <<"unavailable">>}},
ItemAttrs = #{<<"affiliation">> => <<"none">>, <<"role">> => <<"none">>},
ItemEls = [#xmlel{name = <<"reason">>, children = [#xmlcdata{content = ErrText2}]}],
Expand Down
Loading

0 comments on commit 704a926

Please sign in to comment.