Просмотр исходного кода

Merge pull request #7700 from HJianBo/emqx-schema-i18n-mqtt

docs(emqx): i18n support for emqx_schema.erl
JianBo He 3 лет назад
Родитель
Сommit
0c27613ce4
2 измененных файлов с 460 добавлено и 123 удалено
  1. 413 0
      apps/emqx/i18n/emqx_schema_i18n.conf
  2. 47 123
      apps/emqx/src/emqx_schema.erl

+ 413 - 0
apps/emqx/i18n/emqx_schema_i18n.conf

@@ -0,0 +1,413 @@
+emqx_schema {
+
+    zones {
+        desc {
+            en: """A zone is a set of configs grouped by the zone <code>name</code>.
+For flexible configuration mapping, the <code>name</code> can be set to a listener's <code>zone</code> config.
+NOTE: A built-in zone named <code>default</code> is auto created and can not be deleted.
+"""
+            zh: """<code>zone</code> 是按<code>name</code> 分组的一组配置。
+对于灵活的配置映射,可以将 <code>name</code> 设置为侦听器的 <code>zone</code> 配置。
+注:名为 <code>default</code> 的内置区域是自动创建的,无法删除。"""
+        }
+    }
+
+    mqtt {
+        desc {
+            en: """Global MQTT configuration.
+The configs here work as default values which can be overridden in <code>zone</code> configs
+"""
+            zh: """全局的 MQTT 配置项。
+mqtt 下所有的配置作为全局的默认值存在,它可以被 <code>zone</code> 中的配置覆盖。"""
+        }
+    }
+
+    mqtt_idle_timeout {
+        desc {
+            en: """Close TCP connections from the clients that have not sent MQTT CONNECT message within this interval."""
+            zh: """关闭在此时间间隔内未发送 MQTT CONNECT 消息的客户端的 TCP 连接。"""
+        }
+    }
+
+    mqtt_max_packet_size {
+        desc {
+            en: """Maximum MQTT packet size allowed."""
+            zh: """允许的最大 MQTT 报文大小。"""
+        }
+    }
+
+    mqtt_max_clientid_len {
+        desc {
+            en: """"Maximum allowed length of MQTT clientId."""
+            zh: """允许的最大 MQTT Client ID 长度"""
+        }
+    }
+
+    mqtt_max_topic_levels {
+        desc {
+            en: """Maximum topic levels allowed."""
+            zh: """允许的 Topic 最大层级数"""
+        }
+    }
+
+    mqtt_max_qos_allowed {
+        desc {
+            en: """Maximum QoS allowed."""
+            zh: """允许的最大 QoS 等级。"""
+        }
+    }
+
+    mqtt_max_topic_alias {
+        desc {
+            en: """Maximum Topic Alias, 0 means no topic alias supported."""
+            zh: """允许的最大主题别名数,0 表示不支持主题别名。"""
+        }
+    }
+
+    mqtt_retain_available {
+        desc {
+            en: """Support MQTT retained messages."""
+            zh: """是否支持 retained 消息。"""
+        }
+    }
+
+    mqtt_wildcard_subscription {
+        desc {
+            en: """Support MQTT Wildcard Subscriptions."""
+            zh: """是否支持主题的通配符订阅。"""
+        }
+    }
+
+    mqtt_shared_subscription {
+        desc {
+            en: """Support MQTT Shared Subscriptions."""
+            zh: """是否支持 MQTT 共享订阅"""
+        }
+    }
+
+    mqtt_ignore_loop_deliver {
+        desc {
+            en: """Ignore loop delivery of messages for MQTT v3.1.1/v3.1.0."""
+            zh: """是否为 MQTT v3.1.1/v3.1.0 客户端忽略接收自己发布出消息"""
+        }
+    }
+
+    mqtt_strict_mode {
+        desc {
+            en: """Parse MQTT messages in strict mode.
+When set to true, invalid utf8 strings in for example client ID, topic name, etc. will cause the client to be disconnected"""
+            zh: """是否以严格模式解析 MQTT 消息。
+当设置为 true 时,例如客户端 ID、主题名称等中的无效 utf8 字符串将导致客户端断开连接。"""
+        }
+    }
+
+    mqtt_response_information {
+        desc {
+            en: """Specify the response information returned to the client. This feature is disabled if is set to \"\"."""
+            zh: """指定返回给客户端的响应信息。如果设置为 \"\",则禁用此功能。"""
+        }
+    }
+
+    mqtt_server_keepalive {
+        desc {
+            en: """'Server Keep Alive' of MQTT 5.0.
+If the server returns a 'Server Keep Alive' in the CONNACK packet, the client MUST use that value instead of the value it sent as the 'Keep Alive'."""
+            zh: """MQTT 5.0 的 'Server Keep Alive' 属性。
+如果服务器在 CONNACK 数据包中返回'Server Keep Alive',则客户端必须使用该值作为实际的 'Keep Alive' 值。"""
+        }
+    }
+
+    mqtt_keepalive_backoff {
+        desc {
+            en: """The backoff for MQTT keepalive timeout. The broker will close the connection after idling for 'Keepalive * backoff * 2'."""
+            zh: """Broker 判定客户端 Keep Alive 超时的退避乘数。EMQX 将在'Keepalive * backoff * 2' 空闲后关闭连接。"""
+        }
+    }
+
+    mqtt_max_subscriptions {
+        desc {
+            en: """Maximum number of subscriptions allowed."""
+            zh: """允许的每个客户端最大订阅数"""
+        }
+    }
+
+    mqtt_upgrade_qos {
+        desc {
+            en: """Force upgrade of QoS level according to subscription."""
+            zh: """投递消息时,是否根据订阅主题时的 QoS 等级来强制提升派发的消息的 QoS 等级。"""
+        }
+    }
+
+    mqtt_max_inflight {
+        desc {
+            en: """Maximum size of the Inflight Window storing QoS1/2 messages delivered but un-acked."""
+            zh: """飞行窗口的最大值。"""
+        }
+    }
+
+    mqtt_retry_interval {
+        desc {
+            en: """Retry interval for QoS1/2 message delivering."""
+            zh: """QoS1/2 消息的重新投递间隔。"""
+        }
+    }
+
+    mqtt_max_awaiting_rel {
+        desc {
+            en: """Maximum QoS2 packets (Client -> Broker) awaiting PUBREL."""
+            zh: """PUBREL (Client -> Broker) 最大等待队列长度。"""
+        }
+    }
+
+    mqtt_await_rel_timeout {
+        desc {
+            en: """The QoS2 messages (Client -> Broker) will be dropped if awaiting PUBREL timeout."""
+            zh: """PUBREL (Client -> Broker) 最大等待时间,超时则会被丢弃。"""
+        }
+    }
+
+    mqtt_session_expiry_interval {
+        desc {
+            en: """Default session expiry interval for MQTT V3.1.1 connections."""
+            zh: """Session 默认超时时间。"""
+        }
+    }
+
+    mqtt_max_mqueue_len {
+        desc {
+            en: """Maximum queue length. Enqueued messages when persistent client disconnected, or inflight window is full."""
+            zh: """消息队列最大长度。持久客户端断开连接或飞行窗口已满时排队的消息长度。"""
+        }
+    }
+
+    mqtt_mqueue_priorities {
+        desc {
+            en: """Topic priorities. Priority number [1-255]
+There's no priority table by default, hence all messages are treated equal.
+
+**NOTE**: Comma and equal signs are not allowed for priority topic names.
+**NOTE**: Messages for topics not in the priority table are treated as either highest or lowest priority depending on the configured value for <code>mqtt.mqueue_default_priority</code>.
+
+**Examples**:
+To configure <code>\"topic/1\" > \"topic/2\"</code>:
+<code>mqueue_priorities: {\"topic/1\": 10, \"topic/2\": 8}</code>
+"""
+            zh: """主题优先级。取值范围 [1-255]
+默认优先级表为空,即所有的主题优先级相同。
+
+注:优先主题名称中不支持使用逗号和等号。
+注:不在此列表中的主题,被视为最高/最低优先级,这取决于<code>mqtt.mqueue_default_priority</code> 的配置
+
+示例:
+配置 <code>\"topic/1\" > \"topic/2\"</code>:
+<code>mqueue_priorities: {\"topic/1\": 10, \"topic/2\": 8}</code>
+"""
+        }
+    }
+
+    mqtt_mqueue_default_priority {
+        desc {
+            en: """Default to the highest priority for topics not matching priority table."""
+            zh: """主题默认的优先级,不在 <code>mqtt.mqueue_priorities</code> 中的主题将会使用该优先级。"""
+        }
+    }
+
+    mqtt_mqueue_store_qos0 {
+        desc {
+            en: """Support enqueue QoS0 messages."""
+            zh: """消息队列是否存储 QoS0 消息。"""
+        }
+    }
+
+    mqtt_use_username_as_clientid {
+        desc {
+            en: """Replace client ID with the username."""
+            zh: """是否使用 Client ID 替换 Username。"""
+        }
+    }
+
+    mqtt_peer_cert_as_username {
+        desc {
+            en: """Use the CN, DN or CRT field from the client certificate as a username.
+Only works for the TLS connection."""
+            zh: """使用客户端证书中的 CN, DN 字段或整个证书来作为客户端用户名。"""
+        }
+    }
+
+    mqtt_peer_cert_as_clientid {
+        desc {
+            en: """Use the CN, DN or CRT field from the client certificate as a clientid.
+Only works for the TLS connection."""
+            zh: """使用客户端证书中的 CN, DN 字段或整个证书来作为客户端 ID。"""
+        }
+    }
+
+    broker {
+        desc {
+            en: """"Message broker options."""
+            zh: """Broker 相关配置项。"""
+        }
+    }
+
+    broker_enable_session_registry {
+        desc {
+            en: """Enable session registry"""
+            zh: """是否启用 Session Registry"""
+        }
+    }
+
+    broker_session_locking_strategy {
+        desc {
+            en: """Session locking strategy in a cluster.
+  - `local`: only lock the session on the current node
+  - `one`: select only one remote node to lock the session
+  - `quorum`: select some nodes to lock the session
+  - `all`: lock the session on all the nodes in the cluster
+"""
+
+            zh: """Session 在集群中的锁策略。
+  - `loca`: 仅锁本节点的 Session
+  - `one`: 任选一个其它节点加锁
+  - `quorum`: 选择集群中半数以上的节点加锁
+  - `all`: 选择所有节点加锁
+"""
+        }
+    }
+
+    broker_shared_subscription_strategy {
+        desc {
+            en: """Dispatch strategy for shared subscription.
+  - `random`: dispatch the message to a random selected subscriber
+  - `round_robin`: select the subscribers in a round-robin manner
+  - `sticky`: always use the last selected subscriber to dispatch, until the subscriber disconnects.
+  - `hash`: select the subscribers by the hash of `clientIds`
+"""
+
+            zh: """共享订阅消息派发策略。
+  - `random`: 随机挑选一个共享订阅者派发
+  - `round_robin`: 使用 round-robin 策略派发
+  - `sticky`: 总是使用上次选中的订阅者派发,直到它断开连接
+  - `hash`: 使用发送者的 Client ID 进行 Hash 来选择订阅者
+"""
+        }
+    }
+
+    broker_shared_dispatch_ack_enabled {
+        desc {
+            en: """Enable/disable shared dispatch acknowledgement for QoS1 and QoS2 messages.
+This should allow messages to be dispatched to a different subscriber in the group in case the picked (based on `shared_subscription_strategy`) subscriber is offline.
+"""
+
+            zh: """启用/禁用 QoS1 和 QoS2 消息的共享派发确认。
+开启后,允许将消息从未及时回复 ACK 的订阅者 (例如,客户端离线)重新派发给另外一个订阅者。
+"""
+        }
+    }
+
+    broker_route_batch_clean {
+        desc {
+            en: """Enable batch clean for deleted routes."""
+            zh: """是否开启批量清除路由。"""
+        }
+    }
+
+    broker_perf_route_lock_type {
+        desc {
+            en: """Performance tuning for subscribing/unsubscribing a wildcard topic.
+Change this parameter only when there are many wildcard topics.
+
+NOTE: when changing from/to `global` lock, it requires all nodes in the cluster to be stopped before the change.
+  - `key`: mnesia transactional updates with per-key locks. Recommended for a single-node setup.
+  - `tab`: mnesia transactional updates with table lock. Recommended for a cluster setup.
+  - `global`: updates are protected with a global lock. Recommended for large clusters.
+"""
+            zh: """通配主题订阅/取消订阅性能调优。
+建议仅当通配符主题较多时才更改此参数。
+
+注:当从/更改为 `global` 锁时,它要求集群中的所有节点在更改之前停止。
+  - `key`: 为 Mnesia 事务涉及到的每个 key 上锁,建议单节点时使用。
+  - `tab`: 为 Mnesia 事务涉及到的表上锁,建议在集群中使用。
+  - `global`: 所以更新操作都被全局的锁保护,仅建议在超大规模集群中使用。
+"""
+        }
+    }
+
+    broker_perf_trie_compaction {
+        desc {
+            en: """Enable trie path compaction.
+Enabling it significantly improves wildcard topic subscribe rate, if wildcard topics have unique prefixes like: 'sensor/{{id}}/+/', where ID is unique per subscriber.
+Topic match performance (when publishing) may degrade if messages are mostly published to topics with large number of levels.
+
+NOTE: This is a cluster-wide configuration. It requires all nodes to be stopped before changing it.
+"""
+            zh: """是否开启主题表压缩存储。
+启用它会显着提高通配符主题订阅率,如果通配符主题具有唯一前缀,例如:'sensor/{{id}}/+/',其中每个订阅者的 ID 是唯一的。
+如果消息主要发布到具有大量级别的主题,则主题匹配性能(发布时)可能会降低。
+
+注意:这是一个集群范围的配置。 它要求在更改之前停止所有节点。
+"""
+        }
+    }
+
+    sys_topics {
+        desc {
+            en: """System topics configuration."""
+            zh: """系统主题配置。"""
+        }
+    }
+
+    sys_msg_interval {
+        desc {
+            en: """Time interval of publishing `$SYS` messages."""
+            zh: """发送 `$SYS` 主题的间隔时间。"""
+        }
+    }
+
+    sys_heartbeat_interval {
+        desc {
+            en: """Time interval for publishing following heartbeat messages:
+  - `$SYS/brokers/<node>/uptime`
+  - `$SYS/brokers/<node>/datetime`
+"""
+            zh: """发送心跳系统消息的间隔时间,它包括:
+  - `$SYS/brokers/<node>/uptime`
+  - `$SYS/brokers/<node>/datetime`
+"""
+        }
+    }
+
+    sys_event_messages {
+        desc {
+            en: """Client events messages"""
+            zh: """客户端事件消息"""
+        }
+    }
+
+    sys_event_client_connected {
+        desc {
+            en: """Enable to publish client connected event messages"""
+            zh: """是否开启客户端已连接事件消息。"""
+        }
+    }
+
+    sys_event_client_disconnected {
+        desc {
+            en: """Enable to publish client disconnected event messages."""
+            zh: """是否开启客户端已断开连接事件消息。"""
+        }
+    }
+
+    sys_event_client_subscribed {
+        desc {
+            en: """Enable to publish event message that client subscribed a topic successfully."""
+            zh: """是否开启客户端已成功订阅主题事件消息。"""
+        }
+    }
+
+    sys_event_client_unsubscribed {
+        desc {
+            en: """Enable to publish event message that client unsubscribed a topic successfully."""
+            zh: """是否开启客户端已成功取消订阅主题事件消息。"""
+        }
+    }
+}

