refactor: stop i18n support in hotconf and bridges

frontend team has decided to deal with translations all by themselves
This commit is contained in:
Zaiming (Stone) Shi 2023-04-25 11:40:27 +02:00
parent d398276852
commit 28a68a0ec7
3 changed files with 88 additions and 68 deletions

View File

@ -31,8 +31,9 @@
%% TODO: move to emqx_dashboard when we stop building api schema at build time %% TODO: move to emqx_dashboard when we stop building api schema at build time
-export([ -export([
hotconf_schema_json/1, hotconf_schema_json/0,
bridge_schema_json/1 bridge_schema_json/0,
hocon_schema_to_spec/2
]). ]).
%% for rpc %% for rpc
@ -184,13 +185,13 @@ gen_api_schema_json(Dir, Lang) ->
%% TODO: delete this function when we stop generating this JSON at build time. %% TODO: delete this function when we stop generating this JSON at build time.
gen_api_schema_json_hotconf(Dir, Lang) -> gen_api_schema_json_hotconf(Dir, Lang) ->
File = schema_filename(Dir, "hot-config-schema-", Lang), File = schema_filename(Dir, "hot-config-schema-", Lang),
IoData = hotconf_schema_json(Lang), IoData = hotconf_schema_json(),
ok = write_api_schema_json_file(File, IoData). ok = write_api_schema_json_file(File, IoData).
%% TODO: delete this function when we stop generating this JSON at build time. %% TODO: delete this function when we stop generating this JSON at build time.
gen_api_schema_json_bridge(Dir, Lang) -> gen_api_schema_json_bridge(Dir, Lang) ->
File = schema_filename(Dir, "bridge-api-", Lang), File = schema_filename(Dir, "bridge-api-", Lang),
IoData = bridge_schema_json(Lang), IoData = bridge_schema_json(),
ok = write_api_schema_json_file(File, IoData). ok = write_api_schema_json_file(File, IoData).
%% TODO: delete this function when we stop generating this JSON at build time. %% TODO: delete this function when we stop generating this JSON at build time.
@ -199,14 +200,14 @@ write_api_schema_json_file(File, IoData) ->
file:write_file(File, IoData). file:write_file(File, IoData).
%% TODO: move this function to emqx_dashboard when we stop generating this JSON at build time. %% TODO: move this function to emqx_dashboard when we stop generating this JSON at build time.
hotconf_schema_json(Lang) -> hotconf_schema_json() ->
SchemaInfo = #{title => <<"EMQX Hot Conf API Schema">>, version => <<"0.1.0">>}, SchemaInfo = #{title => <<"EMQX Hot Conf API Schema">>, version => <<"0.1.0">>},
gen_api_schema_json_iodata(emqx_mgmt_api_configs, SchemaInfo, Lang). gen_api_schema_json_iodata(emqx_mgmt_api_configs, SchemaInfo).
%% TODO: move this function to emqx_dashboard when we stop generating this JSON at build time. %% TODO: move this function to emqx_dashboard when we stop generating this JSON at build time.
bridge_schema_json(Lang) -> bridge_schema_json() ->
SchemaInfo = #{title => <<"EMQX Data Bridge API Schema">>, version => <<"0.1.0">>}, SchemaInfo = #{title => <<"EMQX Data Bridge API Schema">>, version => <<"0.1.0">>},
gen_api_schema_json_iodata(emqx_bridge_api, SchemaInfo, Lang). gen_api_schema_json_iodata(emqx_bridge_api, SchemaInfo).
schema_filename(Dir, Prefix, Lang) -> schema_filename(Dir, Prefix, Lang) ->
Filename = Prefix ++ Lang ++ ".json", Filename = Prefix ++ Lang ++ ".json",
@ -270,50 +271,11 @@ gen_example(File, SchemaModule) ->
Example = hocon_schema_example:gen(SchemaModule, Opts), Example = hocon_schema_example:gen(SchemaModule, Opts),
file:write_file(File, Example). file:write_file(File, Example).
%% TODO: move this to emqx_dashboard when we stop generating gen_api_schema_json_iodata(SchemaMod, SchemaInfo) ->
%% this JSON at build time. emqx_dashboard_swagger:gen_api_schema_json_iodata(
gen_api_schema_json_iodata(SchemaMod, SchemaInfo, Lang) ->
{ApiSpec0, Components0} = emqx_dashboard_swagger:spec(
SchemaMod, SchemaMod,
#{ SchemaInfo,
schema_converter => fun hocon_schema_to_spec/2, fun ?MODULE:hocon_schema_to_spec/2
i18n_lang => Lang
}
),
ApiSpec = lists:foldl(
fun({Path, Spec, _, _}, Acc) ->
NewSpec = maps:fold(
fun(Method, #{responses := Responses}, SubAcc) ->
case Responses of
#{
<<"200">> :=
#{
<<"content">> := #{
<<"application/json">> := #{<<"schema">> := Schema}
}
}
} ->
SubAcc#{Method => Schema};
_ ->
SubAcc
end
end,
#{},
Spec
),
Acc#{list_to_atom(Path) => NewSpec}
end,
#{},
ApiSpec0
),
Components = lists:foldl(fun(M, Acc) -> maps:merge(M, Acc) end, #{}, Components0),
emqx_utils_json:encode(
#{
info => SchemaInfo,
paths => ApiSpec,
components => #{schemas => Components}
},
[pretty, force_utf8]
). ).
-define(TO_REF(_N_, _F_), iolist_to_binary([to_bin(_N_), ".", to_bin(_F_)])). -define(TO_REF(_N_, _F_), iolist_to_binary([to_bin(_N_), ".", to_bin(_F_)])).

