dsh-pocket 1.9.2 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/client.js +145 -39
- package/client/index.jsx +58 -43
- package/client/pocket-locales.js +101 -0
- package/package.json +1 -1
package/client/client.js
CHANGED
|
@@ -1290,9 +1290,115 @@ function mobileApply(ctx) {
|
|
|
1290
1290
|
}, MobileDrawerFooter));
|
|
1291
1291
|
}
|
|
1292
1292
|
|
|
1293
|
+
// client/pocket-locales.js
|
|
1294
|
+
var NS2 = "pocket";
|
|
1295
|
+
var zh2 = {
|
|
1296
|
+
"section": "\u624B\u673A\u8BBF\u95EE",
|
|
1297
|
+
"title": "\u{1F4F1} \u624B\u673A\u8BBF\u95EE",
|
|
1298
|
+
"subtitle": "\u624B\u673A\u626B\u7801\u6253\u5F00\u7684\u5C31\u662F\u7535\u8111\u4E0A\u7684\u8FD9\u4E2A\u754C\u9762\uFF0C\u5B9E\u65F6\u540C\u6B65",
|
|
1299
|
+
"developer": "\u5F00\u53D1\u8005\uFF1A\u7A0B\u5E8F\u5458\u5C11\u5317\u6668",
|
|
1300
|
+
"starAsk": "\u2B50 \u987A\u624B\u7559\u9897 Star\uFF0C\u4F5C\u8005\u80FD\u9AD8\u5174\u4E00\u6574\u5929",
|
|
1301
|
+
"starCta": "\u884C\uFF0C\u7ED9\u4F60\u4E00\u9897 Star",
|
|
1302
|
+
"restarted": "\u{1F504} \u5DF2\u91CD\u542F",
|
|
1303
|
+
"ok": "\u77E5\u9053\u4E86",
|
|
1304
|
+
"bgHint": "\u8FDB\u7A0B\u5728\u540E\u53F0\u8FD0\u884C\uFF08\u4E0D\u6302\u7EC8\u7AEF\uFF09\u3002\u5982\u9700\u505C\u6B62\uFF1A{cmd}",
|
|
1305
|
+
"updatedRestart": "\u2705 \u5DF2\u66F4\u65B0 v{ver}\uFF0C\u91CD\u542F\u751F\u6548",
|
|
1306
|
+
"updateAutoRestarting": "\u2705 \u5DF2\u66F4\u65B0 v{ver}\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u542F\u2026",
|
|
1307
|
+
"updatedOk": "\u2705 \u5DF2\u66F4\u65B0 v{ver}",
|
|
1308
|
+
"updateAvailable": "\u{1F4E6} \u65B0\u7248\u672C v{ver}",
|
|
1309
|
+
"updating": "\u66F4\u65B0\u4E2D\u2026",
|
|
1310
|
+
"updateTo": "\u66F4\u65B0\u5230 v{ver}",
|
|
1311
|
+
"restartingNow": "\u6B63\u5728\u91CD\u542F\u751F\u6548\u2026",
|
|
1312
|
+
"restarting": "\u91CD\u542F\u4E2D\u2026",
|
|
1313
|
+
"restartNow": "\u{1F504} \u91CD\u542F dsh web \u751F\u6548",
|
|
1314
|
+
"updatingDetail": "\u23F3 \u66F4\u65B0\u4E2D\uFF08\u901A\u5E38 1-2 \u5206\u949F\uFF09\xB7 \u5DF2\u7B49\u5F85 {s} \u79D2",
|
|
1315
|
+
"restartingDetail": "\u23F3 \u6B63\u5728\u91CD\u542F\u751F\u6548\uFF08\u901A\u5E38 10-30 \u79D2\uFF09\xB7 \u5DF2\u7B49\u5F85 {s} \u79D2",
|
|
1316
|
+
"updatedAutoDetail": "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u6B63\u5728\u81EA\u52A8\u91CD\u542F\u751F\u6548\uFF0C\u8BF7\u7A0D\u5019\u5237\u65B0",
|
|
1317
|
+
"updatedRestartDetail": "\u2705 \u5DF2\u66F4\u65B0\uFF0C\u91CD\u542F dsh web \u751F\u6548",
|
|
1318
|
+
"updateFailed": "\u274C \u5931\u8D25\uFF1A{err}\uFF08\u624B\u52A8\u66F4\u65B0\uFF1Adsh plugin --profile web update dsh-pocket --latest -w\uFF09",
|
|
1319
|
+
"versionRange": "\u5F53\u524D v{cur} \u2192 \u6700\u65B0 v{latest}",
|
|
1320
|
+
"lanTitle": "\u{1F4F6} \u5C40\u57DF\u7F51\uFF08\u540C\u4E00 WiFi\uFF09",
|
|
1321
|
+
"lanHint": "\u624B\u673A\u8FDE\u63A5\u540C\u4E00 WiFi \u540E\u626B\u7801\u5373\u53EF\u6253\u5F00",
|
|
1322
|
+
"lanPin": "\u5C40\u57DF\u7F51\u8BBF\u95EE\u5BC6\u7801",
|
|
1323
|
+
"on": "\u5F00",
|
|
1324
|
+
"off": "\u5173",
|
|
1325
|
+
"lanPinValue": "\u{1F510} \u8BBF\u95EE\u5BC6\u7801\uFF1A{pin}\uFF08\u624B\u673A\u6253\u5F00\u9700\u8F93\u5165\uFF1B\u4E0E\u516C\u7F51\u5BC6\u7801\u5206\u5F00\uFF09",
|
|
1326
|
+
"refresh": "\u5237\u65B0",
|
|
1327
|
+
"lanPinOff": "\u{1F513} \u5BC6\u7801\u5DF2\u5173\u95ED\uFF1A\u626B\u7801\u76F4\u8FDE\uFF0C\u65E0\u9700\u5BC6\u7801\uFF08\u4EC5\u540C\u4E00\u5C40\u57DF\u7F51\u8BBE\u5907\u53EF\u8BBF\u95EE\uFF1B\u516C\u7F51\u4ECD\u8981\u5BC6\u7801\uFF09",
|
|
1328
|
+
"lanStarting": "\u4EE3\u7406\u672A\u5C31\u7EEA\u2026",
|
|
1329
|
+
"wanTitle": "\u{1F310} \u516C\u7F51\uFF08\u4EBA\u5728\u5916\u9762\uFF09",
|
|
1330
|
+
"wanHint": "\u4EFB\u4F55\u7F51\u7EDC\u626B\u7801\u5373\u7528\uFF08URL \u6BCF\u6B21\u91CD\u542F\u81EA\u52A8\u6362\u65B0\uFF09",
|
|
1331
|
+
"wanPin": "\u{1F510} \u8BBF\u95EE\u5BC6\u7801\uFF1A{pin}\uFF08\u6BCF\u6B21\u5F00\u542F\u516C\u7F51\u53D8\u65B0\uFF1B\u624B\u673A\u6253\u5F00\u94FE\u63A5\u9700\u8F93\u5165\u6B64\u5BC6\u7801\uFF09",
|
|
1332
|
+
"stopTunnel": "\u5173\u95ED\u516C\u7F51",
|
|
1333
|
+
"enable": "\u5F00\u542F\u516C\u7F51\u8BBF\u95EE",
|
|
1334
|
+
"opening": "\u5F00\u542F\u4E2D\u2026",
|
|
1335
|
+
"downloading": "\u23F3 \u4E0B\u8F7D cloudflared\uFF08\u9996\u6B21\u7EA6 20-50MB\uFF0C\u901A\u5E38 1-2 \u5206\u949F\uFF1B\u4E4B\u540E\u79D2\u5F00\uFF09\xB7 \u5DF2\u7B49\u5F85 {s} \u79D2",
|
|
1336
|
+
"connecting": "\u23F3 \u8FDE\u63A5 Cloudflare \u8FB9\u7F18\uFF08\u901A\u5E38 5-30 \u79D2\uFF09\xB7 \u5DF2\u7B49\u5F85 {s} \u79D2{suffix}",
|
|
1337
|
+
"slowHint": " \u2014 \u6709\u70B9\u4E45\uFF1F\u68C0\u67E5\u662F\u5426\u5F00\u7740\u4EE3\u7406/VPN\uFF08Clash TUN \u7B49\uFF09",
|
|
1338
|
+
"error": "\u274C \u5F00\u542F\u5931\u8D25\uFF1A{detail}\uFF08\u53EF\u91CD\u8BD5\uFF1B\u82E5\u662F\u4EE3\u7406/VPN \u95EE\u9898\u89C1 README \u6392\u969C\uFF09",
|
|
1339
|
+
"unknownError": "\u672A\u77E5\u9519\u8BEF",
|
|
1340
|
+
"feedback": "\u6709\u95EE\u9898\uFF1F\u6B22\u8FCE\u5230 GitHub Issues \u53CD\u9988 \u{1F64F}"
|
|
1341
|
+
};
|
|
1342
|
+
var en2 = {
|
|
1343
|
+
"section": "Phone access",
|
|
1344
|
+
"title": "\u{1F4F1} Phone access",
|
|
1345
|
+
"subtitle": "The phone shows this exact screen, live",
|
|
1346
|
+
"developer": "Developer: \u5C11\u5317\u6668 (shaobeichen)",
|
|
1347
|
+
"starAsk": "\u2B50 Drop a Star if it helped \u2014 it makes the author\u2019s day",
|
|
1348
|
+
"starCta": "\u2605 Give a Star",
|
|
1349
|
+
"restarted": "\u{1F504} Restarted",
|
|
1350
|
+
"ok": "Got it",
|
|
1351
|
+
"bgHint": "Running in the background (not attached to a terminal). To stop: {cmd}",
|
|
1352
|
+
"updatedRestart": "\u2705 Updated to v{ver} \u2014 restart to apply",
|
|
1353
|
+
"updateAutoRestarting": "\u2705 Updated to v{ver} \u2014 auto-restarting\u2026",
|
|
1354
|
+
"updatedOk": "\u2705 Updated to v{ver}",
|
|
1355
|
+
"updateAvailable": "\u{1F4E6} Update available: v{ver}",
|
|
1356
|
+
"updating": "Updating\u2026",
|
|
1357
|
+
"updateTo": "Update to v{ver}",
|
|
1358
|
+
"restartingNow": "Restarting to apply\u2026",
|
|
1359
|
+
"restarting": "Restarting\u2026",
|
|
1360
|
+
"restartNow": "\u{1F504} Restart dsh web now",
|
|
1361
|
+
"updatingDetail": "\u23F3 Updating (usually 1-2 min) \xB7 {s}s elapsed",
|
|
1362
|
+
"restartingDetail": "\u23F3 Restarting to apply (usually 10-30s) \xB7 {s}s elapsed",
|
|
1363
|
+
"updatedAutoDetail": "\u2705 Updated \u2014 auto-restarting in progress, refresh shortly",
|
|
1364
|
+
"updatedRestartDetail": "\u2705 Updated \u2014 restart dsh web to apply",
|
|
1365
|
+
"updateFailed": "\u274C Failed: {err} (manual update: dsh plugin --profile web update dsh-pocket --latest -w)",
|
|
1366
|
+
"versionRange": "Current v{cur} \u2192 latest v{latest}",
|
|
1367
|
+
"lanTitle": "\u{1F4F6} LAN (same Wi-Fi)",
|
|
1368
|
+
"lanHint": "Scan to open once your phone is on the same Wi-Fi",
|
|
1369
|
+
"lanPin": "LAN access PIN",
|
|
1370
|
+
"on": "On",
|
|
1371
|
+
"off": "Off",
|
|
1372
|
+
"lanPinValue": "\u{1F510} PIN: {pin} (required on the phone; separate from the public PIN)",
|
|
1373
|
+
"refresh": "Refresh",
|
|
1374
|
+
"lanPinOff": "\u{1F513} PIN off \u2014 scan & go, no PIN (LAN devices only; public still requires PIN)",
|
|
1375
|
+
"lanStarting": "Proxy starting\u2026",
|
|
1376
|
+
"wanTitle": "\u{1F310} Anywhere (public)",
|
|
1377
|
+
"wanHint": "Scan from any network (the URL changes on every restart)",
|
|
1378
|
+
"wanPin": "\u{1F510} PIN: {pin} (changes each time the tunnel is enabled; required on the phone)",
|
|
1379
|
+
"stopTunnel": "Stop",
|
|
1380
|
+
"enable": "Enable anywhere",
|
|
1381
|
+
"opening": "Enabling\u2026",
|
|
1382
|
+
"downloading": "\u23F3 Downloading cloudflared (first run ~20-50MB, usually 1-2 min; instant afterward) \xB7 {s}s elapsed",
|
|
1383
|
+
"connecting": "\u23F3 Connecting to Cloudflare edge (usually 5-30s) \xB7 {s}s elapsed{suffix}",
|
|
1384
|
+
"slowHint": " \u2014 taking long? Check for a proxy/VPN (e.g., Clash TUN)",
|
|
1385
|
+
"error": "\u274C Failed to enable: {detail} (you can retry; for proxy/VPN issues see the README)",
|
|
1386
|
+
"unknownError": "unknown error",
|
|
1387
|
+
"feedback": "\u{1F64F} Questions? Open an issue on GitHub"
|
|
1388
|
+
};
|
|
1389
|
+
|
|
1293
1390
|
// client/index.jsx
|
|
1294
1391
|
var name = "dsh-pocket";
|
|
1295
1392
|
var inject = ["slots", "connection", "layout", "locale", "sessionLogDownload"];
|
|
1393
|
+
function fmt(t, key, vars) {
|
|
1394
|
+
let s = t(key);
|
|
1395
|
+
if (vars) {
|
|
1396
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
1397
|
+
s = String(s).split(`{${k}}`).join(String(v));
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return s;
|
|
1401
|
+
}
|
|
1296
1402
|
var styles = {
|
|
1297
1403
|
card: { background: "var(--dsw-alias-bg-layer-1,#fff)", border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", borderRadius: 12, padding: "16px 20px", maxWidth: 480 },
|
|
1298
1404
|
block: { borderTop: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", marginTop: 16, paddingTop: 16 },
|
|
@@ -1305,7 +1411,7 @@ var styles = {
|
|
|
1305
1411
|
qr: { width: 220, height: 220, borderRadius: 10, border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", margin: "8px 0" },
|
|
1306
1412
|
warn: { color: "var(--dsw-alias-state-warn-primary,#b45309)", fontSize: 12, lineHeight: 1.5 }
|
|
1307
1413
|
};
|
|
1308
|
-
function PocketSettingsTab({ rpcCall }) {
|
|
1414
|
+
function PocketSettingsTab({ rpcCall, t }) {
|
|
1309
1415
|
const [status, setStatus] = (0, import_react2.useState)(null);
|
|
1310
1416
|
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
1311
1417
|
const [error, setError] = (0, import_react2.useState)(null);
|
|
@@ -1315,8 +1421,8 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1315
1421
|
const [isDesktop, setIsDesktop] = (0, import_react2.useState)(false);
|
|
1316
1422
|
const [now, setNow] = (0, import_react2.useState)(Date.now());
|
|
1317
1423
|
(0, import_react2.useEffect)(() => {
|
|
1318
|
-
const
|
|
1319
|
-
return () => clearInterval(
|
|
1424
|
+
const t2 = setInterval(() => setNow(Date.now()), 1e3);
|
|
1425
|
+
return () => clearInterval(t2);
|
|
1320
1426
|
}, []);
|
|
1321
1427
|
const elapsed = (startedAt) => startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1e3)) : 0;
|
|
1322
1428
|
const call = async (endpoint, payload) => {
|
|
@@ -1348,8 +1454,8 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1348
1454
|
};
|
|
1349
1455
|
(0, import_react2.useEffect)(() => {
|
|
1350
1456
|
load();
|
|
1351
|
-
const
|
|
1352
|
-
return () => clearInterval(
|
|
1457
|
+
const t2 = setInterval(load, 3e3);
|
|
1458
|
+
return () => clearInterval(t2);
|
|
1353
1459
|
}, []);
|
|
1354
1460
|
(0, import_react2.useEffect)(() => {
|
|
1355
1461
|
try {
|
|
@@ -1375,10 +1481,10 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1375
1481
|
}
|
|
1376
1482
|
};
|
|
1377
1483
|
check();
|
|
1378
|
-
const
|
|
1484
|
+
const t2 = setInterval(check, 5 * 60 * 1e3);
|
|
1379
1485
|
return () => {
|
|
1380
1486
|
alive = false;
|
|
1381
|
-
clearInterval(
|
|
1487
|
+
clearInterval(t2);
|
|
1382
1488
|
};
|
|
1383
1489
|
}, [isDesktop]);
|
|
1384
1490
|
const restartPocket = async () => {
|
|
@@ -1460,18 +1566,18 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1460
1566
|
(0, import_react2.createElement)(
|
|
1461
1567
|
"div",
|
|
1462
1568
|
null,
|
|
1463
|
-
(0, import_react2.createElement)("strong", null, "
|
|
1464
|
-
(0, import_react2.createElement)("div", { style: styles.muted }, "
|
|
1569
|
+
(0, import_react2.createElement)("strong", null, t("title")),
|
|
1570
|
+
(0, import_react2.createElement)("div", { style: styles.muted }, t("subtitle"))
|
|
1465
1571
|
),
|
|
1466
1572
|
(0, import_react2.createElement)(
|
|
1467
1573
|
"div",
|
|
1468
1574
|
{ style: { fontSize: 12, color: "var(--dsw-alias-label-tertiary,#8b93a1)", textAlign: "right" } },
|
|
1469
|
-
(0, import_react2.createElement)("div", { style: { whiteSpace: "nowrap" } }, "
|
|
1470
|
-
(0, import_react2.createElement)("div", { style: { whiteSpace: "nowrap" } }, "
|
|
1575
|
+
(0, import_react2.createElement)("div", { style: { whiteSpace: "nowrap" } }, t("developer")),
|
|
1576
|
+
(0, import_react2.createElement)("div", { style: { whiteSpace: "nowrap" } }, t("starAsk")),
|
|
1471
1577
|
(0, import_react2.createElement)(
|
|
1472
1578
|
"a",
|
|
1473
1579
|
{ href: "https://github.com/shaobeichen/dsh-pocket", target: "_blank", rel: "noreferrer", style: { color: "var(--dsw-alias-brand-primary,#4f6ef7)", fontSize: 12, lineHeight: 1.6, textDecoration: "underline" } },
|
|
1474
|
-
"
|
|
1580
|
+
t("starCta")
|
|
1475
1581
|
)
|
|
1476
1582
|
)
|
|
1477
1583
|
),
|
|
@@ -1483,10 +1589,10 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1483
1589
|
(0, import_react2.createElement)(
|
|
1484
1590
|
"div",
|
|
1485
1591
|
{ style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 } },
|
|
1486
|
-
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, "
|
|
1487
|
-
(0, import_react2.createElement)("button", { style: styles.btn, onClick: () => setRestartNotice(false) }, "
|
|
1592
|
+
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, t("restarted")),
|
|
1593
|
+
(0, import_react2.createElement)("button", { style: styles.btn, onClick: () => setRestartNotice(false) }, t("ok"))
|
|
1488
1594
|
),
|
|
1489
|
-
(0, import_react2.createElement)("div", { style: styles.muted, marginTop: 4, wordBreak: "break-all" },
|
|
1595
|
+
(0, import_react2.createElement)("div", { style: styles.muted, marginTop: 4, wordBreak: "break-all" }, fmt(t, "bgHint", { cmd: status?.killHint ?? `lsof -ti :${status?.dshPort ?? 3080} | xargs kill -9` }))
|
|
1490
1596
|
) : null,
|
|
1491
1597
|
// 更新提示——左侧黄色色条(提示有新版本);单状态:有更新/更新中/已更新自动重启,不并存
|
|
1492
1598
|
// 桌面端不渲染(更新由 DSH Desktop 管理)
|
|
@@ -1499,84 +1605,82 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1499
1605
|
(0, import_react2.createElement)(
|
|
1500
1606
|
"div",
|
|
1501
1607
|
{ style: { fontWeight: 600, fontSize: 13 } },
|
|
1502
|
-
updateInfo.updated ?
|
|
1608
|
+
updateInfo.updated ? fmt(t, "updatedRestart", { ver: updateInfo.current }) : updateInfo.result === "ok" ? updateInfo.autoRestart ? fmt(t, "updateAutoRestarting", { ver: updateInfo.latest }) : fmt(t, "updatedOk", { ver: updateInfo.latest }) : fmt(t, "updateAvailable", { ver: updateInfo.latest })
|
|
1503
1609
|
),
|
|
1504
|
-
updateInfo.result !== "ok" ? (0, import_react2.createElement)("button", { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? "
|
|
1610
|
+
updateInfo.result !== "ok" ? (0, import_react2.createElement)("button", { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? t("updating") : fmt(t, "updateTo", { ver: updateInfo.latest })) : updateInfo.autoRestart ? (0, import_react2.createElement)("button", { style: styles.btn, disabled: true }, t("restartingNow")) : (0, import_react2.createElement)("button", { style: styles.primary, onClick: restartPocket, disabled: updateInfo.restarting }, updateInfo.restarting ? t("restarting") : t("restartNow"))
|
|
1505
1611
|
),
|
|
1506
1612
|
(0, import_react2.createElement)(
|
|
1507
1613
|
"div",
|
|
1508
1614
|
{ style: styles.muted, marginTop: 4 },
|
|
1509
|
-
updateInfo.updating ?
|
|
1615
|
+
updateInfo.updating ? fmt(t, "updatingDetail", { s: elapsed(updateInfo.startedAt) }) : updateInfo.restarting ? fmt(t, "restartingDetail", { s: elapsed(updateInfo.startedAt) }) : updateInfo.result === "ok" ? updateInfo.autoRestart ? t("updatedAutoDetail") : t("updatedRestartDetail") : updateInfo.result === "fail" ? fmt(t, "updateFailed", { err: updateInfo.output || t("unknownError") }) : fmt(t, "versionRange", { cur: updateInfo.current, latest: updateInfo.latest })
|
|
1510
1616
|
)
|
|
1511
1617
|
) : null,
|
|
1512
1618
|
// 局域网
|
|
1513
1619
|
(0, import_react2.createElement)(
|
|
1514
1620
|
"div",
|
|
1515
1621
|
{ style: styles.block },
|
|
1516
|
-
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, "
|
|
1622
|
+
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, t("lanTitle")),
|
|
1517
1623
|
lanUrl ? (0, import_react2.createElement)(
|
|
1518
1624
|
"div",
|
|
1519
1625
|
null,
|
|
1520
1626
|
(0, import_react2.createElement)("img", { src: status.lanQr, alt: "LAN QR", style: styles.qr }),
|
|
1521
1627
|
(0, import_react2.createElement)("div", { style: styles.code }, lanUrl),
|
|
1522
|
-
(0, import_react2.createElement)("div", { style: styles.muted }, "
|
|
1628
|
+
(0, import_react2.createElement)("div", { style: styles.muted }, t("lanHint")),
|
|
1523
1629
|
// 访问密码开关(issue #24):默认开启;关闭后扫码直连(仅同一局域网设备可访问)
|
|
1524
1630
|
(0, import_react2.createElement)(
|
|
1525
1631
|
"div",
|
|
1526
1632
|
{ style: { display: "flex", alignItems: "center", gap: 8, marginTop: 8 } },
|
|
1527
|
-
(0, import_react2.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)" } }, "
|
|
1633
|
+
(0, import_react2.createElement)("span", { style: { fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)" } }, t("lanPin")),
|
|
1528
1634
|
(0, import_react2.createElement)("button", {
|
|
1529
1635
|
style: { ...styles.btn, height: 28, padding: "0 12px", fontSize: 12, fontWeight: status?.lanAuthEnabled !== false ? 600 : 400, background: status?.lanAuthEnabled !== false ? "var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))" : "var(--dsw-alias-bg-layer-1,#fff)", color: status?.lanAuthEnabled !== false ? "var(--dsw-alias-label-primary-foreground, #fff)" : "var(--dsw-alias-label-primary,inherit)" },
|
|
1530
1636
|
onClick: () => setLanAuth(true)
|
|
1531
|
-
}, "
|
|
1637
|
+
}, t("on")),
|
|
1532
1638
|
(0, import_react2.createElement)("button", {
|
|
1533
1639
|
style: { ...styles.btn, height: 28, padding: "0 12px", fontSize: 12, fontWeight: status?.lanAuthEnabled === false ? 600 : 400, background: status?.lanAuthEnabled === false ? "var(--dsw-alias-state-error-primary,#dc2626)" : "var(--dsw-alias-bg-layer-1,#fff)", color: status?.lanAuthEnabled === false ? "#fff" : "var(--dsw-alias-label-primary,inherit)" },
|
|
1534
1640
|
onClick: () => setLanAuth(false)
|
|
1535
|
-
}, "
|
|
1641
|
+
}, t("off"))
|
|
1536
1642
|
),
|
|
1537
1643
|
status?.lanAuthEnabled !== false ? (0, import_react2.createElement)(
|
|
1538
1644
|
"div",
|
|
1539
1645
|
{ style: { marginTop: 6, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.5 } },
|
|
1540
|
-
"
|
|
1541
|
-
|
|
1542
|
-
"\uFF08\u624B\u673A\u6253\u5F00\u9700\u8F93\u5165\uFF1B\u4E0E\u516C\u7F51\u5BC6\u7801\u5206\u5F00\uFF09",
|
|
1543
|
-
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12, marginLeft: 8 }, onClick: refreshLanPin }, "\u5237\u65B0 | Refresh")
|
|
1646
|
+
fmt(t, "lanPinValue", { pin: status.lanToken }),
|
|
1647
|
+
(0, import_react2.createElement)("button", { style: { ...styles.btn, height: 26, padding: "0 10px", fontSize: 12, marginLeft: 8 }, onClick: refreshLanPin }, t("refresh"))
|
|
1544
1648
|
) : (0, import_react2.createElement)(
|
|
1545
1649
|
"div",
|
|
1546
1650
|
{ style: { marginTop: 6, fontSize: 12, color: "var(--dsw-alias-state-warn-primary,#b45309)", lineHeight: 1.5 } },
|
|
1547
|
-
"
|
|
1651
|
+
t("lanPinOff")
|
|
1548
1652
|
)
|
|
1549
|
-
) : (0, import_react2.createElement)("div", { style: styles.muted }, "
|
|
1653
|
+
) : (0, import_react2.createElement)("div", { style: styles.muted }, t("lanStarting"))
|
|
1550
1654
|
),
|
|
1551
1655
|
// 公网
|
|
1552
1656
|
(0, import_react2.createElement)(
|
|
1553
1657
|
"div",
|
|
1554
1658
|
{ style: styles.block },
|
|
1555
|
-
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, "
|
|
1659
|
+
(0, import_react2.createElement)("div", { style: { fontWeight: 600, fontSize: 13 } }, t("wanTitle")),
|
|
1556
1660
|
tunnelUrl ? (0, import_react2.createElement)(
|
|
1557
1661
|
"div",
|
|
1558
1662
|
null,
|
|
1559
1663
|
(0, import_react2.createElement)("img", { src: status.tunnelQr, alt: "Tunnel QR", style: styles.qr }),
|
|
1560
1664
|
(0, import_react2.createElement)("div", { style: styles.code }, tunnelUrl),
|
|
1561
|
-
(0, import_react2.createElement)("div", { style: styles.muted }, "
|
|
1665
|
+
(0, import_react2.createElement)("div", { style: styles.muted }, t("wanHint")),
|
|
1562
1666
|
status.accessToken ? (0, import_react2.createElement)(
|
|
1563
1667
|
"div",
|
|
1564
1668
|
{ style: { marginTop: 6, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", lineHeight: 1.5 } },
|
|
1565
|
-
|
|
1669
|
+
fmt(t, "wanPin", { pin: status.accessToken })
|
|
1566
1670
|
) : null,
|
|
1567
|
-
(0, import_react2.createElement)("button", { style: styles.btn, onClick: stopTunnel }, "
|
|
1671
|
+
(0, import_react2.createElement)("button", { style: styles.btn, onClick: stopTunnel }, t("stopTunnel"))
|
|
1568
1672
|
) : (0, import_react2.createElement)(
|
|
1569
1673
|
"div",
|
|
1570
1674
|
null,
|
|
1571
|
-
(0, import_react2.createElement)("button", { style: { ...styles.primary, margin: "8px 0" }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy ? "
|
|
1675
|
+
(0, import_react2.createElement)("button", { style: { ...styles.primary, margin: "8px 0" }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy ? t("opening") : t("enable")),
|
|
1572
1676
|
tunnelStarting ? (0, import_react2.createElement)(
|
|
1573
1677
|
"div",
|
|
1574
1678
|
{ style: { marginTop: 4, fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)" } },
|
|
1575
|
-
tunnelPhase === "downloading" ?
|
|
1679
|
+
tunnelPhase === "downloading" ? fmt(t, "downloading", { s: elapsed(tunnelStateStarted) }) : fmt(t, "connecting", { s: elapsed(tunnelStateStarted), suffix: elapsed(tunnelStateStarted) > 30 ? t("slowHint") : "" })
|
|
1576
1680
|
) : tunnelPhase === "error" ? (0, import_react2.createElement)(
|
|
1577
1681
|
"div",
|
|
1578
1682
|
{ style: { marginTop: 4, fontSize: 12, color: "var(--dsw-alias-state-error-primary,#dc2626)" } },
|
|
1579
|
-
|
|
1683
|
+
fmt(t, "error", { detail: tunnelStateDetail || t("unknownError") })
|
|
1580
1684
|
) : null
|
|
1581
1685
|
)
|
|
1582
1686
|
),
|
|
@@ -1588,7 +1692,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1588
1692
|
(0, import_react2.createElement)(
|
|
1589
1693
|
"a",
|
|
1590
1694
|
{ href: "https://github.com/shaobeichen/dsh-pocket/issues", target: "_blank", rel: "noreferrer", style: { fontSize: 12, color: "var(--dsw-alias-label-secondary,#6b7280)", textDecoration: "none" } },
|
|
1591
|
-
"
|
|
1695
|
+
t("feedback")
|
|
1592
1696
|
)
|
|
1593
1697
|
)
|
|
1594
1698
|
);
|
|
@@ -1596,6 +1700,8 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
1596
1700
|
function apply(ctx) {
|
|
1597
1701
|
mobileApply(ctx);
|
|
1598
1702
|
const rpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(POCKET_RPC_CHANNEL, endpoint, payload, signal);
|
|
1703
|
+
const translate = ctx.locale.bind(NS2);
|
|
1704
|
+
ctx.effect(() => ctx.locale.register(NS2, { zh: zh2, en: en2 }), "dsh-pocket: pocket locale dictionaries");
|
|
1599
1705
|
ctx.slots.inject(
|
|
1600
1706
|
"settings.section",
|
|
1601
1707
|
() => ctx.slots.register(
|
|
@@ -1603,8 +1709,8 @@ function apply(ctx) {
|
|
|
1603
1709
|
name: "settings.section",
|
|
1604
1710
|
id: "pocket",
|
|
1605
1711
|
order: 1,
|
|
1606
|
-
label: () => "
|
|
1607
|
-
inject: () => ({ rpcCall })
|
|
1712
|
+
label: () => translate("section"),
|
|
1713
|
+
inject: () => ({ rpcCall, t: translate })
|
|
1608
1714
|
},
|
|
1609
1715
|
PocketSettingsTab
|
|
1610
1716
|
)
|
package/client/index.jsx
CHANGED
|
@@ -11,10 +11,23 @@ import { createElement as h, useEffect, useState } from 'react';
|
|
|
11
11
|
|
|
12
12
|
import { POCKET_RPC_CHANNEL, POCKET_ENDPOINTS, redactStatus, compareVersions } from './api.js';
|
|
13
13
|
import { mobileApply } from './mobile/mobile-apply.tsx';
|
|
14
|
+
import { NS as POCKET_NS, zh as POCKET_ZH, en as POCKET_EN } from './pocket-locales.js';
|
|
14
15
|
|
|
15
16
|
const name = 'dsh-pocket';
|
|
16
17
|
const inject = ['slots', 'connection', 'layout', 'locale', 'sessionLogDownload'];
|
|
17
18
|
|
|
19
|
+
// 词典在 pocket-locales.js;这里只做「取 key → 替换 {占位符} → 字符串」。
|
|
20
|
+
// 不依赖 DSH t() 的插值能力,避免行为不一致。
|
|
21
|
+
function fmt(t, key, vars) {
|
|
22
|
+
let s = t(key);
|
|
23
|
+
if (vars) {
|
|
24
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
25
|
+
s = String(s).split(`{${k}}`).join(String(v));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return s;
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
// 官方 DeepSeek Harness 设计系统(dsh-client-ui-theme design-platform.css):
|
|
19
32
|
// 按钮 md=36px 胶囊形 / sm=28px;品牌色 --dsw-alias-brand-primary;
|
|
20
33
|
// hover 走 --dsw-alias-button-*-hover;间距 4px 栅格;正文 13px。
|
|
@@ -31,7 +44,7 @@ const styles = {
|
|
|
31
44
|
warn: { color: 'var(--dsw-alias-state-warn-primary,#b45309)', fontSize: 12, lineHeight: 1.5 },
|
|
32
45
|
};
|
|
33
46
|
|
|
34
|
-
function PocketSettingsTab({ rpcCall }) {
|
|
47
|
+
function PocketSettingsTab({ rpcCall, t }) {
|
|
35
48
|
const [status, setStatus] = useState(null);
|
|
36
49
|
const [busy, setBusy] = useState(false);
|
|
37
50
|
const [error, setError] = useState(null);
|
|
@@ -193,14 +206,14 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
193
206
|
return h('div', { style: styles.card },
|
|
194
207
|
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
|
|
195
208
|
h('div', null,
|
|
196
|
-
h('strong', null, '
|
|
197
|
-
h('div', { style: styles.muted }, '
|
|
209
|
+
h('strong', null, t('title')),
|
|
210
|
+
h('div', { style: styles.muted }, t('subtitle')),
|
|
198
211
|
),
|
|
199
212
|
h('div', { style: { fontSize: 12, color: 'var(--dsw-alias-label-tertiary,#8b93a1)', textAlign: 'right' } },
|
|
200
|
-
h('div', { style: { whiteSpace: 'nowrap' } }, '
|
|
201
|
-
h('div', { style: { whiteSpace: 'nowrap' } }, '
|
|
213
|
+
h('div', { style: { whiteSpace: 'nowrap' } }, t('developer')),
|
|
214
|
+
h('div', { style: { whiteSpace: 'nowrap' } }, t('starAsk')),
|
|
202
215
|
h('a', { href: 'https://github.com/shaobeichen/dsh-pocket', target: '_blank', rel: 'noreferrer', style: { color: 'var(--dsw-alias-brand-primary,#4f6ef7)', fontSize: 12, lineHeight: 1.6, textDecoration: 'underline' } },
|
|
203
|
-
'
|
|
216
|
+
t('starCta')),
|
|
204
217
|
),
|
|
205
218
|
),
|
|
206
219
|
|
|
@@ -209,10 +222,10 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
209
222
|
// 重启后提示(进程在后台运行,停止方法)——左侧蓝色色条(桌面端不会触发本插件的自重启)
|
|
210
223
|
!isDesktop && restartNotice ? h('div', { style: { ...styles.block, borderLeft: '4px solid var(--dsw-alias-brand-primary,#4f6ef7)', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-2,#f3f4f6)', padding: '10px 12px' } },
|
|
211
224
|
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
|
|
212
|
-
h('div', { style: { fontWeight: 600, fontSize: 13 } }, '
|
|
213
|
-
h('button', { style: styles.btn, onClick: () => setRestartNotice(false) }, '
|
|
225
|
+
h('div', { style: { fontWeight: 600, fontSize: 13 } }, t('restarted')),
|
|
226
|
+
h('button', { style: styles.btn, onClick: () => setRestartNotice(false) }, t('ok')),
|
|
214
227
|
),
|
|
215
|
-
h('div', { style: styles.muted, marginTop: 4, wordBreak: 'break-all' },
|
|
228
|
+
h('div', { style: styles.muted, marginTop: 4, wordBreak: 'break-all' }, fmt(t, 'bgHint', { cmd: status?.killHint ?? `lsof -ti :${status?.dshPort ?? 3080} | xargs kill -9` })),
|
|
216
229
|
) : null,
|
|
217
230
|
|
|
218
231
|
// 更新提示——左侧黄色色条(提示有新版本);单状态:有更新/更新中/已更新自动重启,不并存
|
|
@@ -221,85 +234,83 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
221
234
|
h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 } },
|
|
222
235
|
h('div', { style: { fontWeight: 600, fontSize: 13 } },
|
|
223
236
|
updateInfo.updated
|
|
224
|
-
?
|
|
237
|
+
? fmt(t, 'updatedRestart', { ver: updateInfo.current })
|
|
225
238
|
: updateInfo.result === 'ok'
|
|
226
|
-
? (updateInfo.autoRestart ?
|
|
227
|
-
:
|
|
239
|
+
? (updateInfo.autoRestart ? fmt(t, 'updateAutoRestarting', { ver: updateInfo.latest }) : fmt(t, 'updatedOk', { ver: updateInfo.latest }))
|
|
240
|
+
: fmt(t, 'updateAvailable', { ver: updateInfo.latest })),
|
|
228
241
|
updateInfo.result !== 'ok'
|
|
229
|
-
? h('button', { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? '
|
|
242
|
+
? h('button', { style: styles.primary, onClick: runUpdate, disabled: updateInfo.updating }, updateInfo.updating ? t('updating') : fmt(t, 'updateTo', { ver: updateInfo.latest }))
|
|
230
243
|
: updateInfo.autoRestart
|
|
231
|
-
? h('button', { style: styles.btn, disabled: true }, '
|
|
232
|
-
: h('button', { style: styles.primary, onClick: restartPocket, disabled: updateInfo.restarting }, updateInfo.restarting ? '
|
|
244
|
+
? h('button', { style: styles.btn, disabled: true }, t('restartingNow'))
|
|
245
|
+
: h('button', { style: styles.primary, onClick: restartPocket, disabled: updateInfo.restarting }, updateInfo.restarting ? t('restarting') : t('restartNow')),
|
|
233
246
|
),
|
|
234
247
|
h('div', { style: styles.muted, marginTop: 4 },
|
|
235
248
|
updateInfo.updating
|
|
236
|
-
?
|
|
249
|
+
? fmt(t, 'updatingDetail', { s: elapsed(updateInfo.startedAt) })
|
|
237
250
|
: updateInfo.restarting
|
|
238
|
-
?
|
|
251
|
+
? fmt(t, 'restartingDetail', { s: elapsed(updateInfo.startedAt) })
|
|
239
252
|
: updateInfo.result === 'ok'
|
|
240
|
-
? (updateInfo.autoRestart ? '
|
|
241
|
-
: '
|
|
242
|
-
: updateInfo.result === 'fail' ?
|
|
243
|
-
:
|
|
253
|
+
? (updateInfo.autoRestart ? t('updatedAutoDetail')
|
|
254
|
+
: t('updatedRestartDetail'))
|
|
255
|
+
: updateInfo.result === 'fail' ? fmt(t, 'updateFailed', { err: updateInfo.output || t('unknownError') })
|
|
256
|
+
: fmt(t, 'versionRange', { cur: updateInfo.current, latest: updateInfo.latest })),
|
|
244
257
|
) : null,
|
|
245
258
|
|
|
246
259
|
// 局域网
|
|
247
260
|
h('div', { style: styles.block },
|
|
248
|
-
h('div', { style: { fontWeight: 600, fontSize: 13 } }, '
|
|
261
|
+
h('div', { style: { fontWeight: 600, fontSize: 13 } }, t('lanTitle')),
|
|
249
262
|
lanUrl
|
|
250
263
|
? h('div', null,
|
|
251
264
|
h('img', { src: status.lanQr, alt: 'LAN QR', style: styles.qr }),
|
|
252
265
|
h('div', { style: styles.code }, lanUrl),
|
|
253
|
-
h('div', { style: styles.muted }, '
|
|
266
|
+
h('div', { style: styles.muted }, t('lanHint')),
|
|
254
267
|
// 访问密码开关(issue #24):默认开启;关闭后扫码直连(仅同一局域网设备可访问)
|
|
255
268
|
h('div', { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 8 } },
|
|
256
|
-
h('span', { style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } }, '
|
|
269
|
+
h('span', { style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } }, t('lanPin')),
|
|
257
270
|
h('button', {
|
|
258
271
|
style: { ...styles.btn, height: 28, padding: '0 12px', fontSize: 12, fontWeight: status?.lanAuthEnabled !== false ? 600 : 400, background: status?.lanAuthEnabled !== false ? 'var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary,#4f6ef7))' : 'var(--dsw-alias-bg-layer-1,#fff)', color: status?.lanAuthEnabled !== false ? 'var(--dsw-alias-label-primary-foreground, #fff)' : 'var(--dsw-alias-label-primary,inherit)' },
|
|
259
272
|
onClick: () => setLanAuth(true),
|
|
260
|
-
}, '
|
|
273
|
+
}, t('on')),
|
|
261
274
|
h('button', {
|
|
262
275
|
style: { ...styles.btn, height: 28, padding: '0 12px', fontSize: 12, fontWeight: status?.lanAuthEnabled === false ? 600 : 400, background: status?.lanAuthEnabled === false ? 'var(--dsw-alias-state-error-primary,#dc2626)' : 'var(--dsw-alias-bg-layer-1,#fff)', color: status?.lanAuthEnabled === false ? '#fff' : 'var(--dsw-alias-label-primary,inherit)' },
|
|
263
276
|
onClick: () => setLanAuth(false),
|
|
264
|
-
}, '
|
|
277
|
+
}, t('off')),
|
|
265
278
|
),
|
|
266
279
|
status?.lanAuthEnabled !== false
|
|
267
280
|
? h('div', { style: { marginTop: 6, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', lineHeight: 1.5 } },
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
'(手机打开需输入;与公网密码分开)',
|
|
271
|
-
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12, marginLeft: 8 }, onClick: refreshLanPin }, '刷新 | Refresh'),
|
|
281
|
+
fmt(t, 'lanPinValue', { pin: status.lanToken }),
|
|
282
|
+
h('button', { style: { ...styles.btn, height: 26, padding: '0 10px', fontSize: 12, marginLeft: 8 }, onClick: refreshLanPin }, t('refresh')),
|
|
272
283
|
)
|
|
273
284
|
: h('div', { style: { marginTop: 6, fontSize: 12, color: 'var(--dsw-alias-state-warn-primary,#b45309)', lineHeight: 1.5 } },
|
|
274
|
-
|
|
285
|
+
t('lanPinOff')),
|
|
275
286
|
)
|
|
276
|
-
: h('div', { style: styles.muted }, '
|
|
287
|
+
: h('div', { style: styles.muted }, t('lanStarting')),
|
|
277
288
|
),
|
|
278
289
|
|
|
279
290
|
// 公网
|
|
280
291
|
h('div', { style: styles.block },
|
|
281
|
-
h('div', { style: { fontWeight: 600, fontSize: 13 } }, '
|
|
292
|
+
h('div', { style: { fontWeight: 600, fontSize: 13 } }, t('wanTitle')),
|
|
282
293
|
tunnelUrl
|
|
283
294
|
? h('div', null,
|
|
284
295
|
h('img', { src: status.tunnelQr, alt: 'Tunnel QR', style: styles.qr }),
|
|
285
296
|
h('div', { style: styles.code }, tunnelUrl),
|
|
286
|
-
h('div', { style: styles.muted }, '
|
|
297
|
+
h('div', { style: styles.muted }, t('wanHint')),
|
|
287
298
|
status.accessToken
|
|
288
299
|
? h('div', { style: { marginTop: 6, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', lineHeight: 1.5 } },
|
|
289
|
-
|
|
300
|
+
fmt(t, 'wanPin', { pin: status.accessToken }))
|
|
290
301
|
: null,
|
|
291
|
-
h('button', { style: styles.btn, onClick: stopTunnel }, '
|
|
302
|
+
h('button', { style: styles.btn, onClick: stopTunnel }, t('stopTunnel')),
|
|
292
303
|
)
|
|
293
304
|
: h('div', null,
|
|
294
|
-
h('button', { style: { ...styles.primary, margin: '8px 0' }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy ? '
|
|
305
|
+
h('button', { style: { ...styles.primary, margin: '8px 0' }, onClick: startTunnel, disabled: busy || tunnelStarting }, busy ? t('opening') : t('enable')),
|
|
295
306
|
tunnelStarting
|
|
296
307
|
? h('div', { style: { marginTop: 4, fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)' } },
|
|
297
308
|
tunnelPhase === 'downloading'
|
|
298
|
-
?
|
|
299
|
-
:
|
|
309
|
+
? fmt(t, 'downloading', { s: elapsed(tunnelStateStarted) })
|
|
310
|
+
: fmt(t, 'connecting', { s: elapsed(tunnelStateStarted), suffix: elapsed(tunnelStateStarted) > 30 ? t('slowHint') : '' }))
|
|
300
311
|
: tunnelPhase === 'error'
|
|
301
312
|
? h('div', { style: { marginTop: 4, fontSize: 12, color: 'var(--dsw-alias-state-error-primary,#dc2626)' } },
|
|
302
|
-
|
|
313
|
+
fmt(t, 'error', { detail: tunnelStateDetail || t('unknownError') }))
|
|
303
314
|
: null,
|
|
304
315
|
),
|
|
305
316
|
),
|
|
@@ -309,7 +320,7 @@ function PocketSettingsTab({ rpcCall }) {
|
|
|
309
320
|
// 页面最底部:反馈入口
|
|
310
321
|
h('div', { style: { ...styles.block, textAlign: 'center' } },
|
|
311
322
|
h('a', { href: 'https://github.com/shaobeichen/dsh-pocket/issues', target: '_blank', rel: 'noreferrer', style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary,#6b7280)', textDecoration: 'none' } },
|
|
312
|
-
'
|
|
323
|
+
t('feedback')),
|
|
313
324
|
),
|
|
314
325
|
);
|
|
315
326
|
}
|
|
@@ -321,6 +332,10 @@ export function apply(ctx) {
|
|
|
321
332
|
const rpcCall = (endpoint, payload, signal) =>
|
|
322
333
|
ctx.connection.rpc.call(POCKET_RPC_CHANNEL, endpoint, payload, signal);
|
|
323
334
|
|
|
335
|
+
// 设置页签接入 DSH 本地化:注册 pocket 词典(zh/en),并绑定一个随当前 locale 切换的 t()。
|
|
336
|
+
const translate = ctx.locale.bind(POCKET_NS);
|
|
337
|
+
ctx.effect(() => ctx.locale.register(POCKET_NS, { zh: POCKET_ZH, en: POCKET_EN }), 'dsh-pocket: pocket locale dictionaries');
|
|
338
|
+
|
|
324
339
|
// 设置一级入口(与 通用设置/模型/插件 同级,order 1 = 通用之后、最外层)
|
|
325
340
|
ctx.slots.inject('settings.section', () =>
|
|
326
341
|
ctx.slots.register(
|
|
@@ -328,8 +343,8 @@ export function apply(ctx) {
|
|
|
328
343
|
name: 'settings.section',
|
|
329
344
|
id: 'pocket',
|
|
330
345
|
order: 1,
|
|
331
|
-
label: () => '
|
|
332
|
-
inject: () => ({ rpcCall }),
|
|
346
|
+
label: () => translate('section'),
|
|
347
|
+
inject: () => ({ rpcCall, t: translate }),
|
|
333
348
|
},
|
|
334
349
|
PocketSettingsTab,
|
|
335
350
|
),
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// dsh-pocket 设置页签 i18n 词典(与 client/mobile/locales.ts 同款:zh 为源真,en 为译文)。
|
|
2
|
+
// 需要新增字符串时:先加到 zh(key-set 唯一来源),再补 en(key 必须与 zh 完全一致)。
|
|
3
|
+
export const NS = 'pocket'
|
|
4
|
+
|
|
5
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
6
|
+
export const zh = {
|
|
7
|
+
'section': '手机访问',
|
|
8
|
+
'title': '📱 手机访问',
|
|
9
|
+
'subtitle': '手机扫码打开的就是电脑上的这个界面,实时同步',
|
|
10
|
+
'developer': '开发者:程序员少北晨',
|
|
11
|
+
'starAsk': '⭐ 顺手留颗 Star,作者能高兴一整天',
|
|
12
|
+
'starCta': '行,给你一颗 Star',
|
|
13
|
+
'restarted': '🔄 已重启',
|
|
14
|
+
'ok': '知道了',
|
|
15
|
+
'bgHint': '进程在后台运行(不挂终端)。如需停止:{cmd}',
|
|
16
|
+
'updatedRestart': '✅ 已更新 v{ver},重启生效',
|
|
17
|
+
'updateAutoRestarting': '✅ 已更新 v{ver},正在自动重启…',
|
|
18
|
+
'updatedOk': '✅ 已更新 v{ver}',
|
|
19
|
+
'updateAvailable': '📦 新版本 v{ver}',
|
|
20
|
+
'updating': '更新中…',
|
|
21
|
+
'updateTo': '更新到 v{ver}',
|
|
22
|
+
'restartingNow': '正在重启生效…',
|
|
23
|
+
'restarting': '重启中…',
|
|
24
|
+
'restartNow': '🔄 重启 dsh web 生效',
|
|
25
|
+
'updatingDetail': '⏳ 更新中(通常 1-2 分钟)· 已等待 {s} 秒',
|
|
26
|
+
'restartingDetail': '⏳ 正在重启生效(通常 10-30 秒)· 已等待 {s} 秒',
|
|
27
|
+
'updatedAutoDetail': '✅ 已更新,正在自动重启生效,请稍候刷新',
|
|
28
|
+
'updatedRestartDetail': '✅ 已更新,重启 dsh web 生效',
|
|
29
|
+
'updateFailed': '❌ 失败:{err}(手动更新:dsh plugin --profile web update dsh-pocket --latest -w)',
|
|
30
|
+
'versionRange': '当前 v{cur} → 最新 v{latest}',
|
|
31
|
+
'lanTitle': '📶 局域网(同一 WiFi)',
|
|
32
|
+
'lanHint': '手机连接同一 WiFi 后扫码即可打开',
|
|
33
|
+
'lanPin': '局域网访问密码',
|
|
34
|
+
'on': '开',
|
|
35
|
+
'off': '关',
|
|
36
|
+
'lanPinValue': '🔐 访问密码:{pin}(手机打开需输入;与公网密码分开)',
|
|
37
|
+
'refresh': '刷新',
|
|
38
|
+
'lanPinOff': '🔓 密码已关闭:扫码直连,无需密码(仅同一局域网设备可访问;公网仍要密码)',
|
|
39
|
+
'lanStarting': '代理未就绪…',
|
|
40
|
+
'wanTitle': '🌐 公网(人在外面)',
|
|
41
|
+
'wanHint': '任何网络扫码即用(URL 每次重启自动换新)',
|
|
42
|
+
'wanPin': '🔐 访问密码:{pin}(每次开启公网变新;手机打开链接需输入此密码)',
|
|
43
|
+
'stopTunnel': '关闭公网',
|
|
44
|
+
'enable': '开启公网访问',
|
|
45
|
+
'opening': '开启中…',
|
|
46
|
+
'downloading': '⏳ 下载 cloudflared(首次约 20-50MB,通常 1-2 分钟;之后秒开)· 已等待 {s} 秒',
|
|
47
|
+
'connecting': '⏳ 连接 Cloudflare 边缘(通常 5-30 秒)· 已等待 {s} 秒{suffix}',
|
|
48
|
+
'slowHint': ' — 有点久?检查是否开着代理/VPN(Clash TUN 等)',
|
|
49
|
+
'error': '❌ 开启失败:{detail}(可重试;若是代理/VPN 问题见 README 排障)',
|
|
50
|
+
'unknownError': '未知错误',
|
|
51
|
+
'feedback': '有问题?欢迎到 GitHub Issues 反馈 🙏',
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** English dictionary, key-identical to the Chinese source of truth. */
|
|
55
|
+
export const en = {
|
|
56
|
+
'section': 'Phone access',
|
|
57
|
+
'title': '📱 Phone access',
|
|
58
|
+
'subtitle': 'The phone shows this exact screen, live',
|
|
59
|
+
'developer': 'Developer: 少北晨 (shaobeichen)',
|
|
60
|
+
'starAsk': '⭐ Drop a Star if it helped — it makes the author’s day',
|
|
61
|
+
'starCta': '★ Give a Star',
|
|
62
|
+
'restarted': '🔄 Restarted',
|
|
63
|
+
'ok': 'Got it',
|
|
64
|
+
'bgHint': 'Running in the background (not attached to a terminal). To stop: {cmd}',
|
|
65
|
+
'updatedRestart': '✅ Updated to v{ver} — restart to apply',
|
|
66
|
+
'updateAutoRestarting': '✅ Updated to v{ver} — auto-restarting…',
|
|
67
|
+
'updatedOk': '✅ Updated to v{ver}',
|
|
68
|
+
'updateAvailable': '📦 Update available: v{ver}',
|
|
69
|
+
'updating': 'Updating…',
|
|
70
|
+
'updateTo': 'Update to v{ver}',
|
|
71
|
+
'restartingNow': 'Restarting to apply…',
|
|
72
|
+
'restarting': 'Restarting…',
|
|
73
|
+
'restartNow': '🔄 Restart dsh web now',
|
|
74
|
+
'updatingDetail': '⏳ Updating (usually 1-2 min) · {s}s elapsed',
|
|
75
|
+
'restartingDetail': '⏳ Restarting to apply (usually 10-30s) · {s}s elapsed',
|
|
76
|
+
'updatedAutoDetail': '✅ Updated — auto-restarting in progress, refresh shortly',
|
|
77
|
+
'updatedRestartDetail': '✅ Updated — restart dsh web to apply',
|
|
78
|
+
'updateFailed': '❌ Failed: {err} (manual update: dsh plugin --profile web update dsh-pocket --latest -w)',
|
|
79
|
+
'versionRange': 'Current v{cur} → latest v{latest}',
|
|
80
|
+
'lanTitle': '📶 LAN (same Wi-Fi)',
|
|
81
|
+
'lanHint': 'Scan to open once your phone is on the same Wi-Fi',
|
|
82
|
+
'lanPin': 'LAN access PIN',
|
|
83
|
+
'on': 'On',
|
|
84
|
+
'off': 'Off',
|
|
85
|
+
'lanPinValue': '🔐 PIN: {pin} (required on the phone; separate from the public PIN)',
|
|
86
|
+
'refresh': 'Refresh',
|
|
87
|
+
'lanPinOff': '🔓 PIN off — scan & go, no PIN (LAN devices only; public still requires PIN)',
|
|
88
|
+
'lanStarting': 'Proxy starting…',
|
|
89
|
+
'wanTitle': '🌐 Anywhere (public)',
|
|
90
|
+
'wanHint': 'Scan from any network (the URL changes on every restart)',
|
|
91
|
+
'wanPin': '🔐 PIN: {pin} (changes each time the tunnel is enabled; required on the phone)',
|
|
92
|
+
'stopTunnel': 'Stop',
|
|
93
|
+
'enable': 'Enable anywhere',
|
|
94
|
+
'opening': 'Enabling…',
|
|
95
|
+
'downloading': '⏳ Downloading cloudflared (first run ~20-50MB, usually 1-2 min; instant afterward) · {s}s elapsed',
|
|
96
|
+
'connecting': '⏳ Connecting to Cloudflare edge (usually 5-30s) · {s}s elapsed{suffix}',
|
|
97
|
+
'slowHint': ' — taking long? Check for a proxy/VPN (e.g., Clash TUN)',
|
|
98
|
+
'error': '❌ Failed to enable: {detail} (you can retry; for proxy/VPN issues see the README)',
|
|
99
|
+
'unknownError': 'unknown error',
|
|
100
|
+
'feedback': '🙏 Questions? Open an issue on GitHub',
|
|
101
|
+
}
|
package/package.json
CHANGED