diff --git a/application/i18n/locales/en/core.ts b/application/i18n/locales/en/core.ts index a0fb1d6e..1b06e773 100644 --- a/application/i18n/locales/en/core.ts +++ b/application/i18n/locales/en/core.ts @@ -312,6 +312,15 @@ export const enCoreMessages: Messages = { 'settings.terminal.font.size.desc': 'Terminal text size', 'settings.terminal.font.weight': 'Font weight', 'settings.terminal.font.weight.desc': 'Weight for regular text (100-900)', + 'settings.terminal.font.weight.thin': 'Thin', + 'settings.terminal.font.weight.extraLight': 'Extra Light', + 'settings.terminal.font.weight.light': 'Light', + 'settings.terminal.font.weight.normal': 'Normal', + 'settings.terminal.font.weight.medium': 'Medium', + 'settings.terminal.font.weight.semiBold': 'Semi Bold', + 'settings.terminal.font.weight.bold': 'Bold', + 'settings.terminal.font.weight.extraBold': 'Extra Bold', + 'settings.terminal.font.weight.black': 'Black', 'settings.terminal.font.weightBold': 'Bold font weight', 'settings.terminal.font.weightBold.desc': 'Weight for bold text (100-900)', 'settings.terminal.font.linePadding': 'Line padding', diff --git a/application/i18n/locales/ru/core.ts b/application/i18n/locales/ru/core.ts index 89ac1044..39cfe996 100644 --- a/application/i18n/locales/ru/core.ts +++ b/application/i18n/locales/ru/core.ts @@ -312,6 +312,15 @@ export const ruCoreMessages: Messages = { 'settings.terminal.font.size.desc': 'Размер текста терминала', 'settings.terminal.font.weight': 'Толщина шрифта', 'settings.terminal.font.weight.desc': 'Толщина обычного текста (100-900)', + 'settings.terminal.font.weight.thin': 'Тонкий', + 'settings.terminal.font.weight.extraLight': 'Очень светлый', + 'settings.terminal.font.weight.light': 'Светлый', + 'settings.terminal.font.weight.normal': 'Обычный', + 'settings.terminal.font.weight.medium': 'Средний', + 'settings.terminal.font.weight.semiBold': 'Полужирный', + 'settings.terminal.font.weight.bold': 'Жирный', + 'settings.terminal.font.weight.extraBold': 'Очень жирный', + 'settings.terminal.font.weight.black': 'Максимально жирный', 'settings.terminal.font.weightBold': 'Толщина жирного шрифта', 'settings.terminal.font.weightBold.desc': 'Толщина жирного текста (100-900)', 'settings.terminal.font.linePadding': 'Межстрочный отступ', @@ -500,6 +509,7 @@ export const ruCoreMessages: Messages = { 'settings.shortcuts.binding.next-tab': 'Следующая вкладка', 'settings.shortcuts.binding.prev-tab': 'Предыдущая вкладка', 'settings.shortcuts.binding.close-tab': 'Закрыть вкладку', + 'settings.shortcuts.binding.close-session': 'Закрыть панель сессии', 'settings.shortcuts.binding.new-tab': 'Новая локальная вкладка', 'settings.shortcuts.binding.copy': 'Копировать из терминала', 'settings.shortcuts.binding.paste': 'Вставить в терминал', @@ -507,9 +517,13 @@ export const ruCoreMessages: Messages = { 'settings.shortcuts.binding.select-all': 'Выделить всё содержимое терминала', 'settings.shortcuts.binding.clear-buffer': 'Очистить буфер терминала', 'settings.shortcuts.binding.search-terminal': 'Открыть поиск по терминалу', + 'settings.shortcuts.binding.increase-terminal-font-size': 'Увеличить размер шрифта терминала', + 'settings.shortcuts.binding.decrease-terminal-font-size': 'Уменьшить размер шрифта терминала', + 'settings.shortcuts.binding.reset-terminal-font-size': 'Сбросить размер шрифта терминала', 'settings.shortcuts.binding.move-focus': 'Переместить фокус между разделёнными окнами', 'settings.shortcuts.binding.split-horizontal': 'Горизонтальное разделение', 'settings.shortcuts.binding.split-vertical': 'Вертикальное разделение', + 'settings.shortcuts.binding.toggle-pane-zoom': 'Переключить масштаб панели', 'settings.shortcuts.binding.open-hosts': 'Открыть список хостов', 'settings.shortcuts.binding.open-local': 'Открыть локальный терминал', 'settings.shortcuts.binding.open-sftp': 'Открыть SFTP', diff --git a/application/i18n/locales/settingsLocales.test.ts b/application/i18n/locales/settingsLocales.test.ts new file mode 100644 index 00000000..a6631776 --- /dev/null +++ b/application/i18n/locales/settingsLocales.test.ts @@ -0,0 +1,55 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { DEFAULT_KEY_BINDINGS } from "../../../domain/models/keyBindings.ts"; +import zhCN from "./zh-CN.ts"; +import ru from "./ru.ts"; + +const LOCALIZED_SETTINGS_LOCALES = [ + { name: "zh-CN", messages: zhCN }, + { name: "ru", messages: ru }, +]; + +test("localized settings include names for every default shortcut", () => { + for (const locale of LOCALIZED_SETTINGS_LOCALES) { + const missing = DEFAULT_KEY_BINDINGS + .map((binding) => `settings.shortcuts.binding.${binding.id}`) + .filter((key) => !locale.messages[key]); + + assert.deepEqual(missing, [], `${locale.name} is missing shortcut labels`); + } +}); + +test("localized settings include workspace focus indicator labels", () => { + const keys = [ + "settings.terminal.section.workspaceFocus", + "settings.terminal.workspaceFocus.style", + "settings.terminal.workspaceFocus.style.desc", + "settings.terminal.workspaceFocus.dim", + "settings.terminal.workspaceFocus.border", + ]; + + for (const locale of LOCALIZED_SETTINGS_LOCALES) { + const missing = keys.filter((key) => !locale.messages[key]); + assert.deepEqual(missing, [], `${locale.name} is missing workspace focus labels`); + } +}); + +test("localized settings include terminal font weight option labels", () => { + const keys = [ + "settings.terminal.font.weight.thin", + "settings.terminal.font.weight.extraLight", + "settings.terminal.font.weight.light", + "settings.terminal.font.weight.normal", + "settings.terminal.font.weight.medium", + "settings.terminal.font.weight.semiBold", + "settings.terminal.font.weight.bold", + "settings.terminal.font.weight.extraBold", + "settings.terminal.font.weight.black", + ]; + + for (const locale of LOCALIZED_SETTINGS_LOCALES) { + const missing = keys.filter((key) => !locale.messages[key]); + assert.deepEqual(missing, [], `${locale.name} is missing font weight labels`); + } +}); diff --git a/application/i18n/locales/zh-CN/terminal.ts b/application/i18n/locales/zh-CN/terminal.ts index 361325dc..c73156bf 100644 --- a/application/i18n/locales/zh-CN/terminal.ts +++ b/application/i18n/locales/zh-CN/terminal.ts @@ -190,6 +190,15 @@ export const zhCNTerminalMessages: Messages = { 'settings.terminal.font.size.desc': '终端文字大小', 'settings.terminal.font.weight': '字重', 'settings.terminal.font.weight.desc': '常规文本字重 (100-900)', + 'settings.terminal.font.weight.thin': '极细', + 'settings.terminal.font.weight.extraLight': '特细', + 'settings.terminal.font.weight.light': '细', + 'settings.terminal.font.weight.normal': '常规', + 'settings.terminal.font.weight.medium': '中等', + 'settings.terminal.font.weight.semiBold': '半粗', + 'settings.terminal.font.weight.bold': '粗', + 'settings.terminal.font.weight.extraBold': '特粗', + 'settings.terminal.font.weight.black': '黑体', 'settings.terminal.font.weightBold': '粗体字重', 'settings.terminal.font.weightBold.desc': '粗体文本字重 (100-900)', 'settings.terminal.font.linePadding': '行间距', @@ -328,6 +337,13 @@ export const zhCNTerminalMessages: Messages = { 'settings.terminal.rendering.renderer.desc': '选择终端渲染技术。自动模式会在低内存设备上使用 DOM 渲染。更改将在新终端会话中生效。', 'settings.terminal.rendering.auto': '自动', + // Settings > Terminal > Workspace Focus Indicator + 'settings.terminal.section.workspaceFocus': '工作区焦点提示', + 'settings.terminal.workspaceFocus.style': '焦点提示样式', + 'settings.terminal.workspaceFocus.style.desc': '在分屏视图中如何标识当前聚焦的窗格。', + 'settings.terminal.workspaceFocus.dim': '淡化未聚焦窗格', + 'settings.terminal.workspaceFocus.border': '为聚焦窗格显示边框', + // Settings > Terminal > Autocomplete 'settings.terminal.section.autocomplete': '自动补全', 'settings.terminal.autocomplete.enabled': '启用自动补全', @@ -362,18 +378,25 @@ export const zhCNTerminalMessages: Messages = { 'settings.shortcuts.binding.next-tab': '下一个标签页', 'settings.shortcuts.binding.prev-tab': '上一个标签页', 'settings.shortcuts.binding.close-tab': '关闭标签页', + 'settings.shortcuts.binding.close-session': '关闭会话窗格', 'settings.shortcuts.binding.new-tab': '新建本地标签页', 'settings.shortcuts.binding.copy': '从终端复制', 'settings.shortcuts.binding.paste': '粘贴到终端', + 'settings.shortcuts.binding.paste-selection': '将选区粘贴到终端', 'settings.shortcuts.binding.select-all': '全选终端内容', 'settings.shortcuts.binding.clear-buffer': '清空终端缓冲区', 'settings.shortcuts.binding.search-terminal': '打开终端搜索', + 'settings.shortcuts.binding.increase-terminal-font-size': '增大终端字号', + 'settings.shortcuts.binding.decrease-terminal-font-size': '减小终端字号', + 'settings.shortcuts.binding.reset-terminal-font-size': '重置终端字号', 'settings.shortcuts.binding.move-focus': '在分屏间移动焦点', 'settings.shortcuts.binding.split-horizontal': '水平分屏', 'settings.shortcuts.binding.split-vertical': '垂直分屏', + 'settings.shortcuts.binding.toggle-pane-zoom': '切换窗格缩放', 'settings.shortcuts.binding.open-hosts': '打开主机列表', 'settings.shortcuts.binding.open-local': '打开本地终端', 'settings.shortcuts.binding.open-sftp': '打开 SFTP', + 'settings.shortcuts.binding.open-settings': '打开设置', 'settings.shortcuts.binding.port-forwarding': '打开端口转发', 'settings.shortcuts.binding.command-palette': '打开命令面板', 'settings.shortcuts.binding.quick-switch': '快速切换', @@ -389,6 +412,9 @@ export const zhCNTerminalMessages: Messages = { 'settings.shortcuts.binding.sftp-delete': '删除文件', 'settings.shortcuts.binding.sftp-refresh': '刷新', 'settings.shortcuts.binding.sftp-new-folder': '新建文件夹', + 'settings.shortcuts.binding.sftp-open': '打开文件 / 进入目录', + 'settings.shortcuts.binding.sftp-go-parent': '转到上级目录', + 'settings.shortcuts.binding.sftp-navigate-to': '转到选中的目录', // Host Details (sub-panels) 'hostDetails.proxyPanel.title': '通过 HTTP/SOCKS5/命令代理', diff --git a/components/settings/settings-ui.tsx b/components/settings/settings-ui.tsx index 62daa6ce..eb16b1b5 100644 --- a/components/settings/settings-ui.tsx +++ b/components/settings/settings-ui.tsx @@ -71,7 +71,7 @@ export const Select: React.FC = ({ = ({ @@ -92,7 +92,7 @@ export const Select: React.FC = ({ - + {opt.icon} {opt.label} diff --git a/components/settings/tabs/SettingsTerminalTab.tsx b/components/settings/tabs/SettingsTerminalTab.tsx index 644d232e..d9fff9de 100644 --- a/components/settings/tabs/SettingsTerminalTab.tsx +++ b/components/settings/tabs/SettingsTerminalTab.tsx @@ -27,6 +27,19 @@ import { resolveFollowedTerminalThemeId, TERMINAL_THEME_AUTO } from "../../../do import { KeywordHighlightRulesEditor, ThemePreviewButton } from "./SettingsTerminalTabControls"; import { TerminalBehaviorSettings } from "./TerminalBehaviorSettings"; + +const FONT_WEIGHT_OPTIONS = [ + { value: "100", labelKey: "settings.terminal.font.weight.thin" }, + { value: "200", labelKey: "settings.terminal.font.weight.extraLight" }, + { value: "300", labelKey: "settings.terminal.font.weight.light" }, + { value: "400", labelKey: "settings.terminal.font.weight.normal" }, + { value: "500", labelKey: "settings.terminal.font.weight.medium" }, + { value: "600", labelKey: "settings.terminal.font.weight.semiBold" }, + { value: "700", labelKey: "settings.terminal.font.weight.bold" }, + { value: "800", labelKey: "settings.terminal.font.weight.extraBold" }, + { value: "900", labelKey: "settings.terminal.font.weight.black" }, +]; + function SettingsTerminalTab(props: { terminalThemeId: string; setTerminalThemeId: (id: string) => void; @@ -146,6 +159,13 @@ function SettingsTerminalTab(props: { || TERMINAL_THEMES[0]; }, [terminalThemeDarkId, terminalThemeLightId, lightUiThemeId, darkUiThemeId, terminalThemeId, customThemes]); + const fontWeightOptions = useMemo(() => ( + FONT_WEIGHT_OPTIONS.map((option) => ({ + value: option.value, + label: `${option.value} - ${t(option.labelKey)}`, + })) + ), [t]); + const handleAutocompleteGhostTextChange = useCallback((enabled: boolean) => { updateTerminalSetting("autocompleteGhostText", enabled); if (enabled) { @@ -516,17 +536,7 @@ function SettingsTerminalTab(props: { > updateTerminalSetting("fontWeightBold", parseInt(v))} className="w-40" /> diff --git a/package.json b/package.json index 020db682..3223eb48 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "tool:cli": "node electron/cli/netcatty-tool-cli.cjs", "lint": "eslint .", "lint:fix": "eslint . --fix", - "test": "node --test --import tsx electron/bridges/*.test.cjs electron/bridges/*/*.test.cjs electron/bridges/aiBridge/sdk/*.test.cjs scripts/*.test.cjs application/*.test.ts application/app/*.test.ts application/state/*.test.ts application/state/*/*.test.ts components/*.test.ts components/*.test.tsx components/editor/*.test.ts components/editor/*.test.tsx components/terminalLayer/*.test.ts components/settings/*.test.tsx components/settings/tabs/ai/*.test.ts components/ai/*.test.ts components/ai-elements/*.test.tsx components/sftp/*.test.ts components/terminal/*.test.ts components/terminal/runtime/*.test.ts domain/*.test.ts infrastructure/ai/*.test.ts infrastructure/config/*.test.ts infrastructure/services/*/*.test.ts lib/*.test.ts" + "test": "node --test --import tsx electron/bridges/*.test.cjs electron/bridges/*/*.test.cjs electron/bridges/aiBridge/sdk/*.test.cjs scripts/*.test.cjs application/*.test.ts application/app/*.test.ts application/i18n/locales/*.test.ts application/state/*.test.ts application/state/*/*.test.ts components/*.test.ts components/*.test.tsx components/editor/*.test.ts components/editor/*.test.tsx components/terminalLayer/*.test.ts components/settings/*.test.tsx components/settings/tabs/ai/*.test.ts components/ai/*.test.ts components/ai-elements/*.test.tsx components/sftp/*.test.ts components/terminal/*.test.ts components/terminal/runtime/*.test.ts domain/*.test.ts infrastructure/ai/*.test.ts infrastructure/config/*.test.ts infrastructure/services/*/*.test.ts lib/*.test.ts" }, "dependencies": { "@ai-sdk/anthropic": "^3.0.58",