+ 47 - 123
apps/emqx/src/emqx_schema.erl

@@ -26,6 +26,7 @@
 -include("emqx_authentication.hrl").
 -include("emqx_access_control.hrl").
 -include_lib("typerefl/include/types.hrl").
+-include_lib("hocon/include/hoconsc.hrl").
 
 -type duration() :: integer().
 -type duration_s() :: integer().
@@ -122,19 +123,12 @@ roots(high) ->
         {"zones",
             sc(
                 map("name", ref("zone")),
-                #{
-                    desc =>
-                        "A zone is a set of configs grouped by the zone <code>name</code>.<br>\n"
-                        "For flexible configuration mapping, the <code>name</code>\n"
-                        "can be set to a listener's <code>zone</code> config.<br>\n"
-                        "NOTE: A built-in zone named <code>default</code> is auto created\n"
-                        "and can not be deleted."
-                }
+                #{}
             )},
         {"mqtt",
             sc(
                 ref("mqtt"),
-                #{}
+                #{ desc => ?DESC(mqtt)}
             )},
         {?EMQX_AUTHENTICATION_CONFIG_ROOT_NAME,
             authentication(
@@ -171,12 +165,12 @@ roots(medium) ->
         {"broker",
             sc(
                 ref("broker"),
-                #{}
+                #{desc => ?DESC(broker)}
             )},
         {"sys_topics",
             sc(
                 ref("sys_topics"),
-                #{}
+                #{desc => ?DESC(sys_topics)}
             )},
         {"rate_limit",
             sc(
@@ -374,9 +368,7 @@ fields("mqtt") ->
                 hoconsc:union([infinity, duration()]),
                 #{
                     default => "15s",
-                    desc =>
-                        "Close TCP connections from the clients that have not sent MQTT CONNECT\n"
-                        "message within this interval."
+                    desc => ?DESC(mqtt_idle_timeout)
                 }
             )},
         {"max_packet_size",
@@ -384,7 +376,7 @@ fields("mqtt") ->
                 bytesize(),
                 #{
                     default => "1MB",
-                    desc => "Maximum MQTT packet size allowed."
+                    desc => ?DESC(mqtt_max_packet_size)
                 }
             )},
         {"max_clientid_len",
@@ -392,7 +384,7 @@ fields("mqtt") ->
                 range(23, 65535),
                 #{
                     default => 65535,
-                    desc => "Maximum allowed length of MQTT clientId."
+                    desc => ?DESC(mqtt_max_clientid_len)
                 }
             )},
         {"max_topic_levels",
@@ -400,7 +392,7 @@ fields("mqtt") ->
                 range(1, 65535),
                 #{
                     default => 65535,
-                    desc => "Maximum topic levels allowed."
+                    desc => ?DESC(mqtt_max_topic_levels)
                 }
             )},
         {"max_qos_allowed",
@@ -408,7 +400,7 @@ fields("mqtt") ->
                 qos(),
                 #{
                     default => 2,
-                    desc => "Maximum QoS allowed."
+                    desc => ?DESC(mqtt_max_qos_allowed)
                 }
             )},
         {"max_topic_alias",
@@ -416,7 +408,7 @@ fields("mqtt") ->
                 range(0, 65535),
                 #{
                     default => 65535,
-                    desc => "Maximum Topic Alias, 0 means no topic alias supported."
+                    desc => ?DESC(mqtt_max_topic_alias)
                 }
             )},
         {"retain_available",
@@ -424,7 +416,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Support MQTT retained messages."
+                    desc => ?DESC(mqtt_retain_available)
                 }
             )},
         {"wildcard_subscription",
@@ -432,7 +424,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Support MQTT Wildcard Subscriptions."
+                    desc => ?DESC(mqtt_wildcard_subscription)
                 }
             )},
         {"shared_subscription",
@@ -440,7 +432,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Support MQTT Shared Subscriptions."
+                    desc => ?DESC(mqtt_shared_subscription)
                 }
             )},
         {"ignore_loop_deliver",
@@ -448,7 +440,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => false,
-                    desc => "Ignore loop delivery of messages for MQTT v3.1.1."
+                    desc => ?DESC(mqtt_ignore_loop_deliver)
                 }
             )},
         {"strict_mode",
@@ -456,11 +448,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => false,
-                    desc =>
-                        "Parse MQTT messages in strict mode. "
-                        "When set to true, invalid utf8 strings in for example "
-                        "client ID, topic name, etc. will cause the client to be "
-                        "disconnected"
+                    desc => ?DESC(mqtt_strict_mode)
                 }
             )},
         {"response_information",
@@ -468,9 +456,7 @@ fields("mqtt") ->
                 string(),
                 #{
                     default => "",
-                    desc =>
-                        "Specify the response information returned to the client\n"
-                        "This feature is disabled if is set to \"\"."
+                    desc => ?DESC(mqtt_response_information)
                 }
             )},
         {"server_keepalive",
@@ -478,10 +464,7 @@ fields("mqtt") ->
                 hoconsc:union([integer(), disabled]),
                 #{
                     default => disabled,
-                    desc =>
-                        "'Server Keep Alive' of MQTT 5.0.\n"
-                        "If the server returns a 'Server Keep Alive' in the CONNACK packet,\n"
-                        "the client MUST use that value instead of the value it sent as the 'Keep Alive'."
+                    desc => ?DESC(mqtt_server_keepalive)
                 }
             )},
         {"keepalive_backoff",
@@ -489,9 +472,7 @@ fields("mqtt") ->
                 float(),
                 #{
                     default => 0.75,
-                    desc =>
-                        "The backoff for MQTT keepalive timeout. The broker will close the connection\n"
-                        "after idling for 'Keepalive * backoff * 2'."
+                    desc => ?DESC(mqtt_keepalive_backoff)
                 }
             )},
         {"max_subscriptions",
@@ -499,7 +480,7 @@ fields("mqtt") ->
                 hoconsc:union([range(1, inf), infinity]),
                 #{
                     default => infinity,
-                    desc => "Maximum number of subscriptions allowed."
+                    desc => ?DESC(mqtt_max_subscriptions)
                 }
             )},
         {"upgrade_qos",
@@ -507,7 +488,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => false,
-                    desc => "Force upgrade of QoS level according to subscription."
+                    desc => ?DESC(mqtt_upgrade_qos)
                 }
             )},
         {"max_inflight",
@@ -515,9 +496,7 @@ fields("mqtt") ->
                 range(1, 65535),
                 #{
                     default => 32,
-                    desc =>
-                        "Maximum size of the Inflight Window storing QoS1/2 "
-                        "messages delivered but un-acked."
+                    desc => ?DESC(mqtt_max_inflight)
                 }
             )},
         {"retry_interval",
@@ -525,7 +504,7 @@ fields("mqtt") ->
                 duration(),
                 #{
                     default => "30s",
-                    desc => "Retry interval for QoS1/2 message delivering."
+                    desc => ?DESC(mqtt_retry_interval)
                 }
             )},
         {"max_awaiting_rel",
@@ -533,7 +512,7 @@ fields("mqtt") ->
                 hoconsc:union([integer(), infinity]),
                 #{
                     default => 100,
-                    desc => "Maximum QoS2 packets (Client -> Broker) awaiting PUBREL."
+                    desc => ?DESC(mqtt_max_awaiting_rel)
                 }
             )},
         {"await_rel_timeout",
@@ -541,9 +520,7 @@ fields("mqtt") ->
                 duration(),
                 #{
                     default => "300s",
-                    desc =>
-                        "The QoS2 messages (Client -> Broker) will be dropped "
-                        "if awaiting PUBREL timeout."
+                    desc => ?DESC(mqtt_await_rel_timeout)
                 }
             )},
         {"session_expiry_interval",
@@ -551,7 +528,7 @@ fields("mqtt") ->
                 duration(),
                 #{
                     default => "2h",
-                    desc => "Default session expiry interval for MQTT V3.1.1 connections."
+                    desc => ?DESC(mqtt_session_expiry_interval)
                 }
             )},
         {"max_mqueue_len",
@@ -559,9 +536,7 @@ fields("mqtt") ->
                 hoconsc:union([non_neg_integer(), infinity]),
                 #{
                     default => 1000,
-                    desc =>
-                        "Maximum queue length. Enqueued messages when persistent client disconnected,\n"
-                        "or inflight window is full."
+                    desc => ?DESC(mqtt_max_mqueue_len)
                 }
             )},
         {"mqueue_priorities",
@@ -569,19 +544,7 @@ fields("mqtt") ->
                 hoconsc:union([map(), disabled]),
                 #{
                     default => disabled,
-                    desc =>
-                        "Topic priorities.<br>\n"
-                        "There's no priority table by default, hence all messages are treated equal.<br>\n"
-                        "Priority number [1-255]<br>\n"
-                        "\n"
-                        "**NOTE**: Comma and equal signs are not allowed for priority topic names.<br>\n"
-                        "**NOTE**: Messages for topics not in the priority table are treated as\n"
-                        "either highest or lowest priority depending on the configured value for\n"
-                        "<code>mqtt.mqueue_default_priority</code>.\n"
-                        "<br><br>\n"
-                        "**Examples**:\n"
-                        "To configure <code>\"topic/1\" > \"topic/2\"</code>:<br/>\n"
-                        "<code>mqueue_priorities: {\"topic/1\": 10, \"topic/2\": 8}</code>"
+                    desc => ?DESC(mqtt_mqueue_priorities)
                 }
             )},
         {"mqueue_default_priority",
@@ -589,8 +552,7 @@ fields("mqtt") ->
                 hoconsc:enum([highest, lowest]),
                 #{
                     default => lowest,
-                    desc =>
-                        "Default to the highest priority for topics not matching priority table."
+                    desc => ?DESC(mqtt_mqueue_default_priority)
                 }
             )},
         {"mqueue_store_qos0",
@@ -598,7 +560,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Support enqueue QoS0 messages."
+                    desc => ?DESC(mqtt_mqueue_store_qos0)
                 }
             )},
         {"use_username_as_clientid",
@@ -606,7 +568,7 @@ fields("mqtt") ->
                 boolean(),
                 #{
                     default => false,
-                    desc => "Replace client ID with the username."
+                    desc => ?DESC(mqtt_use_username_as_clientid)
                 }
             )},
         {"peer_cert_as_username",
@@ -614,9 +576,7 @@ fields("mqtt") ->
                 hoconsc:enum([disabled, cn, dn, crt, pem, md5]),
                 #{
                     default => disabled,
-                    desc =>
-                        "Use the CN, DN or CRT field from the client certificate as a username.\n"
-                        "Only works for the TLS connection."
+                    desc => ?DESC(mqtt_peer_cert_as_username)
                 }
             )},
         {"peer_cert_as_clientid",
@@ -624,9 +584,7 @@ fields("mqtt") ->
                 hoconsc:enum([disabled, cn, dn, crt, pem, md5]),
                 #{
                     default => disabled,
-                    desc =>
-                        "Use the CN, DN or CRT field from the client certificate as a clientid.\n"
-                        "Only works for the TLS connection."
+                    desc => ?DESC(mqtt_peer_cert_as_clientid)
                 }
             )}
     ];
