Zhongwen Deng 3 лет назад
Родитель
Сommit
393fbd2bdb

+ 0 - 12
apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf

@@ -1,12 +0,0 @@
-emqx_dashboard_schema {
-  protocol {
-    desc {
-      en: "Protocol Name"
-      zh: "协议名"
-    }
-    label: {
-      en: "Protocol"
-      zh: "协议"
-    }
-  }
-}

+ 190 - 0
apps/emqx_dashboard/i18n/emqx_dashboard_schema.conf

@@ -0,0 +1,190 @@
+emqx_dashboard_schema {
+  listeners {
+    desc {
+      en: """HTTP(s) listeners are identified by their protocol type and are <br>
+used to serve dashboard UI and restful HTTP API.<br>
+Listeners must have a unique combination of port number and IP address.<br>
+For example, an HTTP listener can listen on all configured IP addresses
+on a given port for a machine by specifying the IP address 0.0.0.0.<br>
+Alternatively, the HTTP listener can specify a unique IP address for each listener,
+but use the same port."""
+      zh: """仪表盘监听器设置。"""
+    }
+    label {
+      en: "Listeners"
+      zh: "监听器"
+    }
+  }
+  sample_interval {
+    desc {
+      en: """How often to update metrics displayed in the dashboard.<br/>"
+Note: `sample_interval` should be a divisor of 60."""
+      zh: """更新仪表板中显示的指标的时间间隔。"""
+    }
+  }
+  token_expired_time {
+    desc {
+      en: "JWT token expiration time."
+      zh: "JWT token 过期时间"
+    }
+    label {
+      en: "Token expired time"
+      zh: "JWT 过期时间"
+    }
+  }
+  num_acceptors {
+    desc {
+      en: "Socket acceptor pool size for TCP protocols."
+      zh: "TCP协议的Socket acceptor池大小"
+    }
+    label {
+      en: "Number of acceptors"
+      zh: "Acceptor 数量"
+    }
+  }
+  max_connections {
+    desc {
+      en: "Maximum number of simultaneous connections."
+      zh: "同时处理的最大连接数"
+    }
+    label {
+      en: "Maximum connections"
+      zh: "最大连接数"
+    }
+  }
+  backlog {
+    desc {
+      en: "Defines the maximum length that the queue of pending connections can grow to."
+      zh: "排队等待连接的队列的最大长度"
+    }
+    label {
+      en: "Backlog"
+      zh: "排队长度"
+    }
+  }
+  send_timeout {
+    desc {
+      en: "Send timeout for the socket."
+      zh: "Socket发送超时时间"
+    }
+    label {
+      en: "Send timeout"
+      zh: "发送超时时间"
+    }
+  }
+  inet6 {
+    desc {
+      en: "Enable IPv6 support."
+      zh: "启用IPv6"
+    }
+    label {
+      en: "IPv6"
+      zh: "IPv6"
+    }
+  }
+  ipv6_v6only {
+    desc {
+      en: "Disable IPv4-to-IPv6 mapping for the listener."
+      zh: "禁用IPv4-to-IPv6映射"
+    }
+    label {
+      en: "IPv6 only"
+      zh: "IPv6 only"
+    }
+  }
+  desc_dashboard {
+    desc {
+      en: "Configuration for EMQX dashboard."
+      zh: "EMQX仪表板配置"
+    }
+    label {
+      en: "Dashboard"
+      zh: "仪表板"
+    }
+  }
+  desc_listeners {
+    desc {
+      en: "Configuration for the dashboard listener."
+      zh: "仪表板监听器配置"
+    }
+    label {
+      en: "Listeners"
+      zh: "监听器"
+    }
+  }
+  desc_http {
+    desc {
+      en: "Configuration for the dashboard listener (plaintext)."
+      zh: "仪表板监听器(HTTP)配置"
+    }
+    label {
+      en: "HTTP"
+      zh: "HTTP"
+    }
+  }
+  desc_https {
+    desc {
+      en: "Configuration for the dashboard listener (TLS)."
+      zh: "仪表板监听器(HTTPS)配置"
+    }
+    label {
+      en: "HTTPS"
+      zh: "HTTPS"
+    }
+  }
+  bind {
+    desc {
+      en: "Port without IP(18083) or port with specified IP(127.0.0.1:18083)."
+      zh: "监听的地址与端口"
+    }
+    label {
+      en: "Bind"
+      zh: "绑定端口"
+    }
+  }
+  default_username {
+    desc {
+      en: "The default username of the automatically created dashboard user."
+      zh: "默认的仪表板用户名"
+    }
+    label {
+      en: "Default username"
+      zh: "默认用户名"
+    }
+  }
+  default_password {
+    desc {
+      en: """The initial default password for dashboard 'admin' user.<br>"
+For safety, it should be changed as soon as possible."""
+      zh: """默认的仪表板用户密码<br>
+为了安全,应该尽快修改密码。"""
+    }
+    label {
+      en: "Default password"
+      zh: "默认密码"
+    }
+  }
+  cors {
+    desc {
+      en: """Support Cross-Origin Resource Sharing (CORS).<br>
+Allows a server to indicate any origins (domain, scheme, or port) other than <br
+its own from which a browser should permit loading resources."""
+      zh: """支持跨域资源共享(CORS)<br>
+允许服务器指示任何来源(域名、协议或端口),除了本服务器之外的任何浏览器应允许加载资源。"""
+    }
+    label {
+      en: "CORS"
+      zh: "跨域资源共享"
+    }
+  }
+  i18n_lang {
+    desc {
+      en: "Internationalization language support."
+      zh: "多语言支持"
+    }
+    label {
+      en: "I18n language"
+      zh: "多语言支持"
+    }
+  }
+}

