feat(ui): translate channels views and update terminology
- Keep 'Token' and 'Skills' in English per user preference - Add i18n to channels.ts, channels.shared.ts, channels.whatsapp.ts - Add WhatsApp-specific translations (linked, authAge, showQr, etc.) - Update nav.tabs.skills to 'Skills' - Update config.sections.skills to 'Skills'
This commit is contained in:
parent
edeb35dbcc
commit
e1066b0a42
@ -186,10 +186,13 @@ export const enUS = {
|
|||||||
connected: "Connected",
|
connected: "Connected",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// General
|
||||||
|
accounts: "Accounts",
|
||||||
|
|
||||||
// WhatsApp
|
// WhatsApp
|
||||||
whatsapp: {
|
whatsapp: {
|
||||||
title: "WhatsApp",
|
title: "WhatsApp",
|
||||||
desc: "WhatsApp via Baileys (multi-device).",
|
desc: "Link WhatsApp Web and monitor connection health.",
|
||||||
start: "Start",
|
start: "Start",
|
||||||
relink: "Relink",
|
relink: "Relink",
|
||||||
logout: "Logout",
|
logout: "Logout",
|
||||||
@ -197,6 +200,12 @@ export const enUS = {
|
|||||||
linking: "Linking…",
|
linking: "Linking…",
|
||||||
waitingForQr: "Waiting for QR code…",
|
waitingForQr: "Waiting for QR code…",
|
||||||
notConfigured: "Not configured.",
|
notConfigured: "Not configured.",
|
||||||
|
linked: "Linked",
|
||||||
|
lastConnect: "Last connect",
|
||||||
|
authAge: "Auth age",
|
||||||
|
showQr: "Show QR",
|
||||||
|
waitForScan: "Wait for scan",
|
||||||
|
working: "Working…",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Telegram
|
// Telegram
|
||||||
|
|||||||
@ -78,7 +78,7 @@ export const zhTW = {
|
|||||||
instances: "實例",
|
instances: "實例",
|
||||||
sessions: "工作階段",
|
sessions: "工作階段",
|
||||||
cron: "排程任務",
|
cron: "排程任務",
|
||||||
skills: "技能",
|
skills: "Skills",
|
||||||
nodes: "節點",
|
nodes: "節點",
|
||||||
chat: "對話",
|
chat: "對話",
|
||||||
config: "組態",
|
config: "組態",
|
||||||
@ -91,7 +91,7 @@ export const zhTW = {
|
|||||||
instances: "來自已連線用戶端與節點的存在訊號。",
|
instances: "來自已連線用戶端與節點的存在訊號。",
|
||||||
sessions: "檢視進行中的工作階段並調整個別設定。",
|
sessions: "檢視進行中的工作階段並調整個別設定。",
|
||||||
cron: "排程喚醒與週期性代理執行。",
|
cron: "排程喚醒與週期性代理執行。",
|
||||||
skills: "管理技能的啟用狀態與 API 金鑰。",
|
skills: "管理 Skills 的啟用狀態與 API 金鑰。",
|
||||||
nodes: "已配對的裝置、功能與指令權限。",
|
nodes: "已配對的裝置、功能與指令權限。",
|
||||||
chat: "直接與閘道器對話,進行快速操作。",
|
chat: "直接與閘道器對話,進行快速操作。",
|
||||||
config: "安全地編輯 ~/.clawdbot/moltbot.json 設定檔。",
|
config: "安全地編輯 ~/.clawdbot/moltbot.json 設定檔。",
|
||||||
@ -107,7 +107,7 @@ export const zhTW = {
|
|||||||
gatewayAccess: "閘道器連線",
|
gatewayAccess: "閘道器連線",
|
||||||
gatewayAccessDesc: "控制台連線位置與認證方式。",
|
gatewayAccessDesc: "控制台連線位置與認證方式。",
|
||||||
websocketUrl: "WebSocket 網址",
|
websocketUrl: "WebSocket 網址",
|
||||||
gatewayToken: "閘道器 Token",
|
gatewayToken: "Gateway Token",
|
||||||
password: "密碼(不會儲存)",
|
password: "密碼(不會儲存)",
|
||||||
passwordPlaceholder: "系統或共用密碼",
|
passwordPlaceholder: "系統或共用密碼",
|
||||||
defaultSessionKey: "預設工作階段金鑰",
|
defaultSessionKey: "預設工作階段金鑰",
|
||||||
@ -193,10 +193,13 @@ export const zhTW = {
|
|||||||
connected: "已連線",
|
connected: "已連線",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 一般
|
||||||
|
accounts: "帳號",
|
||||||
|
|
||||||
// WhatsApp
|
// WhatsApp
|
||||||
whatsapp: {
|
whatsapp: {
|
||||||
title: "WhatsApp",
|
title: "WhatsApp",
|
||||||
desc: "透過 Baileys 連接 WhatsApp(多裝置)。",
|
desc: "連結 WhatsApp Web 並監控連線狀態。",
|
||||||
start: "開始",
|
start: "開始",
|
||||||
relink: "重新連結",
|
relink: "重新連結",
|
||||||
logout: "登出",
|
logout: "登出",
|
||||||
@ -204,6 +207,12 @@ export const zhTW = {
|
|||||||
linking: "連結中…",
|
linking: "連結中…",
|
||||||
waitingForQr: "等待 QR Code…",
|
waitingForQr: "等待 QR Code…",
|
||||||
notConfigured: "尚未設定。",
|
notConfigured: "尚未設定。",
|
||||||
|
linked: "已連結",
|
||||||
|
lastConnect: "上次連線",
|
||||||
|
authAge: "認證時長",
|
||||||
|
showQr: "顯示 QR",
|
||||||
|
waitForScan: "等待掃描",
|
||||||
|
working: "處理中…",
|
||||||
},
|
},
|
||||||
|
|
||||||
// Telegram
|
// Telegram
|
||||||
@ -388,12 +397,12 @@ export const zhTW = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// 技能頁面
|
// Skills 頁面
|
||||||
skills: {
|
skills: {
|
||||||
title: "技能",
|
title: "Skills",
|
||||||
desc: "管理內建與已安裝的技能。",
|
desc: "管理內建與已安裝的 Skills。",
|
||||||
noSkills: "找不到技能。",
|
noSkills: "找不到 Skills。",
|
||||||
filter: "篩選技能",
|
filter: "篩選 Skills",
|
||||||
shown: "個顯示中",
|
shown: "個顯示中",
|
||||||
apiKey: "API 金鑰",
|
apiKey: "API 金鑰",
|
||||||
saveKey: "儲存金鑰",
|
saveKey: "儲存金鑰",
|
||||||
@ -417,7 +426,7 @@ export const zhTW = {
|
|||||||
desc: "已配對的裝置與即時連結。",
|
desc: "已配對的裝置與即時連結。",
|
||||||
noNodes: "找不到節點。",
|
noNodes: "找不到節點。",
|
||||||
devices: "裝置",
|
devices: "裝置",
|
||||||
devicesDesc: "配對請求與角色權杖。",
|
devicesDesc: "配對請求與角色 Token。",
|
||||||
noDevices: "沒有已配對的裝置。",
|
noDevices: "沒有已配對的裝置。",
|
||||||
approve: "核准",
|
approve: "核准",
|
||||||
reject: "拒絕",
|
reject: "拒絕",
|
||||||
@ -427,8 +436,8 @@ export const zhTW = {
|
|||||||
paired: "已配對",
|
paired: "已配對",
|
||||||
approved: "已核准",
|
approved: "已核准",
|
||||||
offline: "離線",
|
offline: "離線",
|
||||||
tokens: "權杖",
|
tokens: "Token",
|
||||||
tokensNone: "權杖:無",
|
tokensNone: "Token:無",
|
||||||
role: "角色",
|
role: "角色",
|
||||||
requested: "請求於",
|
requested: "請求於",
|
||||||
repair: "修復",
|
repair: "修復",
|
||||||
@ -530,7 +539,7 @@ export const zhTW = {
|
|||||||
messages: "訊息",
|
messages: "訊息",
|
||||||
commands: "指令",
|
commands: "指令",
|
||||||
hooks: "鉤子",
|
hooks: "鉤子",
|
||||||
skills: "技能",
|
skills: "Skills",
|
||||||
tools: "工具",
|
tools: "工具",
|
||||||
gateway: "閘道器",
|
gateway: "閘道器",
|
||||||
wizard: "設定精靈",
|
wizard: "設定精靈",
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { html, nothing } from "lit";
|
import { html, nothing } from "lit";
|
||||||
|
|
||||||
|
import { t } from "../../i18n";
|
||||||
import type { ChannelAccountSnapshot } from "../types";
|
import type { ChannelAccountSnapshot } from "../types";
|
||||||
import type { ChannelKey, ChannelsProps } from "./channels.types";
|
import type { ChannelKey, ChannelsProps } from "./channels.types";
|
||||||
|
|
||||||
export function formatDuration(ms?: number | null) {
|
export function formatDuration(ms?: number | null) {
|
||||||
if (!ms && ms !== 0) return "n/a";
|
if (!ms && ms !== 0) return t("common.na");
|
||||||
const sec = Math.round(ms / 1000);
|
const sec = Math.round(ms / 1000);
|
||||||
if (sec < 60) return `${sec}s`;
|
if (sec < 60) return `${sec}s`;
|
||||||
const min = Math.round(sec / 60);
|
const min = Math.round(sec / 60);
|
||||||
@ -41,5 +42,5 @@ export function renderChannelAccountCount(
|
|||||||
) {
|
) {
|
||||||
const count = getChannelAccountCount(key, channelAccounts);
|
const count = getChannelAccountCount(key, channelAccounts);
|
||||||
if (count < 2) return nothing;
|
if (count < 2) return nothing;
|
||||||
return html`<div class="account-count">Accounts (${count})</div>`;
|
return html`<div class="account-count">${t("channels.accounts")} (${count})</div>`;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { html, nothing } from "lit";
|
import { html, nothing } from "lit";
|
||||||
|
|
||||||
|
import { t } from "../../i18n";
|
||||||
import { formatAgo } from "../format";
|
import { formatAgo } from "../format";
|
||||||
import type {
|
import type {
|
||||||
ChannelAccountSnapshot,
|
ChannelAccountSnapshot,
|
||||||
@ -77,10 +78,10 @@ export function renderChannels(props: ChannelsProps) {
|
|||||||
<section class="card" style="margin-top: 18px;">
|
<section class="card" style="margin-top: 18px;">
|
||||||
<div class="row" style="justify-content: space-between;">
|
<div class="row" style="justify-content: space-between;">
|
||||||
<div>
|
<div>
|
||||||
<div class="card-title">Channel health</div>
|
<div class="card-title">${t("channels.health")}</div>
|
||||||
<div class="card-sub">Channel status snapshots from the gateway.</div>
|
<div class="card-sub">${t("channels.healthDesc")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="muted">${props.lastSuccessAt ? formatAgo(props.lastSuccessAt) : "n/a"}</div>
|
<div class="muted">${props.lastSuccessAt ? formatAgo(props.lastSuccessAt) : t("common.na")}</div>
|
||||||
</div>
|
</div>
|
||||||
${props.lastError
|
${props.lastError
|
||||||
? html`<div class="callout danger" style="margin-top: 12px;">
|
? html`<div class="callout danger" style="margin-top: 12px;">
|
||||||
@ -88,7 +89,7 @@ export function renderChannels(props: ChannelsProps) {
|
|||||||
</div>`
|
</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
<pre class="code-block" style="margin-top: 12px;">
|
<pre class="code-block" style="margin-top: 12px;">
|
||||||
${props.snapshot ? JSON.stringify(props.snapshot, null, 2) : "No snapshot yet."}
|
${props.snapshot ? JSON.stringify(props.snapshot, null, 2) : t("channels.noSnapshot")}
|
||||||
</pre>
|
</pre>
|
||||||
</section>
|
</section>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { html, nothing } from "lit";
|
import { html, nothing } from "lit";
|
||||||
|
|
||||||
|
import { t } from "../../i18n";
|
||||||
import { formatAgo } from "../format";
|
import { formatAgo } from "../format";
|
||||||
import type { WhatsAppStatus } from "../types";
|
import type { WhatsAppStatus } from "../types";
|
||||||
import type { ChannelsProps } from "./channels.types";
|
import type { ChannelsProps } from "./channels.types";
|
||||||
@ -16,46 +17,46 @@ export function renderWhatsAppCard(params: {
|
|||||||
return html`
|
return html`
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">WhatsApp</div>
|
<div class="card-title">WhatsApp</div>
|
||||||
<div class="card-sub">Link WhatsApp Web and monitor connection health.</div>
|
<div class="card-sub">${t("channels.whatsapp.desc")}</div>
|
||||||
${accountCountLabel}
|
${accountCountLabel}
|
||||||
|
|
||||||
<div class="status-list" style="margin-top: 16px;">
|
<div class="status-list" style="margin-top: 16px;">
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Configured</span>
|
<span class="label">${t("channels.labels.configured")}</span>
|
||||||
<span>${whatsapp?.configured ? "Yes" : "No"}</span>
|
<span>${whatsapp?.configured ? t("common.yes") : t("common.no")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Linked</span>
|
<span class="label">${t("channels.whatsapp.linked")}</span>
|
||||||
<span>${whatsapp?.linked ? "Yes" : "No"}</span>
|
<span>${whatsapp?.linked ? t("common.yes") : t("common.no")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Running</span>
|
<span class="label">${t("channels.labels.running")}</span>
|
||||||
<span>${whatsapp?.running ? "Yes" : "No"}</span>
|
<span>${whatsapp?.running ? t("common.yes") : t("common.no")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Connected</span>
|
<span class="label">${t("channels.labels.connected")}</span>
|
||||||
<span>${whatsapp?.connected ? "Yes" : "No"}</span>
|
<span>${whatsapp?.connected ? t("common.yes") : t("common.no")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Last connect</span>
|
<span class="label">${t("channels.whatsapp.lastConnect")}</span>
|
||||||
<span>
|
<span>
|
||||||
${whatsapp?.lastConnectedAt
|
${whatsapp?.lastConnectedAt
|
||||||
? formatAgo(whatsapp.lastConnectedAt)
|
? formatAgo(whatsapp.lastConnectedAt)
|
||||||
: "n/a"}
|
: t("common.na")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Last message</span>
|
<span class="label">${t("channels.lastInbound")}</span>
|
||||||
<span>
|
<span>
|
||||||
${whatsapp?.lastMessageAt ? formatAgo(whatsapp.lastMessageAt) : "n/a"}
|
${whatsapp?.lastMessageAt ? formatAgo(whatsapp.lastMessageAt) : t("common.na")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">Auth age</span>
|
<span class="label">${t("channels.whatsapp.authAge")}</span>
|
||||||
<span>
|
<span>
|
||||||
${whatsapp?.authAgeMs != null
|
${whatsapp?.authAgeMs != null
|
||||||
? formatDuration(whatsapp.authAgeMs)
|
? formatDuration(whatsapp.authAgeMs)
|
||||||
: "n/a"}
|
: t("common.na")}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -84,31 +85,31 @@ export function renderWhatsAppCard(params: {
|
|||||||
?disabled=${props.whatsappBusy}
|
?disabled=${props.whatsappBusy}
|
||||||
@click=${() => props.onWhatsAppStart(false)}
|
@click=${() => props.onWhatsAppStart(false)}
|
||||||
>
|
>
|
||||||
${props.whatsappBusy ? "Working…" : "Show QR"}
|
${props.whatsappBusy ? t("channels.whatsapp.working") : t("channels.whatsapp.showQr")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn"
|
||||||
?disabled=${props.whatsappBusy}
|
?disabled=${props.whatsappBusy}
|
||||||
@click=${() => props.onWhatsAppStart(true)}
|
@click=${() => props.onWhatsAppStart(true)}
|
||||||
>
|
>
|
||||||
Relink
|
${t("channels.whatsapp.relink")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn"
|
||||||
?disabled=${props.whatsappBusy}
|
?disabled=${props.whatsappBusy}
|
||||||
@click=${() => props.onWhatsAppWait()}
|
@click=${() => props.onWhatsAppWait()}
|
||||||
>
|
>
|
||||||
Wait for scan
|
${t("channels.whatsapp.waitForScan")}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn danger"
|
class="btn danger"
|
||||||
?disabled=${props.whatsappBusy}
|
?disabled=${props.whatsappBusy}
|
||||||
@click=${() => props.onWhatsAppLogout()}
|
@click=${() => props.onWhatsAppLogout()}
|
||||||
>
|
>
|
||||||
Logout
|
${t("channels.whatsapp.logout")}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn" @click=${() => props.onRefresh(true)}>
|
<button class="btn" @click=${() => props.onRefresh(true)}>
|
||||||
Refresh
|
${t("common.refresh")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user