@@ -1229,7 +1187,7 @@ fields("broker") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Enable session registry"
+                    desc => ?DESC(broker_enable_session_registry)
                 }
             )},
         {"session_locking_strategy",
@@ -1237,12 +1195,7 @@ fields("broker") ->
                 hoconsc:enum([local, leader, quorum, all]),
                 #{
                     default => quorum,
-                    desc =>
-                        "Session locking strategy in a cluster.<br/>\n"
-                        " - `local`: only lock the session on the current node\n"
-                        " - `one`: select only one remote node to lock the session\n"
-                        " - `quorum`: select some nodes to lock the session\n"
-                        " - `all`: lock the session on all the nodes in the cluster"
+                    desc => ?DESC(broker_session_locking_strategy)
                 }
             )},
         {"shared_subscription_strategy",
@@ -1250,13 +1203,7 @@ fields("broker") ->
                 hoconsc:enum([random, round_robin, sticky, hash_topic, hash_clientid]),
                 #{
                     default => round_robin,
-                    desc =>
-                        "Dispatch strategy for shared subscription.<br/>\n"
-                        " - `random`: dispatch the message to a random selected subscriber\n"
-                        " - `round_robin`: select the subscribers in a round-robin manner\n"
-                        " - `sticky`: always use the last selected subscriber to dispatch,\n"
-                        "   until the subscriber disconnects.\n"
-                        " - `hash`: select the subscribers by the hash of `clientIds`"
+                    desc => ?DESC(broker_shared_subscription_strategy)
                 }
             )},
         {"shared_dispatch_ack_enabled",
@@ -1264,11 +1211,7 @@ fields("broker") ->
                 boolean(),
                 #{
                     default => false,
-                    desc =>
-                        "Enable/disable shared dispatch acknowledgement for QoS1 and QoS2 messages.<br/>\n"
-                        " This should allow messages to be dispatched to a different subscriber in\n"
-                        " the group in case the picked (based on `shared_subscription_strategy`) subscriber\n"
-                        " is offline."
+                    desc => ?DESC(broker_shared_dispatch_ack_enabled)
                 }
             )},
         {"route_batch_clean",
@@ -1276,7 +1219,7 @@ fields("broker") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Enable batch clean for deleted routes."
+                    desc => ?DESC(broker_route_batch_clean)
                 }
             )},
         {"perf",
@@ -1292,15 +1235,7 @@ fields("broker_perf") ->
                 hoconsc:enum([key, tab, global]),
                 #{
                     default => key,
-                    desc =>
-                        "Performance tuning for subscribing/unsubscribing a wildcard topic.<br/>\n"
-                        "Change this parameter only when there are many wildcard topics.<br/>\n"
-                        "NOTE: when changing from/to `global` lock, it requires all\n"
-                        "nodes in the cluster to be stopped before the change.\n\n"
-                        " - `key`: mnesia transactional updates with per-key locks. "
-                        "Recommended for a single-node setup.\n"
-                        " - `tab`: mnesia transactional updates with table lock. Recommended for a cluster setup.\n"
-                        " - `global`: updates are protected with a global lock. Recommended for large clusters."
+                    desc => ?DESC(broker_perf_route_lock_type)
                 }
             )},
         {"trie_compaction",
@@ -1308,15 +1243,7 @@ fields("broker_perf") ->
                 boolean(),
                 #{
                     default => true,
-                    desc =>
-                        "Enable trie path compaction.<br/>\n"
-                        "Enabling it significantly improves wildcard topic subscribe\n"
-                        "rate, if wildcard topics have unique prefixes like:\n"
-                        "'sensor/{{id}}/+/', where ID is unique per subscriber.<br/>\n"
-                        "Topic match performance (when publishing) may degrade if messages\n"
-                        "are mostly published to topics with large number of levels.<br/>\n"
-                        "NOTE: This is a cluster-wide configuration.\n"
-                        "It requires all nodes to be stopped before changing it."
+                    desc => ?DESC(broker_perf_trie_compaction)
                 }
             )}
     ];