+ 26 - 42
apps/emqx_dashboard/src/emqx_dashboard_schema.erl

@@ -32,16 +32,7 @@ fields("dashboard") ->
         {listeners,
         {listeners,
             sc(
             sc(
                 ref("listeners"),
                 ref("listeners"),
-                #{
-                    desc =>
-                        "HTTP(s) listeners are identified by their protocol type and are\n"
-                        "used to serve dashboard UI and restful HTTP API.<br>\n"
-                        "Listeners must have a unique combination of port number and IP address.<br>\n"
-                        "For example, an HTTP listener can listen on all configured IP addresses\n"
-                        "on a given port for a machine by specifying the IP address 0.0.0.0.<br>\n"
-                        "Alternatively, the HTTP listener can specify a unique IP address for each listener,\n"
-                        "but use the same port."
-                }
+                #{ desc => ?DESC(listeners)}
             )},
             )},
         {default_username, fun default_username/1},
         {default_username, fun default_username/1},
         {default_password, fun default_password/1},
         {default_password, fun default_password/1},
@@ -50,9 +41,8 @@ fields("dashboard") ->
                 emqx_schema:duration_s(),
                 emqx_schema:duration_s(),
                 #{
                 #{
                     default => "10s",
                     default => "10s",
-                    desc =>
-                        "How often to update metrics displayed in the dashboard.<br/>"
-                        "Note: `sample_interval` should be a divisor of 60."
+                    desc => ?DESC(sample_interval),
+                    validator => fun validate_sample_interval/1
                 }
                 }
             )},
             )},
         {token_expired_time,
         {token_expired_time,
@@ -60,7 +50,7 @@ fields("dashboard") ->
                 emqx_schema:duration(),
                 emqx_schema:duration(),
                 #{
                 #{
                     default => "30m",
                     default => "30m",
-                    desc => "JWT token expiration time."
+                    desc => ?DESC(token_expired_time)
                 }
                 }
             )},
             )},
         {cors, fun cors/1},
         {cors, fun cors/1},
@@ -93,7 +83,7 @@ fields("http") ->
                 integer(),
                 integer(),
                 #{
                 #{
                     default => 4,
                     default => 4,
-                    desc => "Socket acceptor pool size for TCP protocols."
+                    desc => ?DESC(num_acceptors)
                 }
                 }
             )},
             )},
         {"max_connections",
         {"max_connections",
@@ -101,7 +91,7 @@ fields("http") ->
                 integer(),
                 integer(),
                 #{
                 #{
                     default => 512,
                     default => 512,
-                    desc => "Maximum number of simultaneous connections."
+                    desc => ?DESC(max_connections)
                 }
                 }
             )},
             )},
         {"backlog",
         {"backlog",
@@ -109,8 +99,7 @@ fields("http") ->
                 integer(),
                 integer(),
                 #{
                 #{
                     default => 1024,
                     default => 1024,
-                    desc =>
-                        "Defines the maximum length that the queue of pending connections can grow to."
+                    desc => ?DESC(backlog)
                 }
                 }
             )},
             )},
         {"send_timeout",
         {"send_timeout",
@@ -118,7 +107,7 @@ fields("http") ->
                 emqx_schema:duration(),
                 emqx_schema:duration(),
                 #{
                 #{
                     default => "5s",
                     default => "5s",
-                    desc => "Send timeout for the socket."
+                    desc => ?DESC(send_timeout)
                 }
                 }
             )},
             )},
         {"inet6",
         {"inet6",
@@ -126,7 +115,7 @@ fields("http") ->
                 boolean(),
                 boolean(),
                 #{
                 #{
                     default => false,
                     default => false,
-                    desc => "Sets up the listener for IPv6."
+                    desc => ?DESC(inet6)
                 }
                 }
             )},
             )},
         {"ipv6_v6only",
         {"ipv6_v6only",
@@ -134,7 +123,7 @@ fields("http") ->
                 boolean(),
                 boolean(),
                 #{
                 #{
                     default => false,
                     default => false,
-                    desc => "Disable IPv4-to-IPv6 mapping for the listener."
+                    desc => ?DESC(ipv6_v6only)
                 }
                 }
             )}
             )}
     ];
     ];