View File

@ -45,18 +45,11 @@ schema("/schemas/:name") ->
'operationId' => get_schema, 'operationId' => get_schema,
get => #{ get => #{
parameters => [ parameters => [
{name, hoconsc:mk(hoconsc:enum([hotconf, bridges]), #{in => path})}, {name, hoconsc:mk(hoconsc:enum([hotconf, bridges]), #{in => path})}
{lang,
hoconsc:mk(typerefl:string(), #{
in => query,
default => <<"en">>,
desc => <<"The language of the schema.">>
})}
], ],
desc => << desc => <<
"Get the schema JSON of the specified name. " "Get the schema JSON of the specified name. "
"NOTE: you should never need to make use of this API " "NOTE: only intended for EMQX Dashboard."
"unless you are building a multi-lang dashboaard."
>>, >>,
tags => ?TAGS, tags => ?TAGS,
security => [], security => [],
@ -71,14 +64,13 @@ schema("/schemas/:name") ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
get_schema(get, #{ get_schema(get, #{
bindings := #{name := Name}, bindings := #{name := Name}
query_string := #{<<"lang">> := Lang}
}) -> }) ->
{200, gen_schema(Name, iolist_to_binary(Lang))}; {200, gen_schema(Name)};
get_schema(get, _) -> get_schema(get, _) ->
{400, ?BAD_REQUEST, <<"unknown">>}. {400, ?BAD_REQUEST, <<"unknown">>}.
gen_schema(hotconf, Lang) -> gen_schema(hotconf) ->
emqx_conf:hotconf_schema_json(Lang); emqx_conf:hotconf_schema_json();
gen_schema(bridges, Lang) -> gen_schema(bridges) ->
emqx_conf:bridge_schema_json(Lang). emqx_conf:bridge_schema_json().

View File

@ -26,7 +26,11 @@
-export([error_codes/1, error_codes/2]). -export([error_codes/1, error_codes/2]).
-export([file_schema/1]). -export([file_schema/1]).
-export([filter_check_request/2, filter_check_request_and_translate_body/2]). -export([
filter_check_request/2,
filter_check_request_and_translate_body/2,
gen_api_schema_json_iodata/3
]).
-ifdef(TEST). -ifdef(TEST).
-export([ -export([
@ -72,6 +76,8 @@
]) ])
). ).
-define(SPECIAL_LANG_MSGID, <<"$msgid">>).
-define(MAX_ROW_LIMIT, 1000). -define(MAX_ROW_LIMIT, 1000).
-define(DEFAULT_ROW, 100). -define(DEFAULT_ROW, 100).
@ -192,6 +198,50 @@ file_schema(FileName) ->
} }
}. }.
gen_api_schema_json_iodata(SchemaMod, SchemaInfo, Converter) ->
{ApiSpec0, Components0} = emqx_dashboard_swagger:spec(
SchemaMod,
#{
schema_converter => Converter,
i18n_lang => ?SPECIAL_LANG_MSGID
}
),
ApiSpec = lists:foldl(
fun({Path, Spec, _, _}, Acc) ->
NewSpec = maps:fold(
fun(Method, #{responses := Responses}, SubAcc) ->
case Responses of
#{
<<"200">> :=
#{
<<"content">> := #{
<<"application/json">> := #{<<"schema">> := Schema}
}
}
} ->
SubAcc#{Method => Schema};
_ ->
SubAcc
end
end,
#{},
Spec
),
Acc#{list_to_atom(Path) => NewSpec}
end,
#{},
ApiSpec0
),
Components = lists:foldl(fun(M, Acc) -> maps:merge(M, Acc) end, #{}, Components0),
emqx_utils_json:encode(
#{
info => SchemaInfo,
paths => ApiSpec,
components => #{schemas => Components}
},
[pretty, force_utf8]
).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Private functions %% Private functions
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
@ -482,6 +532,14 @@ maybe_add_summary_from_label(Spec, Hocon, Options) ->
get_i18n(Tag, ?DESC(Namespace, Id), Default, Options) -> get_i18n(Tag, ?DESC(Namespace, Id), Default, Options) ->
Lang = get_lang(Options), Lang = get_lang(Options),
case Lang of
?SPECIAL_LANG_MSGID ->
make_msgid(Namespace, Id, Tag);
_ ->
get_i18n_text(Lang, Namespace, Id, Tag, Default)
end.
get_i18n_text(Lang, Namespace, Id, Tag, Default) ->
case emqx_dashboard_desc_cache:lookup(Lang, Namespace, Id, Tag) of case emqx_dashboard_desc_cache:lookup(Lang, Namespace, Id, Tag) of
undefined -> undefined ->
Default; Default;
@ -489,6 +547,14 @@ get_i18n(Tag, ?DESC(Namespace, Id), Default, Options) ->
Text Text
end. end.
%% Format$msgid:Namespace.Id.Tag
%% e.g. $msgid:emqx_schema.key.desc
%% $msgid:emqx_schema.key.label
%% if needed, the consumer of this schema JSON can use this msgid to
%% resolve the text in the i18n database.
make_msgid(Namespace, Id, Tag) ->
iolist_to_binary(["$msgid:", to_bin(Namespace), ".", to_bin(Id), ".", Tag]).
%% So far i18n_lang in options is only used at build time. %% So far i18n_lang in options is only used at build time.
%% At runtime, it's still the global config which controls the language. %% At runtime, it's still the global config which controls the language.
get_lang(#{i18n_lang := Lang}) -> Lang; get_lang(#{i18n_lang := Lang}) -> Lang;