@@ -1327,7 +1254,7 @@ fields("sys_topics") ->
                 hoconsc:union([disabled, duration()]),
                 #{
                     default => "1m",
-                    desc => "Time interval of publishing `$SYS` messages."
+                    desc => ?DESC(sys_msg_interval)
                 }
             )},
         {"sys_heartbeat_interval",
@@ -1335,16 +1262,13 @@ fields("sys_topics") ->
                 hoconsc:union([disabled, duration()]),
                 #{
                     default => "30s",
-                    desc =>
-                        "Time interval for publishing following heartbeat messages:<br/>"
-                        " - `$SYS/brokers/<node>/uptime`\n"
-                        " - `$SYS/brokers/<node>/datetime`"
+                    desc => ?DESC(sys_heartbeat_interval)
                 }
             )},
         {"sys_event_messages",
             sc(
                 ref("event_names"),
-                #{}
+                #{ desc => ?DESC(sys_event_messages) }
             )}
     ];
 fields("event_names") ->
@@ -1354,7 +1278,7 @@ fields("event_names") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Connection complete"
+                    desc => ?DESC(sys_event_client_connected)
                 }
             )},
         {"client_disconnected",
@@ -1362,7 +1286,7 @@ fields("event_names") ->
                 boolean(),
                 #{
                     default => true,
-                    desc => "Disconnect"
+                    desc => ?DESC(sys_event_client_disconnected)
                 }
             )},
         {"client_subscribed",
@@ -1370,7 +1294,7 @@ fields("event_names") ->
                 boolean(),
                 #{
                     default => false,
-                    desc => "Subscribe"
+                    desc => ?DESC(sys_event_client_subscribed)
                 }
             )},
         {"client_unsubscribed",
@@ -1378,7 +1302,7 @@ fields("event_names") ->
                 boolean(),
                 #{
                     default => false,
-                    desc => "Unsubscribe"
+                    desc => ?DESC(sys_event_client_unsubscribed)
                 }
             )}
     ];