@@ -145,27 +134,22 @@ fields("https") ->
             emqx_schema:server_ssl_opts_schema(#{}, true)
             emqx_schema:server_ssl_opts_schema(#{}, true)
         ).
         ).
 
 
-desc("dashboard") ->
-    "Configuration for EMQX dashboard.";
-desc("listeners") ->
-    "Configuration for the dashboard listener.";
-desc("http") ->
-    "Configuration for the dashboard listener (plaintext).";
-desc("https") ->
-    "Configuration for the dashboard listener (TLS).";
-desc(_) ->
-    undefined.
+desc("dashboard") -> ?DESC(desc_dashboard);
+desc("listeners") -> ?DESC(desc_listeners);
+desc("http") -> ?DESC(desc_http);
+desc("https") -> ?DESC(desc_https);
+desc(_) -> undefined.
 
 
 bind(type) -> hoconsc:union([non_neg_integer(), emqx_schema:ip_port()]);
 bind(type) -> hoconsc:union([non_neg_integer(), emqx_schema:ip_port()]);
 bind(default) -> 18083;
 bind(default) -> 18083;
 bind(required) -> true;
 bind(required) -> true;
-bind(desc) -> "Port without IP(18083) or port with specified IP(127.0.0.1:18083).";
+bind(desc) -> ?DESC(bind);
 bind(_) -> undefined.
 bind(_) -> undefined.
 
 
 default_username(type) -> string();
 default_username(type) -> string();
 default_username(default) -> "admin";
 default_username(default) -> "admin";
 default_username(required) -> true;
 default_username(required) -> true;
-default_username(desc) -> "The default username of the automatically created dashboard user.";
+default_username(desc) ->  ?DESC(default_username);
 default_username('readOnly') -> true;
 default_username('readOnly') -> true;
 default_username(_) -> undefined.
 default_username(_) -> undefined.
 
 
@@ -180,11 +164,7 @@ default_password('readOnly') ->
 default_password(sensitive) ->
 default_password(sensitive) ->
     true;
     true;
 default_password(desc) ->
 default_password(desc) ->
-    ""
-    "\n"
-    "The initial default password for dashboard 'admin' user.\n"
-    "For safety, it should be changed as soon as possible."
-    "";
+    ?DESC(default_password);
 default_password(_) ->
 default_password(_) ->
     undefined.
     undefined.
 
 
@@ -195,18 +175,22 @@ cors(default) ->
 cors(required) ->
 cors(required) ->
     false;
     false;
 cors(desc) ->
 cors(desc) ->
-    "Support Cross-Origin Resource Sharing (CORS).\n"
-    "Allows a server to indicate any origins (domain, scheme, or port) other than\n"
-    "its own from which a browser should permit loading resources.";
+    ?DESC(cors);
 cors(_) ->
 cors(_) ->
     undefined.
     undefined.
 
 
 i18n_lang(type) -> ?ENUM([en, zh]);
 i18n_lang(type) -> ?ENUM([en, zh]);
 i18n_lang(default) -> en;
 i18n_lang(default) -> en;
 i18n_lang('readOnly') -> true;
 i18n_lang('readOnly') -> true;
-i18n_lang(desc) -> "Internationalization language support.";
+i18n_lang(desc) -> ?DESC(i18n_lang);
 i18n_lang(_) -> undefined.
 i18n_lang(_) -> undefined.
 
 
+validate_sample_interval(Second) ->
+    case Second >= 1 andalso Second =< 60 andalso (60 rem Second =:= 0) of
+        true -> ok;
+        false -> error({"Sample interval must be between 1 and 60 and be a divisor of 60.", Second})
+    end.
+
 sc(Type, Meta) -> hoconsc:mk(Type, Meta).
 sc(Type, Meta) -> hoconsc:mk(Type, Meta).
 
 
 ref(Field) -> hoconsc:ref(?MODULE, Field).
 ref(Field) -> hoconsc:ref(?MODULE, Field).

+ 1 - 1
scripts/merge-i18n.escript

@@ -3,7 +3,7 @@
 -mode(compile).
 -mode(compile).
 
 
 main(_) ->
 main(_) ->
-    {ok, BaseConf} = file:read_file("apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf"),
+    {ok, BaseConf} = file:read_file("apps/emqx_dashboard/i18n/emqx_dashboard_schema.conf"),
 
 
     Cfgs = get_all_cfgs("apps/"),
     Cfgs = get_all_cfgs("apps/"),
     Conf = [merge(BaseConf, Cfgs),
     Conf = [merge(BaseConf, Cfgs),