diff --git a/apps/desktop/src/components/connection/ConnectionDialog.vue b/apps/desktop/src/components/connection/ConnectionDialog.vue
index 9eef79123a..f1decc5dd6 100644
--- a/apps/desktop/src/components/connection/ConnectionDialog.vue
+++ b/apps/desktop/src/components/connection/ConnectionDialog.vue
@@ -7798,7 +7798,7 @@ function openExternalUrl(url: string) {
-
+
diff --git a/apps/desktop/src/i18n/__tests__/mqttConnectionLabelParity.spec.ts b/apps/desktop/src/i18n/__tests__/mqttConnectionLabelParity.spec.ts
new file mode 100644
index 0000000000..607b67b655
--- /dev/null
+++ b/apps/desktop/src/i18n/__tests__/mqttConnectionLabelParity.spec.ts
@@ -0,0 +1,104 @@
+import { readFileSync } from "node:fs";
+import { createI18n } from "vue-i18n";
+import { describe, expect, it } from "vitest";
+import az from "@/i18n/locales/az";
+import en from "@/i18n/locales/en";
+import es from "@/i18n/locales/es";
+import itLocale from "@/i18n/locales/it";
+import ja from "@/i18n/locales/ja";
+import ko from "@/i18n/locales/ko";
+import ptBR from "@/i18n/locales/pt-BR";
+import tr from "@/i18n/locales/tr";
+import zhCN from "@/i18n/locales/zh-CN";
+import zhTW from "@/i18n/locales/zh-TW";
+
+// These assertions read the locale SOURCES as text instead of importing the modules.
+// Every non-English locale is `export default withEnglishFallback({ ... })`, and
+// withEnglishFallback deep-merges `en` UNDER the locale at import time, so the imported
+// default export already carries every english key — including the key this spec exists
+// to guard. Asserting on those objects would pass even if a locale silently dropped the
+// label (same trap documented in docsNamespaceParity.spec.ts), so the check has to happen
+// before the merge does.
+function localeSource(name: string): string {
+ return readFileSync(new URL(`../locales/${name}.ts`, import.meta.url), "utf8");
+}
+
+function declaredString(source: string, key: string): string | undefined {
+ return source.match(new RegExp(String.raw`^\s*${key}:\s*"((?:[^"\\]|\\.)*)",\s*$`, "m"))?.[1];
+}
+
+// The locales that carry the connection.mqtt* form cluster (led by mqttKeepAlive).
+const localesCarryingMqttCluster = ["en", "zh-CN", "zh-TW", "ja", "it", "es", "pt-BR", "tr", "az"];
+// Every locale FILE must declare the key in source. This is the assertion that actually
+// guards drift: the imported modules cannot show a removed source key, because
+// withEnglishFallback deep-merges english underneath at import time (see header).
+const allLocaleFiles = [...localesCarryingMqttCluster, "ko"];
+
+describe("mqtt max packet size label i18n parity", () => {
+ it("english declares the label with its byte unit", () => {
+ expect(declaredString(localeSource("en"), "mqttMaxPacketSize")).toContain("bytes");
+ });
+
+ it.each(allLocaleFiles)("%s declares the label in its source file", (name) => {
+ const label = declaredString(localeSource(name), "mqttMaxPacketSize");
+ expect(label, `${name}.ts must declare connection.mqttMaxPacketSize`).toBeTruthy();
+ expect(label?.trim()).not.toBe("");
+ });
+
+ it.each(localesCarryingMqttCluster)("%s declares the label alongside its mqtt cluster", (name) => {
+ const source = localeSource(name);
+ // Anchor: only locales that already declare the cluster get the new key.
+ expect(declaredString(source, "mqttKeepAlive"), `${name}.ts must declare connection.mqttKeepAlive`).toBeTruthy();
+ // Semantic-cluster anchoring (i18n-locales.md): the label belongs next to mqttConnectTimeout.
+ expect(source.indexOf("mqttMaxPacketSize:"), `${name}.ts must anchor the key after mqttConnectTimeout`).toBeGreaterThan(source.indexOf("mqttConnectTimeout:"));
+ });
+
+ it("ko declares the label without taking on the rest of the mqtt form cluster", () => {
+ const source = localeSource("ko");
+ // ko translates a few mqtt console strings but none of the form fields, so the form
+ // renders in english there via withEnglishFallback. This one label is the deliberate
+ // exception: it is declared in source so the Korean text exists in the file, and it is
+ // the only form key ko owns — do not grow the cluster here.
+ expect(declaredString(source, "mqttMaxPacketSize")).toBeTruthy();
+ expect(declaredString(source, "mqttKeepAlive")).toBeUndefined();
+ expect(declaredString(source, "mqttConnectTimeout")).toBeUndefined();
+ });
+});
+
+// Layer (a) from the PRD: the label must also resolve through vue-i18n at runtime. This is
+// weaker than the source-level check above — the deep-merge hands a locale that drops the
+// key the english text, so it cannot see drift — but it is what catches a locale module
+// that fails to declare or parse the key at all, and the "key path leaks into the UI"
+// failure mode that a missing translation produces.
+const localeModules: Array<[string, Record]> = [
+ ["az", az],
+ ["en", en],
+ ["es", es],
+ ["it", itLocale],
+ ["ja", ja],
+ ["ko", ko],
+ ["pt-BR", ptBR],
+ ["tr", tr],
+ ["zh-CN", zhCN],
+ ["zh-TW", zhTW],
+];
+
+describe("mqtt max packet size label resolution", () => {
+ it.each(localeModules)("%s resolves the label to a translated string", (name, messages) => {
+ const connection = (messages.connection ?? {}) as typeof en.connection;
+ const i18n = createI18n({ legacy: false, locale: name, messages: { [name]: { connection } } });
+ const label = i18n.global.t("connection.mqttMaxPacketSize");
+ expect(label).not.toBe("connection.mqttMaxPacketSize");
+ expect(label.trim()).not.toBe("");
+ i18n.dispose();
+ });
+});
+
+describe("connection dialog mqtt label call site", () => {
+ const componentSource = readFileSync(new URL("../../components/connection/ConnectionDialog.vue", import.meta.url), "utf8");
+
+ it("renders the label through vue-i18n instead of a hardcoded chinese string", () => {
+ expect(componentSource).toContain('{{ t("connection.mqttMaxPacketSize") }}');
+ expect(componentSource).not.toContain("最大报文");
+ });
+});
diff --git a/apps/desktop/src/i18n/locales/az.ts b/apps/desktop/src/i18n/locales/az.ts
index 095742ad36..a85f8cbb19 100644
--- a/apps/desktop/src/i18n/locales/az.ts
+++ b/apps/desktop/src/i18n/locales/az.ts
@@ -950,6 +950,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket yolu",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Əlaqə üçün vaxt limiti (saniyə)",
+ mqttMaxPacketSize: "Maksimal paket ölçüsü (bayt)",
mqttConsoleTitle: "MQTT konsolu",
mqttTopics: "Mövzular",
mqttMessages: "Mesajlar",
diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts
index fdf48dd9d7..3ef46e82be 100644
--- a/apps/desktop/src/i18n/locales/en.ts
+++ b/apps/desktop/src/i18n/locales/en.ts
@@ -1118,6 +1118,7 @@ export default {
mqttWsPath: "WebSocket Path",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Connect Timeout (seconds)",
+ mqttMaxPacketSize: "Max Packet Size (bytes)",
mqttConsoleTitle: "MQTT Console",
mqttTopics: "Topics",
mqttMessages: "Messages",
diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts
index 4ba5d9863a..46ea234a9e 100644
--- a/apps/desktop/src/i18n/locales/es.ts
+++ b/apps/desktop/src/i18n/locales/es.ts
@@ -982,6 +982,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket Path",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Connect Timeout (seconds)",
+ mqttMaxPacketSize: "Max Packet Size (bytes)",
nacosMetrics: "Métricas Prometheus",
nacosMetricsAuto: "Detección automática",
nacosMetricsDisabled: "Desactivado",
diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts
index cb69619c93..5a2ecb9ef1 100644
--- a/apps/desktop/src/i18n/locales/it.ts
+++ b/apps/desktop/src/i18n/locales/it.ts
@@ -980,6 +980,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket Path",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Connect Timeout (seconds)",
+ mqttMaxPacketSize: "Max Packet Size (bytes)",
nacosMetrics: "Metriche Prometheus",
nacosMetricsAuto: "Rilevamento automatico",
nacosMetricsDisabled: "Disabilitato",
diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts
index 17bb8af84a..3a566e2ea8 100644
--- a/apps/desktop/src/i18n/locales/ja.ts
+++ b/apps/desktop/src/i18n/locales/ja.ts
@@ -946,6 +946,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket Path",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Connect Timeout (seconds)",
+ mqttMaxPacketSize: "Max Packet Size (bytes)",
nacosMetrics: "Prometheus メトリクス",
nacosMetricsAuto: "自動検出",
nacosMetricsDisabled: "無効",
diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts
index 6197274aff..6aa0f1d4fa 100644
--- a/apps/desktop/src/i18n/locales/ko.ts
+++ b/apps/desktop/src/i18n/locales/ko.ts
@@ -1400,6 +1400,7 @@ export default withEnglishFallback({
pluginSshKeyPickerEmpty: "키를 찾을 수 없음",
pluginSshKeyEncrypted: "암호화됨",
objectCacheRefreshFailed: "개체 캐시 새로 고침 실패: {message}",
+ mqttMaxPacketSize: "최대 패킷 크기(바이트)",
},
editor: {
duckdbDraining: "이전 DuckDB 쿼리가 아직 중지 중입니다. 잠시 후 다시 시도해 주세요.",
diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts
index 28530025c5..30b2068119 100644
--- a/apps/desktop/src/i18n/locales/pt-BR.ts
+++ b/apps/desktop/src/i18n/locales/pt-BR.ts
@@ -981,6 +981,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket Path",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Connect Timeout (seconds)",
+ mqttMaxPacketSize: "Max Packet Size (bytes)",
nacosMetrics: "Métricas Prometheus",
nacosMetricsAuto: "Detecção automática",
nacosMetricsDisabled: "Desativado",
diff --git a/apps/desktop/src/i18n/locales/tr.ts b/apps/desktop/src/i18n/locales/tr.ts
index ded4a0936b..79480ea50d 100644
--- a/apps/desktop/src/i18n/locales/tr.ts
+++ b/apps/desktop/src/i18n/locales/tr.ts
@@ -952,6 +952,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket Yolu",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Bağlantı Zaman Aşımı (saniye)",
+ mqttMaxPacketSize: "Maksimum Paket Boyutu (bayt)",
mqttConsoleTitle: "MQTT Konsolu",
mqttTopics: "Konular",
mqttMessages: "Mesajlar",
diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts
index fdcc45efba..4a38456c8d 100644
--- a/apps/desktop/src/i18n/locales/zh-CN.ts
+++ b/apps/desktop/src/i18n/locales/zh-CN.ts
@@ -1032,6 +1032,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket 路径",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "连接超时(秒)",
+ mqttMaxPacketSize: "最大报文(字节)",
mqttConsoleTitle: "MQTT 控制台",
mqttTopics: "Topics",
mqttMessages: "消息",
diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts
index 8f85bf60e1..83f912d1a8 100644
--- a/apps/desktop/src/i18n/locales/zh-TW.ts
+++ b/apps/desktop/src/i18n/locales/zh-TW.ts
@@ -982,6 +982,7 @@ export default withEnglishFallback({
mqttWsPath: "WebSocket Path",
mqttWsPathPlaceholder: "/mqtt",
mqttConnectTimeout: "Connect Timeout (seconds)",
+ mqttMaxPacketSize: "Max Packet Size (bytes)",
nacosMetrics: "Prometheus 指標",
nacosMetricsAuto: "自動偵測",
nacosMetricsDisabled: "關閉",