From 0622f2c752c16fe2d3e2d5a974f4853b8ca1e5ca Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 29 Jan 2026 10:29:30 +0000 Subject: [PATCH] feat(ui): translate main component strings to Chinese - Add i18n to app-render.ts (gateway disconnected message) - Add i18n to app-render.helpers.ts (theme, chat controls, language selector) - Add i18n to app-channels.ts (Nostr profile messages) - Add translation keys for theme, chat controls, gateway, and nostrProfile https://claude.ai/code/session_01UK3kVX7BRyE1zEHVh3vrFY --- ui/src/i18n/locales/en-US.ts | 27 +++++++++++++++++++++++++++ ui/src/i18n/locales/zh-TW.ts | 27 +++++++++++++++++++++++++++ ui/src/ui/app-channels.ts | 13 +++++++------ ui/src/ui/app-render.helpers.ts | 24 ++++++++++++------------ ui/src/ui/app-render.ts | 2 +- 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/ui/src/i18n/locales/en-US.ts b/ui/src/i18n/locales/en-US.ts index 99346320d..60e268ec4 100644 --- a/ui/src/i18n/locales/en-US.ts +++ b/ui/src/i18n/locales/en-US.ts @@ -687,6 +687,33 @@ export const enUS = { light: "Light", dark: "Dark", system: "System", + ariaLabel: "Theme", + systemAriaLabel: "System theme", + lightAriaLabel: "Light theme", + darkAriaLabel: "Dark theme", + }, + + // Chat controls + chatControls: { + disabledDuringOnboarding: "Disabled during onboarding", + toggleThinking: "Toggle assistant thinking/working output", + toggleFocusMode: "Toggle focus mode (hide sidebar + page header)", + selectLanguage: "Select language", + }, + + // Gateway connection + gateway: { + disconnected: "Disconnected from gateway.", + }, + + // Nostr profile messages + nostrProfile: { + publishFailed: "Profile publish failed on all relays.", + publishSuccess: "Profile published to relays.", + updateFailed: "Profile update failed", + importFailed: "Profile import failed", + importedFromRelays: "Profile imported from relays. Review and publish.", + importedReviewPublish: "Profile imported. Review and publish.", }, // Time/date formatting diff --git a/ui/src/i18n/locales/zh-TW.ts b/ui/src/i18n/locales/zh-TW.ts index 88cde04d6..ba43dfeff 100644 --- a/ui/src/i18n/locales/zh-TW.ts +++ b/ui/src/i18n/locales/zh-TW.ts @@ -694,6 +694,33 @@ export const zhTW = { light: "淺色", dark: "深色", system: "跟隨系統", + ariaLabel: "主題", + systemAriaLabel: "跟隨系統主題", + lightAriaLabel: "淺色主題", + darkAriaLabel: "深色主題", + }, + + // 對話控制 + chatControls: { + disabledDuringOnboarding: "引導期間已停用", + toggleThinking: "切換助手思考/工作輸出", + toggleFocusMode: "切換專注模式(隱藏側邊欄和頁首)", + selectLanguage: "選擇語言", + }, + + // 閘道器連線 + gateway: { + disconnected: "已與閘道器斷線。", + }, + + // Nostr 個人檔案訊息 + nostrProfile: { + publishFailed: "個人檔案發布至所有中繼站失敗。", + publishSuccess: "個人檔案已發布至中繼站。", + updateFailed: "個人檔案更新失敗", + importFailed: "個人檔案匯入失敗", + importedFromRelays: "已從中繼站匯入個人檔案。請檢視並發布。", + importedReviewPublish: "已匯入個人檔案。請檢視並發布。", }, // 時間/日期格式 diff --git a/ui/src/ui/app-channels.ts b/ui/src/ui/app-channels.ts index 91ff734ed..193a8ad9c 100644 --- a/ui/src/ui/app-channels.ts +++ b/ui/src/ui/app-channels.ts @@ -8,6 +8,7 @@ import { loadConfig, saveConfig } from "./controllers/config"; import type { MoltbotApp } from "./app"; import type { NostrProfile } from "./types"; import { createNostrProfileFormState } from "./views/channels.nostr-profile-form"; +import { t } from "../i18n"; export async function handleWhatsAppStart(host: MoltbotApp, force: boolean) { await startWhatsAppLogin(host, force); @@ -142,7 +143,7 @@ export async function handleNostrProfileSave(host: MoltbotApp) { host.nostrProfileFormState = { ...state, saving: false, - error: "Profile publish failed on all relays.", + error: t("nostrProfile.publishFailed"), success: null, }; return; @@ -152,7 +153,7 @@ export async function handleNostrProfileSave(host: MoltbotApp) { ...state, saving: false, error: null, - success: "Profile published to relays.", + success: t("nostrProfile.publishSuccess"), fieldErrors: {}, original: { ...state.values }, }; @@ -161,7 +162,7 @@ export async function handleNostrProfileSave(host: MoltbotApp) { host.nostrProfileFormState = { ...state, saving: false, - error: `Profile update failed: ${String(err)}`, + error: `${t("nostrProfile.updateFailed")}: ${String(err)}`, success: null, }; } @@ -214,8 +215,8 @@ export async function handleNostrProfileImport(host: MoltbotApp) { values: nextValues, error: null, success: data.saved - ? "Profile imported from relays. Review and publish." - : "Profile imported. Review and publish.", + ? t("nostrProfile.importedFromRelays") + : t("nostrProfile.importedReviewPublish"), showAdvanced, }; @@ -226,7 +227,7 @@ export async function handleNostrProfileImport(host: MoltbotApp) { host.nostrProfileFormState = { ...state, importing: false, - error: `Profile import failed: ${String(err)}`, + error: `${t("nostrProfile.importFailed")}: ${String(err)}`, success: null, }; } diff --git a/ui/src/ui/app-render.helpers.ts b/ui/src/ui/app-render.helpers.ts index da0d26bfc..dfb03d3dc 100644 --- a/ui/src/ui/app-render.helpers.ts +++ b/ui/src/ui/app-render.helpers.ts @@ -107,8 +107,8 @@ export function renderChatControls(state: AppViewState) { }} aria-pressed=${showThinking} title=${disableThinkingToggle - ? "Disabled during onboarding" - : "Toggle assistant thinking/working output"} + ? t("chatControls.disabledDuringOnboarding") + : t("chatControls.toggleThinking")} > ${icons.brain} @@ -124,8 +124,8 @@ export function renderChatControls(state: AppViewState) { }} aria-pressed=${focusActive} title=${disableFocusToggle - ? "Disabled during onboarding" - : "Toggle focus mode (hide sidebar + page header)"} + ? t("chatControls.disabledDuringOnboarding") + : t("chatControls.toggleFocusMode")} > ${focusIcon} @@ -172,14 +172,14 @@ export function renderThemeToggle(state: AppViewState) { return html`
-
+
@@ -187,8 +187,8 @@ export function renderThemeToggle(state: AppViewState) { class="theme-toggle__button ${state.theme === "light" ? "active" : ""}" @click=${applyTheme("light")} aria-pressed=${state.theme === "light"} - aria-label="Light theme" - title="Light" + aria-label="${t("theme.lightAriaLabel")}" + title="${t("theme.light")}" > ${renderSunIcon()} @@ -196,8 +196,8 @@ export function renderThemeToggle(state: AppViewState) { class="theme-toggle__button ${state.theme === "dark" ? "active" : ""}" @click=${applyTheme("dark")} aria-pressed=${state.theme === "dark"} - aria-label="Dark theme" - title="Dark" + aria-label="${t("theme.darkAriaLabel")}" + title="${t("theme.dark")}" > ${renderMoonIcon()} @@ -263,7 +263,7 @@ export function renderLanguageSwitcher() { class="language-switcher__select" .value=${currentLocale} @change=${handleChange} - aria-label="Select language" + aria-label="${t("chatControls.selectLanguage")}" > ${locales.map( (locale) => html` diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts index e7567d3e3..79983aa44 100644 --- a/ui/src/ui/app-render.ts +++ b/ui/src/ui/app-render.ts @@ -106,7 +106,7 @@ export function renderApp(state: AppViewState) { const presenceCount = state.presenceEntries.length; const sessionsCount = state.sessionsResult?.count ?? null; const cronNext = state.cronStatus?.nextWakeAtMs ?? null; - const chatDisabledReason = state.connected ? null : "Disconnected from gateway."; + const chatDisabledReason = state.connected ? null : t("gateway.disconnected"); const isChat = state.tab === "chat"; const chatFocus = isChat && (state.settings.chatFocusMode || state.onboarding); const showThinking = state.onboarding ? false : state.settings.chatShowThinking;