The newly added crawler visualization settings and the process visualization orc…
…hestration module have been adapted to support bilingual switching.
Showing
5 changed files
with
650 additions
and
88 deletions
static/js/i18n/spider_translations.js
0 → 100644
| 1 | +// 爬虫控制面板翻译资源文件 | ||
| 2 | +// 包含中文(zh-CN)和英文(en-US)的翻译 | ||
| 3 | + | ||
| 4 | +const spiderI18nResources = { | ||
| 5 | + 'zh-CN': { | ||
| 6 | + translation: { | ||
| 7 | + // 页面标题和导航 | ||
| 8 | + 'page-title': '爬虫控制面板', | ||
| 9 | + | ||
| 10 | + // 卡片标题 | ||
| 11 | + 'topic-selection': '选择话题类型', | ||
| 12 | + 'spider-parameters': '爬虫参数配置', | ||
| 13 | + 'content-filters': '内容筛选配置', | ||
| 14 | + 'account-config': '账号配置', | ||
| 15 | + 'parallel-config': '并行配置', | ||
| 16 | + 'db-config': '数据库配置', | ||
| 17 | + 'ai-assistant': 'AI配置助手', | ||
| 18 | + 'spider-status': '爬虫状态', | ||
| 19 | + | ||
| 20 | + // 话题选择部分 | ||
| 21 | + 'add-custom-topic': '添加自定义话题', | ||
| 22 | + 'custom-topic-placeholder': '输入自定义话题', | ||
| 23 | + 'btn-add': '添加', | ||
| 24 | + 'selected-topics': '已选择的话题:', | ||
| 25 | + | ||
| 26 | + // 爬虫参数部分 | ||
| 27 | + 'crawl-depth': '爬取深度', | ||
| 28 | + 'crawl-depth-hint': '每个话题爬取的页数(1-10)', | ||
| 29 | + 'interval': '爬取间隔(秒)', | ||
| 30 | + 'interval-hint': '每次请求之间的间隔时间', | ||
| 31 | + 'max-retries': '最大重试次数', | ||
| 32 | + 'timeout': '请求超时时间(秒)', | ||
| 33 | + | ||
| 34 | + // 筛选器部分 | ||
| 35 | + 'help': '帮助', | ||
| 36 | + 'filter-conditions': '筛选条件说明:', | ||
| 37 | + 'filter-condition-1': '数值条件:设置大于某个值进行筛选,如点赞数>1000', | ||
| 38 | + 'filter-condition-2': '正则匹配:使用正则表达式匹配内容,如包含特定关键词', | ||
| 39 | + 'filter-condition-3': '多个条件之间是"与"的关系,即同时满足才会保留', | ||
| 40 | + 'filter-tip': '提示:合理设置筛选条件可以提高数据质量', | ||
| 41 | + 'interaction-filter': '互动数据筛选', | ||
| 42 | + 'likes-gt': '点赞数大于', | ||
| 43 | + 'comments-gt': '评论数大于', | ||
| 44 | + 'reposts-gt': '转发数大于', | ||
| 45 | + 'reads-gt': '阅读数大于', | ||
| 46 | + 'regex-filter': '内容正则筛选', | ||
| 47 | + 'add-regex-filter': '添加正则筛选', | ||
| 48 | + 'advanced-options': '高级选项', | ||
| 49 | + 'only-original': '仅爬取原创内容', | ||
| 50 | + 'must-have-media': '必须包含图片或视频', | ||
| 51 | + 'only-verified': '仅认证用户的内容', | ||
| 52 | + | ||
| 53 | + // 账号配置部分 | ||
| 54 | + 'btn-add-account': '添加账号', | ||
| 55 | + 'how-to-get-cookie': '如何获取Cookie?', | ||
| 56 | + 'cookie-step-1': '登录微博网页版', | ||
| 57 | + 'cookie-step-2': '按F12打开开发者工具', | ||
| 58 | + 'cookie-step-3': '切换到Network标签页', | ||
| 59 | + 'cookie-step-4': '刷新页面,找到请求头中的Cookie值', | ||
| 60 | + 'cookie-warning': '注意:请勿泄露您的Cookie信息!', | ||
| 61 | + 'account-tip': '提示:添加多个账号可以提高爬取效率,系统会自动在账号间轮换。', | ||
| 62 | + 'no-account-warning': '请至少添加一个账号', | ||
| 63 | + 'username': '用户名', | ||
| 64 | + 'username-placeholder': '微博用户名', | ||
| 65 | + 'password': '密码', | ||
| 66 | + 'password-placeholder': '微博密码', | ||
| 67 | + 'cookie': 'Cookie', | ||
| 68 | + 'cookie-placeholder': '请输入微博Cookie', | ||
| 69 | + 'save-cookie': '保存Cookie(加密存储)', | ||
| 70 | + 'status-pending': '状态:待验证', | ||
| 71 | + 'btn-validate-account': '验证账号', | ||
| 72 | + 'status-validating': '状态:验证中...', | ||
| 73 | + 'status-success': '状态:验证成功', | ||
| 74 | + 'status-failed': '状态:验证失败 - ', | ||
| 75 | + 'error-empty-cookie': 'Cookie不能为空', | ||
| 76 | + | ||
| 77 | + // 正则筛选器 | ||
| 78 | + 'regex-pattern': '正则表达式', | ||
| 79 | + 'regex-pattern-placeholder': '输入正则表达式', | ||
| 80 | + 'match-target': '匹配目标', | ||
| 81 | + 'target-content': '微博内容', | ||
| 82 | + 'target-author': '作者名', | ||
| 83 | + 'target-location': '发布位置', | ||
| 84 | + 'inverse-match': '反向匹配(不包含匹配项)', | ||
| 85 | + | ||
| 86 | + // 并行配置 | ||
| 87 | + 'max-concurrent': '最大并行数', | ||
| 88 | + 'max-concurrent-hint': '同时进行爬取的最大话题数(1-5)', | ||
| 89 | + 'requests-per-minute': '每分钟请求数限制', | ||
| 90 | + 'requests-per-minute-hint': '避免请求过于频繁(30-120)', | ||
| 91 | + | ||
| 92 | + // 数据库配置 | ||
| 93 | + 'db-type': '数据库类型', | ||
| 94 | + 'host': '主机地址', | ||
| 95 | + 'port': '端口', | ||
| 96 | + 'db-name': '数据库名', | ||
| 97 | + 'username-db': '用户名', | ||
| 98 | + 'password-db': '密码', | ||
| 99 | + 'btn-test-connection': '测试连接', | ||
| 100 | + 'db-connect-success': '数据库连接测试成功!', | ||
| 101 | + 'db-connect-fail': '数据库连接测试失败:', | ||
| 102 | + 'db-connect-error': '测试连接时发生错误:', | ||
| 103 | + | ||
| 104 | + // AI配置助手 | ||
| 105 | + 'ai-prompt-label': '用自然语言描述您的爬虫需求', | ||
| 106 | + 'ai-prompt-placeholder': '例如:我想爬取最近一周关于人工智能的热门微博,重点关注转发量超过1000的内容,每个话题爬取前5页内容。', | ||
| 107 | + 'btn-generate-config': '生成配置', | ||
| 108 | + 'auto-apply': '自动应用生成的配置', | ||
| 109 | + 'ai-suggestion': 'AI助手建议:', | ||
| 110 | + 'ai-config-applied': 'AI配置已自动应用', | ||
| 111 | + 'ai-config-error': '生成配置时出错:', | ||
| 112 | + 'empty-prompt-error': '请输入您的爬虫需求描述!', | ||
| 113 | + | ||
| 114 | + // 操作按钮 | ||
| 115 | + 'btn-start': '开始爬取', | ||
| 116 | + 'btn-save-config': '保存配置', | ||
| 117 | + 'config-saved': '配置已保存!', | ||
| 118 | + 'save-failed': '保存失败:', | ||
| 119 | + 'save-error': '保存出错:', | ||
| 120 | + | ||
| 121 | + // 爬虫状态 | ||
| 122 | + 'task-started': '爬虫任务已启动...', | ||
| 123 | + 'start-failed': '启动失败:', | ||
| 124 | + 'error': '错误:', | ||
| 125 | + | ||
| 126 | + // 验证错误提示 | ||
| 127 | + 'select-topic-error': '请至少选择一个话题!', | ||
| 128 | + 'invalid-regex-error': '正则表达式 "{0}" 格式无效!', | ||
| 129 | + 'need-account-error': '请至少添加一个账号!', | ||
| 130 | + 'empty-cookie-error': '存在未配置Cookie的账号,请检查!', | ||
| 131 | + 'concurrent-limit-error': '最大并行数必须在1-5之间!', | ||
| 132 | + 'request-limit-error': '每分钟请求数必须在30-120之间!', | ||
| 133 | + 'db-config-error': '请完整填写数据库配置信息!' | ||
| 134 | + } | ||
| 135 | + }, | ||
| 136 | + 'en-US': { | ||
| 137 | + translation: { | ||
| 138 | + // Page title and navigation | ||
| 139 | + 'page-title': 'Spider Control Panel', | ||
| 140 | + | ||
| 141 | + // Card titles | ||
| 142 | + 'topic-selection': 'Select Topic Types', | ||
| 143 | + 'spider-parameters': 'Spider Parameters', | ||
| 144 | + 'content-filters': 'Content Filters', | ||
| 145 | + 'account-config': 'Account Configuration', | ||
| 146 | + 'parallel-config': 'Parallel Configuration', | ||
| 147 | + 'db-config': 'Database Configuration', | ||
| 148 | + 'ai-assistant': 'AI Configuration Assistant', | ||
| 149 | + 'spider-status': 'Spider Status', | ||
| 150 | + | ||
| 151 | + // Topic selection section | ||
| 152 | + 'add-custom-topic': 'Add Custom Topic', | ||
| 153 | + 'custom-topic-placeholder': 'Enter custom topic', | ||
| 154 | + 'btn-add': 'Add', | ||
| 155 | + 'selected-topics': 'Selected Topics:', | ||
| 156 | + | ||
| 157 | + // Spider parameters section | ||
| 158 | + 'crawl-depth': 'Crawl Depth', | ||
| 159 | + 'crawl-depth-hint': 'Number of pages to crawl for each topic (1-10)', | ||
| 160 | + 'interval': 'Interval (seconds)', | ||
| 161 | + 'interval-hint': 'Time between requests', | ||
| 162 | + 'max-retries': 'Maximum Retries', | ||
| 163 | + 'timeout': 'Request Timeout (seconds)', | ||
| 164 | + | ||
| 165 | + // Filters section | ||
| 166 | + 'help': 'Help', | ||
| 167 | + 'filter-conditions': 'Filter conditions:', | ||
| 168 | + 'filter-condition-1': 'Numeric conditions: Set values to filter by, e.g., likes > 1000', | ||
| 169 | + 'filter-condition-2': 'Regex matching: Use regular expressions to match content, e.g., contain specific keywords', | ||
| 170 | + 'filter-condition-3': 'Multiple conditions are combined with AND logic', | ||
| 171 | + 'filter-tip': 'Tip: Setting proper filters can improve data quality', | ||
| 172 | + 'interaction-filter': 'Interaction Data Filters', | ||
| 173 | + 'likes-gt': 'Likes greater than', | ||
| 174 | + 'comments-gt': 'Comments greater than', | ||
| 175 | + 'reposts-gt': 'Reposts greater than', | ||
| 176 | + 'reads-gt': 'Reads greater than', | ||
| 177 | + 'regex-filter': 'Content Regex Filters', | ||
| 178 | + 'add-regex-filter': 'Add Regex Filter', | ||
| 179 | + 'advanced-options': 'Advanced Options', | ||
| 180 | + 'only-original': 'Only crawl original content', | ||
| 181 | + 'must-have-media': 'Must contain images or videos', | ||
| 182 | + 'only-verified': 'Only content from verified users', | ||
| 183 | + | ||
| 184 | + // Account configuration section | ||
| 185 | + 'btn-add-account': 'Add Account', | ||
| 186 | + 'how-to-get-cookie': 'How to get the Cookie?', | ||
| 187 | + 'cookie-step-1': 'Login to Weibo web version', | ||
| 188 | + 'cookie-step-2': 'Press F12 to open developer tools', | ||
| 189 | + 'cookie-step-3': 'Switch to Network tab', | ||
| 190 | + 'cookie-step-4': 'Refresh page and find Cookie value in request headers', | ||
| 191 | + 'cookie-warning': 'Warning: Do not expose your Cookie information!', | ||
| 192 | + 'account-tip': 'Tip: Adding multiple accounts can improve crawling efficiency, the system will automatically rotate between accounts.', | ||
| 193 | + 'no-account-warning': 'Please add at least one account', | ||
| 194 | + 'username': 'Username', | ||
| 195 | + 'username-placeholder': 'Weibo username', | ||
| 196 | + 'password': 'Password', | ||
| 197 | + 'password-placeholder': 'Weibo password', | ||
| 198 | + 'cookie': 'Cookie', | ||
| 199 | + 'cookie-placeholder': 'Please enter Weibo Cookie', | ||
| 200 | + 'save-cookie': 'Save Cookie (encrypted storage)', | ||
| 201 | + 'status-pending': 'Status: Pending verification', | ||
| 202 | + 'btn-validate-account': 'Validate Account', | ||
| 203 | + 'status-validating': 'Status: Validating...', | ||
| 204 | + 'status-success': 'Status: Validation successful', | ||
| 205 | + 'status-failed': 'Status: Validation failed - ', | ||
| 206 | + 'error-empty-cookie': 'Cookie cannot be empty', | ||
| 207 | + | ||
| 208 | + // Regex filters | ||
| 209 | + 'regex-pattern': 'Regular Expression', | ||
| 210 | + 'regex-pattern-placeholder': 'Enter regular expression', | ||
| 211 | + 'match-target': 'Match Target', | ||
| 212 | + 'target-content': 'Weibo content', | ||
| 213 | + 'target-author': 'Author name', | ||
| 214 | + 'target-location': 'Posting location', | ||
| 215 | + 'inverse-match': 'Inverse match (exclude matches)', | ||
| 216 | + | ||
| 217 | + // Parallel configuration | ||
| 218 | + 'max-concurrent': 'Maximum Concurrent Tasks', | ||
| 219 | + 'max-concurrent-hint': 'Maximum number of topics to crawl simultaneously (1-5)', | ||
| 220 | + 'requests-per-minute': 'Requests Per Minute Limit', | ||
| 221 | + 'requests-per-minute-hint': 'Avoid too frequent requests (30-120)', | ||
| 222 | + | ||
| 223 | + // Database configuration | ||
| 224 | + 'db-type': 'Database Type', | ||
| 225 | + 'host': 'Host', | ||
| 226 | + 'port': 'Port', | ||
| 227 | + 'db-name': 'Database Name', | ||
| 228 | + 'username-db': 'Username', | ||
| 229 | + 'password-db': 'Password', | ||
| 230 | + 'btn-test-connection': 'Test Connection', | ||
| 231 | + 'db-connect-success': 'Database connection test successful!', | ||
| 232 | + 'db-connect-fail': 'Database connection test failed: ', | ||
| 233 | + 'db-connect-error': 'Error while testing connection: ', | ||
| 234 | + | ||
| 235 | + // AI assistant | ||
| 236 | + 'ai-prompt-label': 'Describe your crawling requirements in natural language', | ||
| 237 | + 'ai-prompt-placeholder': 'For example: I want to crawl trending Weibo posts about AI from the past week, focusing on content with more than 1000 reposts, crawling the first 5 pages for each topic.', | ||
| 238 | + 'btn-generate-config': 'Generate Configuration', | ||
| 239 | + 'auto-apply': 'Auto-apply generated configuration', | ||
| 240 | + 'ai-suggestion': 'AI Assistant Suggestion:', | ||
| 241 | + 'ai-config-applied': 'AI configuration applied automatically', | ||
| 242 | + 'ai-config-error': 'Error generating configuration: ', | ||
| 243 | + 'empty-prompt-error': 'Please enter your crawler requirements!', | ||
| 244 | + | ||
| 245 | + // Action buttons | ||
| 246 | + 'btn-start': 'Start Crawling', | ||
| 247 | + 'btn-save-config': 'Save Configuration', | ||
| 248 | + 'config-saved': 'Configuration saved!', | ||
| 249 | + 'save-failed': 'Save failed: ', | ||
| 250 | + 'save-error': 'Error saving: ', | ||
| 251 | + | ||
| 252 | + // Spider status | ||
| 253 | + 'task-started': 'Crawler task started...', | ||
| 254 | + 'start-failed': 'Start failed: ', | ||
| 255 | + 'error': 'Error: ', | ||
| 256 | + | ||
| 257 | + // Validation error messages | ||
| 258 | + 'select-topic-error': 'Please select at least one topic!', | ||
| 259 | + 'invalid-regex-error': 'Regular expression "{0}" is invalid!', | ||
| 260 | + 'need-account-error': 'Please add at least one account!', | ||
| 261 | + 'empty-cookie-error': 'There are accounts without Cookie configuration, please check!', | ||
| 262 | + 'concurrent-limit-error': 'Maximum concurrent tasks must be between 1-5!', | ||
| 263 | + 'request-limit-error': 'Requests per minute must be between 30-120!', | ||
| 264 | + 'db-config-error': 'Please complete all database configuration fields!' | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | +}; |
static/js/i18n/translations.js
0 → 100644
| 1 | +// 翻译资源文件 | ||
| 2 | +// 包含中文(zh-CN)和英文(en-US)的翻译 | ||
| 3 | + | ||
| 4 | +const i18nResources = { | ||
| 5 | + 'zh-CN': { | ||
| 6 | + translation: { | ||
| 7 | + // 页面标题 | ||
| 8 | + 'page-title': '工作流编辑器 - 微博舆情分析系统', | ||
| 9 | + 'navbar-brand': '工作流编辑器', | ||
| 10 | + | ||
| 11 | + // 导航菜单 | ||
| 12 | + 'nav-visual-editor': '可视化编辑', | ||
| 13 | + 'nav-template-mgmt': '模板管理', | ||
| 14 | + 'nav-task-list': '任务列表', | ||
| 15 | + | ||
| 16 | + // 按钮 | ||
| 17 | + 'btn-save': '保存', | ||
| 18 | + 'btn-run': '运行', | ||
| 19 | + 'btn-cancel': '取消', | ||
| 20 | + 'btn-close': '关闭', | ||
| 21 | + 'btn-create-new': '新建', | ||
| 22 | + 'btn-validate': '验证', | ||
| 23 | + 'btn-undo': '撤销', | ||
| 24 | + 'btn-redo': '重做', | ||
| 25 | + 'btn-zoom-in': '放大', | ||
| 26 | + 'btn-zoom-out': '缩小', | ||
| 27 | + 'btn-fit-view': '适应视图', | ||
| 28 | + 'btn-export': '导出工作流', | ||
| 29 | + 'btn-import': '导入工作流', | ||
| 30 | + 'btn-cancel-task': '取消任务', | ||
| 31 | + 'btn-view-full-result': '查看完整结果', | ||
| 32 | + | ||
| 33 | + // 选项卡 | ||
| 34 | + 'tab-components': '组件', | ||
| 35 | + 'tab-templates': '模板', | ||
| 36 | + | ||
| 37 | + // 组件类别 | ||
| 38 | + 'comp-data-source': '数据源', | ||
| 39 | + 'comp-data-processing': '数据处理', | ||
| 40 | + 'comp-model-analysis': '模型分析', | ||
| 41 | + 'comp-visualization': '可视化', | ||
| 42 | + | ||
| 43 | + // 组件 | ||
| 44 | + 'comp-database': '数据库', | ||
| 45 | + 'comp-file': '文件', | ||
| 46 | + 'comp-crawler': '爬虫', | ||
| 47 | + 'comp-filter': '过滤', | ||
| 48 | + 'comp-sort': '排序', | ||
| 49 | + 'comp-aggregate': '聚合', | ||
| 50 | + 'comp-sentiment': '情感分析', | ||
| 51 | + 'comp-topic': '话题分类', | ||
| 52 | + 'comp-keywords': '关键词提取', | ||
| 53 | + 'comp-summarize': '文本摘要', | ||
| 54 | + 'comp-chart': '图表', | ||
| 55 | + 'comp-table': '表格', | ||
| 56 | + 'comp-wordcloud': '词云', | ||
| 57 | + | ||
| 58 | + // 模板相关 | ||
| 59 | + 'templates-crawler': '爬虫模板', | ||
| 60 | + 'templates-analysis': '分析流程模板', | ||
| 61 | + 'modal-save-template': '保存为模板', | ||
| 62 | + 'template-name': '模板名称', | ||
| 63 | + 'template-description': '描述', | ||
| 64 | + 'template-icon': '图标', | ||
| 65 | + | ||
| 66 | + // 图标名称 | ||
| 67 | + 'icon-chart': '图表', | ||
| 68 | + 'icon-filter': '过滤', | ||
| 69 | + 'icon-crawler': '爬虫', | ||
| 70 | + 'icon-ai': 'AI分析', | ||
| 71 | + 'icon-database': '数据库', | ||
| 72 | + 'icon-wordcloud': '词云', | ||
| 73 | + | ||
| 74 | + // 属性面板 | ||
| 75 | + 'properties-title': '组件属性', | ||
| 76 | + | ||
| 77 | + // 工作流状态 | ||
| 78 | + 'workflow-status-message': '工作流就绪。拖拽左侧组件到画布创建节点。', | ||
| 79 | + 'nodes': '节点', | ||
| 80 | + 'connections': '连接', | ||
| 81 | + | ||
| 82 | + // 运行工作流 | ||
| 83 | + 'modal-run-workflow': '运行工作流', | ||
| 84 | + 'run-workflow-confirm': '确认要运行当前工作流吗?', | ||
| 85 | + 'save-before-run': '运行前保存工作流', | ||
| 86 | + | ||
| 87 | + // 任务状态 | ||
| 88 | + 'modal-task-status': '任务执行状态', | ||
| 89 | + 'task-progress': '进度', | ||
| 90 | + 'task-status-info': '状态信息', | ||
| 91 | + 'task-waiting': '等待中', | ||
| 92 | + 'task-id': '任务ID:', | ||
| 93 | + 'task-status': '状态:', | ||
| 94 | + 'task-start-time': '开始时间:', | ||
| 95 | + 'task-complete-time': '完成时间:', | ||
| 96 | + 'task-current-step': '当前步骤:', | ||
| 97 | + 'waiting-to-start': '等待开始', | ||
| 98 | + 'task-elapsed-time': '耗时:', | ||
| 99 | + 'task-result-preview': '结果预览', | ||
| 100 | + 'refresh-preview': '刷新预览', | ||
| 101 | + 'loading': '加载中...', | ||
| 102 | + 'task-running-preparing': '任务运行中,正在准备预览数据...', | ||
| 103 | + 'preview-after-task': '任务完成后将显示结果预览...', | ||
| 104 | + 'preview-error': '加载预览时发生错误' | ||
| 105 | + } | ||
| 106 | + }, | ||
| 107 | + 'en-US': { | ||
| 108 | + translation: { | ||
| 109 | + // Page title | ||
| 110 | + 'page-title': 'Workflow Editor - Weibo Public Opinion Analysis System', | ||
| 111 | + 'navbar-brand': 'Workflow Editor', | ||
| 112 | + | ||
| 113 | + // Navigation menu | ||
| 114 | + 'nav-visual-editor': 'Visual Editor', | ||
| 115 | + 'nav-template-mgmt': 'Template Management', | ||
| 116 | + 'nav-task-list': 'Task List', | ||
| 117 | + | ||
| 118 | + // Buttons | ||
| 119 | + 'btn-save': 'Save', | ||
| 120 | + 'btn-run': 'Run', | ||
| 121 | + 'btn-cancel': 'Cancel', | ||
| 122 | + 'btn-close': 'Close', | ||
| 123 | + 'btn-create-new': 'Create New', | ||
| 124 | + 'btn-validate': 'Validate', | ||
| 125 | + 'btn-undo': 'Undo', | ||
| 126 | + 'btn-redo': 'Redo', | ||
| 127 | + 'btn-zoom-in': 'Zoom In', | ||
| 128 | + 'btn-zoom-out': 'Zoom Out', | ||
| 129 | + 'btn-fit-view': 'Fit View', | ||
| 130 | + 'btn-export': 'Export Workflow', | ||
| 131 | + 'btn-import': 'Import Workflow', | ||
| 132 | + 'btn-cancel-task': 'Cancel Task', | ||
| 133 | + 'btn-view-full-result': 'View Full Results', | ||
| 134 | + | ||
| 135 | + // Tabs | ||
| 136 | + 'tab-components': 'Components', | ||
| 137 | + 'tab-templates': 'Templates', | ||
| 138 | + | ||
| 139 | + // Component categories | ||
| 140 | + 'comp-data-source': 'Data Sources', | ||
| 141 | + 'comp-data-processing': 'Data Processing', | ||
| 142 | + 'comp-model-analysis': 'Model Analysis', | ||
| 143 | + 'comp-visualization': 'Visualization', | ||
| 144 | + | ||
| 145 | + // Components | ||
| 146 | + 'comp-database': 'Database', | ||
| 147 | + 'comp-file': 'File', | ||
| 148 | + 'comp-crawler': 'Crawler', | ||
| 149 | + 'comp-filter': 'Filter', | ||
| 150 | + 'comp-sort': 'Sort', | ||
| 151 | + 'comp-aggregate': 'Aggregate', | ||
| 152 | + 'comp-sentiment': 'Sentiment Analysis', | ||
| 153 | + 'comp-topic': 'Topic Classification', | ||
| 154 | + 'comp-keywords': 'Keyword Extraction', | ||
| 155 | + 'comp-summarize': 'Text Summarization', | ||
| 156 | + 'comp-chart': 'Chart', | ||
| 157 | + 'comp-table': 'Table', | ||
| 158 | + 'comp-wordcloud': 'Word Cloud', | ||
| 159 | + | ||
| 160 | + // Template related | ||
| 161 | + 'templates-crawler': 'Crawler Templates', | ||
| 162 | + 'templates-analysis': 'Analysis Flow Templates', | ||
| 163 | + 'modal-save-template': 'Save as Template', | ||
| 164 | + 'template-name': 'Template Name', | ||
| 165 | + 'template-description': 'Description', | ||
| 166 | + 'template-icon': 'Icon', | ||
| 167 | + | ||
| 168 | + // Icon names | ||
| 169 | + 'icon-chart': 'Chart', | ||
| 170 | + 'icon-filter': 'Filter', | ||
| 171 | + 'icon-crawler': 'Crawler', | ||
| 172 | + 'icon-ai': 'AI Analysis', | ||
| 173 | + 'icon-database': 'Database', | ||
| 174 | + 'icon-wordcloud': 'Word Cloud', | ||
| 175 | + | ||
| 176 | + // Properties panel | ||
| 177 | + 'properties-title': 'Component Properties', | ||
| 178 | + | ||
| 179 | + // Workflow status | ||
| 180 | + 'workflow-status-message': 'Workflow ready. Drag components from the left panel to create nodes.', | ||
| 181 | + 'nodes': 'Nodes', | ||
| 182 | + 'connections': 'Connections', | ||
| 183 | + | ||
| 184 | + // Run workflow | ||
| 185 | + 'modal-run-workflow': 'Run Workflow', | ||
| 186 | + 'run-workflow-confirm': 'Are you sure you want to run the current workflow?', | ||
| 187 | + 'save-before-run': 'Save workflow before running', | ||
| 188 | + | ||
| 189 | + // Task status | ||
| 190 | + 'modal-task-status': 'Task Execution Status', | ||
| 191 | + 'task-progress': 'Progress', | ||
| 192 | + 'task-status-info': 'Status Information', | ||
| 193 | + 'task-waiting': 'Waiting', | ||
| 194 | + 'task-id': 'Task ID:', | ||
| 195 | + 'task-status': 'Status:', | ||
| 196 | + 'task-start-time': 'Start Time:', | ||
| 197 | + 'task-complete-time': 'Complete Time:', | ||
| 198 | + 'task-current-step': 'Current Step:', | ||
| 199 | + 'waiting-to-start': 'Waiting to start', | ||
| 200 | + 'task-elapsed-time': 'Elapsed Time:', | ||
| 201 | + 'task-result-preview': 'Result Preview', | ||
| 202 | + 'refresh-preview': 'Refresh Preview', | ||
| 203 | + 'loading': 'Loading...', | ||
| 204 | + 'task-running-preparing': 'Task is running, preparing preview data...', | ||
| 205 | + 'preview-after-task': 'Results preview will be displayed after the task is completed...', | ||
| 206 | + 'preview-error': 'Error loading preview' | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | +}; |
| 1 | let workflowEditorInitialized = false; | 1 | let workflowEditorInitialized = false; |
| 2 | 2 | ||
| 3 | +// 初始化i18next多语言支持 | ||
| 4 | +function initializeI18n() { | ||
| 5 | + // 获取浏览器语言,默认为中文 | ||
| 6 | + const browserLang = navigator.language || 'zh-CN'; | ||
| 7 | + const defaultLang = browserLang.startsWith('zh') ? 'zh-CN' : 'en-US'; | ||
| 8 | + | ||
| 9 | + // 初始化i18next | ||
| 10 | + i18next.init({ | ||
| 11 | + lng: localStorage.getItem('preferred_language') || defaultLang, | ||
| 12 | + resources: i18nResources, | ||
| 13 | + fallbackLng: 'zh-CN', | ||
| 14 | + }).then(function(t) { | ||
| 15 | + // 更新当前语言显示 | ||
| 16 | + updateLanguageDisplay(); | ||
| 17 | + | ||
| 18 | + // 应用翻译到所有元素 | ||
| 19 | + applyTranslations(); | ||
| 20 | + }); | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +// 更新语言显示 | ||
| 24 | +function updateLanguageDisplay() { | ||
| 25 | + const currentLang = i18next.language; | ||
| 26 | + const displayName = currentLang === 'zh-CN' ? '中文' : 'English'; | ||
| 27 | + document.getElementById('currentLanguage').textContent = displayName; | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +// 应用翻译到所有元素 | ||
| 31 | +function applyTranslations() { | ||
| 32 | + // 翻译data-i18n属性的元素 | ||
| 33 | + document.querySelectorAll('[data-i18n]').forEach(element => { | ||
| 34 | + const key = element.getAttribute('data-i18n'); | ||
| 35 | + element.textContent = i18next.t(key); | ||
| 36 | + }); | ||
| 37 | + | ||
| 38 | + // 翻译title属性 | ||
| 39 | + document.querySelectorAll('[data-i18n-title]').forEach(element => { | ||
| 40 | + const key = element.getAttribute('data-i18n-title'); | ||
| 41 | + element.title = i18next.t(key); | ||
| 42 | + }); | ||
| 43 | + | ||
| 44 | + // 更新页面标题 | ||
| 45 | + document.title = i18next.t('page-title'); | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +// 切换语言 | ||
| 49 | +function switchLanguage(lang) { | ||
| 50 | + // 保存语言偏好到本地存储 | ||
| 51 | + localStorage.setItem('preferred_language', lang); | ||
| 52 | + | ||
| 53 | + // 更改i18next语言 | ||
| 54 | + i18next.changeLanguage(lang).then(() => { | ||
| 55 | + // 更新语言显示 | ||
| 56 | + updateLanguageDisplay(); | ||
| 57 | + | ||
| 58 | + // 应用翻译 | ||
| 59 | + applyTranslations(); | ||
| 60 | + }); | ||
| 61 | +} | ||
| 62 | + | ||
| 3 | document.addEventListener('DOMContentLoaded', function() { | 63 | document.addEventListener('DOMContentLoaded', function() { |
| 4 | // 检查是否已初始化,防止多次执行 | 64 | // 检查是否已初始化,防止多次执行 |
| 5 | if (workflowEditorInitialized) { | 65 | if (workflowEditorInitialized) { |
| @@ -8,6 +68,17 @@ document.addEventListener('DOMContentLoaded', function() { | @@ -8,6 +68,17 @@ document.addEventListener('DOMContentLoaded', function() { | ||
| 8 | } | 68 | } |
| 9 | workflowEditorInitialized = true; | 69 | workflowEditorInitialized = true; |
| 10 | 70 | ||
| 71 | + // 初始化多语言支持 | ||
| 72 | + initializeI18n(); | ||
| 73 | + | ||
| 74 | + // 添加语言切换事件 | ||
| 75 | + document.querySelectorAll('.language-option').forEach(option => { | ||
| 76 | + option.addEventListener('click', function() { | ||
| 77 | + const lang = this.getAttribute('data-lang'); | ||
| 78 | + switchLanguage(lang); | ||
| 79 | + }); | ||
| 80 | + }); | ||
| 81 | + | ||
| 11 | // 工作流编辑器的主要元素 | 82 | // 工作流编辑器的主要元素 |
| 12 | const workflowCanvas = document.getElementById('workflowCanvas'); | 83 | const workflowCanvas = document.getElementById('workflowCanvas'); |
| 13 | const connectionsSvg = document.getElementById('connectionsSvg'); | 84 | const connectionsSvg = document.getElementById('connectionsSvg'); |
| @@ -384,6 +384,7 @@ | @@ -384,6 +384,7 @@ | ||
| 384 | 384 | ||
| 385 | // 初始化页面 | 385 | // 初始化页面 |
| 386 | window.onload = function() { | 386 | window.onload = function() { |
| 387 | + updateLanguage(); // 设置初始语言 | ||
| 387 | loadPredefinedTopics(); | 388 | loadPredefinedTopics(); |
| 388 | }; | 389 | }; |
| 389 | 390 | ||
| @@ -807,12 +808,12 @@ | @@ -807,12 +808,12 @@ | ||
| 807 | 808 | ||
| 808 | const data = await response.json(); | 809 | const data = await response.json(); |
| 809 | if (data.success) { | 810 | if (data.success) { |
| 810 | - alert('数据库连接测试成功!'); | 811 | + alert(currentLang === 'zh' ? '数据库连接测试成功!' : 'Database connection test successful!'); |
| 811 | } else { | 812 | } else { |
| 812 | - alert('数据库连接测试失败:' + data.message); | 813 | + alert((currentLang === 'zh' ? '数据库连接测试失败:' : 'Database connection test failed: ') + data.message); |
| 813 | } | 814 | } |
| 814 | } catch (error) { | 815 | } catch (error) { |
| 815 | - alert('测试连接时发生错误:' + error.message); | 816 | + alert((currentLang === 'zh' ? '测试连接时发生错误:' : 'Error during connection test: ') + error.message); |
| 816 | } | 817 | } |
| 817 | } | 818 | } |
| 818 | 819 | ||
| @@ -857,13 +858,13 @@ | @@ -857,13 +858,13 @@ | ||
| 857 | .then(response => response.json()) | 858 | .then(response => response.json()) |
| 858 | .then(data => { | 859 | .then(data => { |
| 859 | if (data.success) { | 860 | if (data.success) { |
| 860 | - alert('配置已保存!'); | 861 | + alert(currentLang === 'zh' ? '配置已保存!' : 'Configuration saved!'); |
| 861 | } else { | 862 | } else { |
| 862 | - alert('保存失败:' + data.message); | 863 | + alert((currentLang === 'zh' ? '保存失败:' : 'Save failed: ') + data.message); |
| 863 | } | 864 | } |
| 864 | }) | 865 | }) |
| 865 | .catch(error => { | 866 | .catch(error => { |
| 866 | - alert('保存出错:' + error.message); | 867 | + alert((currentLang === 'zh' ? '保存出错:' : 'Error saving: ') + error.message); |
| 867 | }); | 868 | }); |
| 868 | } | 869 | } |
| 869 | 870 | ||
| @@ -891,7 +892,7 @@ | @@ -891,7 +892,7 @@ | ||
| 891 | async function generateConfig() { | 892 | async function generateConfig() { |
| 892 | const prompt = document.getElementById('aiPrompt').value.trim(); | 893 | const prompt = document.getElementById('aiPrompt').value.trim(); |
| 893 | if (!prompt) { | 894 | if (!prompt) { |
| 894 | - alert('请输入您的爬虫需求描述!'); | 895 | + alert(currentLang === 'zh' ? '请输入您的爬虫需求描述!' : 'Please enter your crawler requirements!'); |
| 895 | return; | 896 | return; |
| 896 | } | 897 | } |
| 897 | 898 | ||
| @@ -933,13 +934,13 @@ | @@ -933,13 +934,13 @@ | ||
| 933 | updateSelectedTopicsList(); | 934 | updateSelectedTopicsList(); |
| 934 | 935 | ||
| 935 | // 添加提示 | 936 | // 添加提示 |
| 936 | - updateCrawlLog('AI配置已自动应用'); | 937 | + updateCrawlLog(currentLang === 'zh' ? 'AI配置已自动应用' : 'AI configuration automatically applied'); |
| 937 | } | 938 | } |
| 938 | } else { | 939 | } else { |
| 939 | throw new Error(data.message); | 940 | throw new Error(data.message); |
| 940 | } | 941 | } |
| 941 | } catch (error) { | 942 | } catch (error) { |
| 942 | - aiSuggestion.textContent = '生成配置时出错:' + error.message; | 943 | + aiSuggestion.textContent = (currentLang === 'zh' ? '生成配置时出错:' : 'Error generating configuration: ') + error.message; |
| 943 | aiResponse.style.display = 'block'; | 944 | aiResponse.style.display = 'block'; |
| 944 | } | 945 | } |
| 945 | } | 946 | } |
| @@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
| 3 | <head> | 3 | <head> |
| 4 | <meta charset="UTF-8"> | 4 | <meta charset="UTF-8"> |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | 5 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 6 | - <title>工作流编辑器 - 微博舆情分析系统</title> | 6 | + <title data-i18n="page-title">工作流编辑器 - 微博舆情分析系统</title> |
| 7 | <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet"> | 7 | <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css" rel="stylesheet"> |
| 8 | <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.0/css/all.min.css" rel="stylesheet"> | 8 | <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.2.0/css/all.min.css" rel="stylesheet"> |
| 9 | <link href="https://cdn.jsdelivr.net/npm/jsoneditor@9.5.0/dist/jsoneditor.min.css" rel="stylesheet"> | 9 | <link href="https://cdn.jsdelivr.net/npm/jsoneditor@9.5.0/dist/jsoneditor.min.css" rel="stylesheet"> |
| @@ -359,7 +359,7 @@ | @@ -359,7 +359,7 @@ | ||
| 359 | <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> | 359 | <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> |
| 360 | <div class="container-fluid"> | 360 | <div class="container-fluid"> |
| 361 | <a class="navbar-brand" href="#"> | 361 | <a class="navbar-brand" href="#"> |
| 362 | - <i class="fas fa-project-diagram me-2"></i>工作流编辑器 | 362 | + <i class="fas fa-project-diagram me-2"></i><span data-i18n="navbar-brand">工作流编辑器</span> |
| 363 | </a> | 363 | </a> |
| 364 | <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> | 364 | <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"> |
| 365 | <span class="navbar-toggler-icon"></span> | 365 | <span class="navbar-toggler-icon"></span> |
| @@ -367,21 +367,31 @@ | @@ -367,21 +367,31 @@ | ||
| 367 | <div class="collapse navbar-collapse" id="navbarNav"> | 367 | <div class="collapse navbar-collapse" id="navbarNav"> |
| 368 | <ul class="navbar-nav me-auto"> | 368 | <ul class="navbar-nav me-auto"> |
| 369 | <li class="nav-item"> | 369 | <li class="nav-item"> |
| 370 | - <a class="nav-link active" href="#">可视化编辑</a> | 370 | + <a class="nav-link active" href="#"><span data-i18n="nav-visual-editor">可视化编辑</span></a> |
| 371 | </li> | 371 | </li> |
| 372 | <li class="nav-item"> | 372 | <li class="nav-item"> |
| 373 | - <a class="nav-link" href="#">模板管理</a> | 373 | + <a class="nav-link" href="#"><span data-i18n="nav-template-mgmt">模板管理</span></a> |
| 374 | </li> | 374 | </li> |
| 375 | <li class="nav-item"> | 375 | <li class="nav-item"> |
| 376 | - <a class="nav-link" href="#">任务列表</a> | 376 | + <a class="nav-link" href="#"><span data-i18n="nav-task-list">任务列表</span></a> |
| 377 | </li> | 377 | </li> |
| 378 | </ul> | 378 | </ul> |
| 379 | <div class="d-flex"> | 379 | <div class="d-flex"> |
| 380 | + <!-- 添加语言切换按钮 --> | ||
| 381 | + <div class="dropdown me-2"> | ||
| 382 | + <button class="btn btn-outline-light dropdown-toggle" type="button" id="languageDropdown" data-bs-toggle="dropdown" aria-expanded="false"> | ||
| 383 | + <i class="fas fa-language me-1"></i><span id="currentLanguage">中文</span> | ||
| 384 | + </button> | ||
| 385 | + <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="languageDropdown"> | ||
| 386 | + <li><button class="dropdown-item language-option" data-lang="zh-CN">中文</button></li> | ||
| 387 | + <li><button class="dropdown-item language-option" data-lang="en-US">English</button></li> | ||
| 388 | + </ul> | ||
| 389 | + </div> | ||
| 380 | <button id="saveWorkflowBtn" class="btn btn-success me-2"> | 390 | <button id="saveWorkflowBtn" class="btn btn-success me-2"> |
| 381 | - <i class="fas fa-save me-1"></i>保存 | 391 | + <i class="fas fa-save me-1"></i><span data-i18n="btn-save">保存</span> |
| 382 | </button> | 392 | </button> |
| 383 | <button id="runWorkflowBtn" class="btn btn-primary"> | 393 | <button id="runWorkflowBtn" class="btn btn-primary"> |
| 384 | - <i class="fas fa-play me-1"></i>运行 | 394 | + <i class="fas fa-play me-1"></i><span data-i18n="btn-run">运行</span> |
| 385 | </button> | 395 | </button> |
| 386 | </div> | 396 | </div> |
| 387 | </div> | 397 | </div> |
| @@ -394,72 +404,72 @@ | @@ -394,72 +404,72 @@ | ||
| 394 | <div class="col-md-3 col-lg-2 d-md-block sidebar"> | 404 | <div class="col-md-3 col-lg-2 d-md-block sidebar"> |
| 395 | <div class="d-flex justify-content-center mb-4"> | 405 | <div class="d-flex justify-content-center mb-4"> |
| 396 | <div class="btn-group"> | 406 | <div class="btn-group"> |
| 397 | - <button class="btn btn-outline-primary active" id="componentsTabBtn">组件</button> | ||
| 398 | - <button class="btn btn-outline-primary" id="templatesTabBtn">模板</button> | 407 | + <button class="btn btn-outline-primary active" id="componentsTabBtn"><span data-i18n="tab-components">组件</span></button> |
| 408 | + <button class="btn btn-outline-primary" id="templatesTabBtn"><span data-i18n="tab-templates">模板</span></button> | ||
| 399 | </div> | 409 | </div> |
| 400 | </div> | 410 | </div> |
| 401 | 411 | ||
| 402 | <!-- 组件面板保持不变 --> | 412 | <!-- 组件面板保持不变 --> |
| 403 | <div id="componentsPanel"> | 413 | <div id="componentsPanel"> |
| 404 | <div class="component-container"> | 414 | <div class="component-container"> |
| 405 | - <h6><i class="fas fa-database me-2"></i>数据源</h6> | 415 | + <h6><i class="fas fa-database me-2"></i><span data-i18n="comp-data-source">数据源</span></h6> |
| 406 | <div class="component-list"> | 416 | <div class="component-list"> |
| 407 | <div class="component-item" data-type="data_source" data-subtype="database"> | 417 | <div class="component-item" data-type="data_source" data-subtype="database"> |
| 408 | - <i class="fas fa-table me-2"></i>数据库 | 418 | + <i class="fas fa-table me-2"></i><span data-i18n="comp-database">数据库</span> |
| 409 | </div> | 419 | </div> |
| 410 | <div class="component-item" data-type="data_source" data-subtype="file"> | 420 | <div class="component-item" data-type="data_source" data-subtype="file"> |
| 411 | - <i class="fas fa-file-alt me-2"></i>文件 | 421 | + <i class="fas fa-file-alt me-2"></i><span data-i18n="comp-file">文件</span> |
| 412 | </div> | 422 | </div> |
| 413 | <div class="component-item" data-type="data_source" data-subtype="crawler"> | 423 | <div class="component-item" data-type="data_source" data-subtype="crawler"> |
| 414 | - <i class="fas fa-spider me-2"></i>爬虫 | 424 | + <i class="fas fa-spider me-2"></i><span data-i18n="comp-crawler">爬虫</span> |
| 415 | </div> | 425 | </div> |
| 416 | </div> | 426 | </div> |
| 417 | </div> | 427 | </div> |
| 418 | 428 | ||
| 419 | <div class="component-container"> | 429 | <div class="component-container"> |
| 420 | - <h6><i class="fas fa-filter me-2"></i>数据处理</h6> | 430 | + <h6><i class="fas fa-filter me-2"></i><span data-i18n="comp-data-processing">数据处理</span></h6> |
| 421 | <div class="component-list"> | 431 | <div class="component-list"> |
| 422 | <div class="component-item" data-type="preprocessing" data-subtype="filter"> | 432 | <div class="component-item" data-type="preprocessing" data-subtype="filter"> |
| 423 | - <i class="fas fa-filter me-2"></i>过滤 | 433 | + <i class="fas fa-filter me-2"></i><span data-i18n="comp-filter">过滤</span> |
| 424 | </div> | 434 | </div> |
| 425 | <div class="component-item" data-type="preprocessing" data-subtype="sort"> | 435 | <div class="component-item" data-type="preprocessing" data-subtype="sort"> |
| 426 | - <i class="fas fa-sort me-2"></i>排序 | 436 | + <i class="fas fa-sort me-2"></i><span data-i18n="comp-sort">排序</span> |
| 427 | </div> | 437 | </div> |
| 428 | <div class="component-item" data-type="preprocessing" data-subtype="aggregate"> | 438 | <div class="component-item" data-type="preprocessing" data-subtype="aggregate"> |
| 429 | - <i class="fas fa-layer-group me-2"></i>聚合 | 439 | + <i class="fas fa-layer-group me-2"></i><span data-i18n="comp-aggregate">聚合</span> |
| 430 | </div> | 440 | </div> |
| 431 | </div> | 441 | </div> |
| 432 | </div> | 442 | </div> |
| 433 | 443 | ||
| 434 | <div class="component-container"> | 444 | <div class="component-container"> |
| 435 | - <h6><i class="fas fa-brain me-2"></i>模型分析</h6> | 445 | + <h6><i class="fas fa-brain me-2"></i><span data-i18n="comp-model-analysis">模型分析</span></h6> |
| 436 | <div class="component-list"> | 446 | <div class="component-list"> |
| 437 | <div class="component-item" data-type="model" data-subtype="sentiment"> | 447 | <div class="component-item" data-type="model" data-subtype="sentiment"> |
| 438 | - <i class="fas fa-smile me-2"></i>情感分析 | 448 | + <i class="fas fa-smile me-2"></i><span data-i18n="comp-sentiment">情感分析</span> |
| 439 | </div> | 449 | </div> |
| 440 | <div class="component-item" data-type="model" data-subtype="topic"> | 450 | <div class="component-item" data-type="model" data-subtype="topic"> |
| 441 | - <i class="fas fa-tags me-2"></i>话题分类 | 451 | + <i class="fas fa-tags me-2"></i><span data-i18n="comp-topic">话题分类</span> |
| 442 | </div> | 452 | </div> |
| 443 | <div class="component-item" data-type="model" data-subtype="keywords"> | 453 | <div class="component-item" data-type="model" data-subtype="keywords"> |
| 444 | - <i class="fas fa-key me-2"></i>关键词提取 | 454 | + <i class="fas fa-key me-2"></i><span data-i18n="comp-keywords">关键词提取</span> |
| 445 | </div> | 455 | </div> |
| 446 | <div class="component-item" data-type="model" data-subtype="summarize"> | 456 | <div class="component-item" data-type="model" data-subtype="summarize"> |
| 447 | - <i class="fas fa-compress-alt me-2"></i>文本摘要 | 457 | + <i class="fas fa-compress-alt me-2"></i><span data-i18n="comp-summarize">文本摘要</span> |
| 448 | </div> | 458 | </div> |
| 449 | </div> | 459 | </div> |
| 450 | </div> | 460 | </div> |
| 451 | 461 | ||
| 452 | <div class="component-container"> | 462 | <div class="component-container"> |
| 453 | - <h6><i class="fas fa-chart-bar me-2"></i>可视化</h6> | 463 | + <h6><i class="fas fa-chart-bar me-2"></i><span data-i18n="comp-visualization">可视化</span></h6> |
| 454 | <div class="component-list"> | 464 | <div class="component-list"> |
| 455 | <div class="component-item" data-type="visualization" data-subtype="chart"> | 465 | <div class="component-item" data-type="visualization" data-subtype="chart"> |
| 456 | - <i class="fas fa-chart-line me-2"></i>图表 | 466 | + <i class="fas fa-chart-line me-2"></i><span data-i18n="comp-chart">图表</span> |
| 457 | </div> | 467 | </div> |
| 458 | <div class="component-item" data-type="visualization" data-subtype="table"> | 468 | <div class="component-item" data-type="visualization" data-subtype="table"> |
| 459 | - <i class="fas fa-table me-2"></i>表格 | 469 | + <i class="fas fa-table me-2"></i><span data-i18n="comp-table">表格</span> |
| 460 | </div> | 470 | </div> |
| 461 | <div class="component-item" data-type="visualization" data-subtype="wordcloud"> | 471 | <div class="component-item" data-type="visualization" data-subtype="wordcloud"> |
| 462 | - <i class="fas fa-cloud me-2"></i>词云 | 472 | + <i class="fas fa-cloud me-2"></i><span data-i18n="comp-wordcloud">词云</span> |
| 463 | </div> | 473 | </div> |
| 464 | </div> | 474 | </div> |
| 465 | </div> | 475 | </div> |
| @@ -469,9 +479,9 @@ | @@ -469,9 +479,9 @@ | ||
| 469 | <div id="templatesPanel" style="display: none;"> | 479 | <div id="templatesPanel" style="display: none;"> |
| 470 | <div class="mb-4"> | 480 | <div class="mb-4"> |
| 471 | <div class="d-flex justify-content-between align-items-center mb-3"> | 481 | <div class="d-flex justify-content-between align-items-center mb-3"> |
| 472 | - <h6 class="mb-0">爬虫模板</h6> | 482 | + <h6 class="mb-0"><span data-i18n="templates-crawler">爬虫模板</span></h6> |
| 473 | <button class="btn btn-sm btn-outline-primary"> | 483 | <button class="btn btn-sm btn-outline-primary"> |
| 474 | - <i class="fas fa-plus"></i> 新建 | 484 | + <i class="fas fa-plus"></i> <span data-i18n="btn-create-new">新建</span> |
| 475 | </button> | 485 | </button> |
| 476 | </div> | 486 | </div> |
| 477 | <div class="templates-wrapper"> | 487 | <div class="templates-wrapper"> |
| @@ -483,9 +493,9 @@ | @@ -483,9 +493,9 @@ | ||
| 483 | 493 | ||
| 484 | <div class="mb-4"> | 494 | <div class="mb-4"> |
| 485 | <div class="d-flex justify-content-between align-items-center mb-3"> | 495 | <div class="d-flex justify-content-between align-items-center mb-3"> |
| 486 | - <h6 class="mb-0">分析流程模板</h6> | 496 | + <h6 class="mb-0"><span data-i18n="templates-analysis">分析流程模板</span></h6> |
| 487 | <button class="btn btn-sm btn-outline-primary"> | 497 | <button class="btn btn-sm btn-outline-primary"> |
| 488 | - <i class="fas fa-plus"></i> 新建 | 498 | + <i class="fas fa-plus"></i> <span data-i18n="btn-create-new">新建</span> |
| 489 | </button> | 499 | </button> |
| 490 | </div> | 500 | </div> |
| 491 | <div class="templates-wrapper"> | 501 | <div class="templates-wrapper"> |
| @@ -502,30 +512,30 @@ | @@ -502,30 +512,30 @@ | ||
| 502 | <!-- 添加工作流工具栏 --> | 512 | <!-- 添加工作流工具栏 --> |
| 503 | <div class="d-flex justify-content-between align-items-center mb-3" id="workflowToolbar"> | 513 | <div class="d-flex justify-content-between align-items-center mb-3" id="workflowToolbar"> |
| 504 | <div class="btn-group"> | 514 | <div class="btn-group"> |
| 505 | - <button id="undoBtn" class="btn btn-sm btn-outline-secondary" title="撤销"> | 515 | + <button id="undoBtn" class="btn btn-sm btn-outline-secondary" title="撤销" data-i18n-title="btn-undo"> |
| 506 | <i class="fas fa-undo"></i> | 516 | <i class="fas fa-undo"></i> |
| 507 | </button> | 517 | </button> |
| 508 | - <button id="redoBtn" class="btn btn-sm btn-outline-secondary" title="重做"> | 518 | + <button id="redoBtn" class="btn btn-sm btn-outline-secondary" title="重做" data-i18n-title="btn-redo"> |
| 509 | <i class="fas fa-redo"></i> | 519 | <i class="fas fa-redo"></i> |
| 510 | </button> | 520 | </button> |
| 511 | - <button id="zoomInBtn" class="btn btn-sm btn-outline-secondary" title="放大"> | 521 | + <button id="zoomInBtn" class="btn btn-sm btn-outline-secondary" title="放大" data-i18n-title="btn-zoom-in"> |
| 512 | <i class="fas fa-search-plus"></i> | 522 | <i class="fas fa-search-plus"></i> |
| 513 | </button> | 523 | </button> |
| 514 | - <button id="zoomOutBtn" class="btn btn-sm btn-outline-secondary" title="缩小"> | 524 | + <button id="zoomOutBtn" class="btn btn-sm btn-outline-secondary" title="缩小" data-i18n-title="btn-zoom-out"> |
| 515 | <i class="fas fa-search-minus"></i> | 525 | <i class="fas fa-search-minus"></i> |
| 516 | </button> | 526 | </button> |
| 517 | - <button id="fitViewBtn" class="btn btn-sm btn-outline-secondary" title="适应视图"> | 527 | + <button id="fitViewBtn" class="btn btn-sm btn-outline-secondary" title="适应视图" data-i18n-title="btn-fit-view"> |
| 518 | <i class="fas fa-expand"></i> | 528 | <i class="fas fa-expand"></i> |
| 519 | </button> | 529 | </button> |
| 520 | </div> | 530 | </div> |
| 521 | <div> | 531 | <div> |
| 522 | - <button id="validateWorkflowBtn" class="btn btn-sm btn-outline-primary" title="验证工作流"> | ||
| 523 | - <i class="fas fa-check-circle"></i> 验证 | 532 | + <button id="validateWorkflowBtn" class="btn btn-sm btn-outline-primary" title="验证工作流" data-i18n-title="btn-validate"> |
| 533 | + <i class="fas fa-check-circle"></i> <span data-i18n="btn-validate">验证</span> | ||
| 524 | </button> | 534 | </button> |
| 525 | - <button id="exportWorkflowBtn" class="btn btn-sm btn-outline-secondary" title="导出工作流"> | 535 | + <button id="exportWorkflowBtn" class="btn btn-sm btn-outline-secondary" title="导出工作流" data-i18n-title="btn-export"> |
| 526 | <i class="fas fa-file-export"></i> | 536 | <i class="fas fa-file-export"></i> |
| 527 | </button> | 537 | </button> |
| 528 | - <button id="importWorkflowBtn" class="btn btn-sm btn-outline-secondary" title="导入工作流"> | 538 | + <button id="importWorkflowBtn" class="btn btn-sm btn-outline-secondary" title="导入工作流" data-i18n-title="btn-import"> |
| 529 | <i class="fas fa-file-import"></i> | 539 | <i class="fas fa-file-import"></i> |
| 530 | </button> | 540 | </button> |
| 531 | </div> | 541 | </div> |
| @@ -540,12 +550,12 @@ | @@ -540,12 +550,12 @@ | ||
| 540 | 550 | ||
| 541 | <!-- 添加工作流状态栏 --> | 551 | <!-- 添加工作流状态栏 --> |
| 542 | <div class="d-flex justify-content-between align-items-center p-2 bg-light rounded mt-3" id="workflowStatusBar" style="display: none !important;"> | 552 | <div class="d-flex justify-content-between align-items-center p-2 bg-light rounded mt-3" id="workflowStatusBar" style="display: none !important;"> |
| 543 | - <div id="workflowStatusMessage" class="text-muted"> | 553 | + <div id="workflowStatusMessage" class="text-muted" data-i18n="workflow-status-message"> |
| 544 | 工作流就绪。拖拽左侧组件到画布创建节点。 | 554 | 工作流就绪。拖拽左侧组件到画布创建节点。 |
| 545 | </div> | 555 | </div> |
| 546 | <div class="d-flex"> | 556 | <div class="d-flex"> |
| 547 | - <div class="me-3">节点: <span id="nodeCount">0</span></div> | ||
| 548 | - <div>连接: <span id="connectionCount">0</span></div> | 557 | + <div class="me-3"><span data-i18n="nodes">节点</span>: <span id="nodeCount">0</span></div> |
| 558 | + <div><span data-i18n="connections">连接</span>: <span id="connectionCount">0</span></div> | ||
| 549 | </div> | 559 | </div> |
| 550 | </div> | 560 | </div> |
| 551 | </div> | 561 | </div> |
| @@ -555,7 +565,7 @@ | @@ -555,7 +565,7 @@ | ||
| 555 | <!-- 属性面板 --> | 565 | <!-- 属性面板 --> |
| 556 | <div class="properties-panel" id="propertiesPanel"> | 566 | <div class="properties-panel" id="propertiesPanel"> |
| 557 | <div class="d-flex justify-content-between align-items-center mb-3"> | 567 | <div class="d-flex justify-content-between align-items-center mb-3"> |
| 558 | - <h5 class="mb-0">组件属性</h5> | 568 | + <h5 class="mb-0"><span data-i18n="properties-title">组件属性</span></h5> |
| 559 | <button class="btn-close" id="closePropertiesBtn"></button> | 569 | <button class="btn-close" id="closePropertiesBtn"></button> |
| 560 | </div> | 570 | </div> |
| 561 | <div id="propertiesContent"> | 571 | <div id="propertiesContent"> |
| @@ -568,35 +578,35 @@ | @@ -568,35 +578,35 @@ | ||
| 568 | <div class="modal-dialog"> | 578 | <div class="modal-dialog"> |
| 569 | <div class="modal-content"> | 579 | <div class="modal-content"> |
| 570 | <div class="modal-header"> | 580 | <div class="modal-header"> |
| 571 | - <h5 class="modal-title">保存为模板</h5> | 581 | + <h5 class="modal-title" data-i18n="modal-save-template">保存为模板</h5> |
| 572 | <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | 582 | <button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
| 573 | </div> | 583 | </div> |
| 574 | <div class="modal-body"> | 584 | <div class="modal-body"> |
| 575 | <form id="saveTemplateForm"> | 585 | <form id="saveTemplateForm"> |
| 576 | <div class="mb-3"> | 586 | <div class="mb-3"> |
| 577 | - <label for="templateName" class="form-label">模板名称</label> | 587 | + <label for="templateName" class="form-label" data-i18n="template-name">模板名称</label> |
| 578 | <input type="text" class="form-control" id="templateName" required> | 588 | <input type="text" class="form-control" id="templateName" required> |
| 579 | </div> | 589 | </div> |
| 580 | <div class="mb-3"> | 590 | <div class="mb-3"> |
| 581 | - <label for="templateDescription" class="form-label">描述</label> | 591 | + <label for="templateDescription" class="form-label" data-i18n="template-description">描述</label> |
| 582 | <textarea class="form-control" id="templateDescription" rows="3"></textarea> | 592 | <textarea class="form-control" id="templateDescription" rows="3"></textarea> |
| 583 | </div> | 593 | </div> |
| 584 | <div class="mb-3"> | 594 | <div class="mb-3"> |
| 585 | - <label for="templateIcon" class="form-label">图标</label> | 595 | + <label for="templateIcon" class="form-label" data-i18n="template-icon">图标</label> |
| 586 | <select class="form-select" id="templateIcon"> | 596 | <select class="form-select" id="templateIcon"> |
| 587 | - <option value="chart-line">📊 图表</option> | ||
| 588 | - <option value="filter">🔍 过滤</option> | ||
| 589 | - <option value="spider">🕸️ 爬虫</option> | ||
| 590 | - <option value="brain">🧠 AI分析</option> | ||
| 591 | - <option value="database">💾 数据库</option> | ||
| 592 | - <option value="cloud">☁️ 词云</option> | 597 | + <option value="chart-line">📊 <span data-i18n="icon-chart">图表</span></option> |
| 598 | + <option value="filter">🔍 <span data-i18n="icon-filter">过滤</span></option> | ||
| 599 | + <option value="spider">🕸️ <span data-i18n="icon-crawler">爬虫</span></option> | ||
| 600 | + <option value="brain">🧠 <span data-i18n="icon-ai">AI分析</span></option> | ||
| 601 | + <option value="database">💾 <span data-i18n="icon-database">数据库</span></option> | ||
| 602 | + <option value="cloud">☁️ <span data-i18n="icon-wordcloud">词云</span></option> | ||
| 593 | </select> | 603 | </select> |
| 594 | </div> | 604 | </div> |
| 595 | </form> | 605 | </form> |
| 596 | </div> | 606 | </div> |
| 597 | <div class="modal-footer"> | 607 | <div class="modal-footer"> |
| 598 | - <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> | ||
| 599 | - <button type="button" class="btn btn-primary" id="saveTemplateBtn">保存</button> | 608 | + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" data-i18n="btn-cancel">取消</button> |
| 609 | + <button type="button" class="btn btn-primary" id="saveTemplateBtn" data-i18n="btn-save">保存</button> | ||
| 600 | </div> | 610 | </div> |
| 601 | </div> | 611 | </div> |
| 602 | </div> | 612 | </div> |
| @@ -606,21 +616,21 @@ | @@ -606,21 +616,21 @@ | ||
| 606 | <div class="modal-dialog"> | 616 | <div class="modal-dialog"> |
| 607 | <div class="modal-content"> | 617 | <div class="modal-content"> |
| 608 | <div class="modal-header"> | 618 | <div class="modal-header"> |
| 609 | - <h5 class="modal-title">运行工作流</h5> | 619 | + <h5 class="modal-title" data-i18n="modal-run-workflow">运行工作流</h5> |
| 610 | <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | 620 | <button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
| 611 | </div> | 621 | </div> |
| 612 | <div class="modal-body"> | 622 | <div class="modal-body"> |
| 613 | - <p>确认要运行当前工作流吗?</p> | 623 | + <p data-i18n="run-workflow-confirm">确认要运行当前工作流吗?</p> |
| 614 | <div class="form-check mb-3"> | 624 | <div class="form-check mb-3"> |
| 615 | <input class="form-check-input" type="checkbox" id="saveBeforeRun" checked> | 625 | <input class="form-check-input" type="checkbox" id="saveBeforeRun" checked> |
| 616 | - <label class="form-check-label" for="saveBeforeRun"> | 626 | + <label class="form-check-label" for="saveBeforeRun" data-i18n="save-before-run"> |
| 617 | 运行前保存工作流 | 627 | 运行前保存工作流 |
| 618 | </label> | 628 | </label> |
| 619 | </div> | 629 | </div> |
| 620 | </div> | 630 | </div> |
| 621 | <div class="modal-footer"> | 631 | <div class="modal-footer"> |
| 622 | - <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button> | ||
| 623 | - <button type="button" class="btn btn-primary" id="confirmRunBtn">运行</button> | 632 | + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" data-i18n="btn-cancel">取消</button> |
| 633 | + <button type="button" class="btn btn-primary" id="confirmRunBtn" data-i18n="btn-run">运行</button> | ||
| 624 | </div> | 634 | </div> |
| 625 | </div> | 635 | </div> |
| 626 | </div> | 636 | </div> |
| @@ -630,13 +640,13 @@ | @@ -630,13 +640,13 @@ | ||
| 630 | <div class="modal-dialog modal-lg"> | 640 | <div class="modal-dialog modal-lg"> |
| 631 | <div class="modal-content"> | 641 | <div class="modal-content"> |
| 632 | <div class="modal-header"> | 642 | <div class="modal-header"> |
| 633 | - <h5 class="modal-title">任务执行状态</h5> | 643 | + <h5 class="modal-title" data-i18n="modal-task-status">任务执行状态</h5> |
| 634 | <button type="button" class="btn-close" data-bs-dismiss="modal"></button> | 644 | <button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
| 635 | </div> | 645 | </div> |
| 636 | <div class="modal-body"> | 646 | <div class="modal-body"> |
| 637 | <div class="mb-3"> | 647 | <div class="mb-3"> |
| 638 | <h6 class="d-flex align-items-center"> | 648 | <h6 class="d-flex align-items-center"> |
| 639 | - <i class="fas fa-tasks me-2"></i>进度 | 649 | + <i class="fas fa-tasks me-2"></i><span data-i18n="task-progress">进度</span> |
| 640 | <div class="ms-auto" id="taskProgressPercentage">0%</div> | 650 | <div class="ms-auto" id="taskProgressPercentage">0%</div> |
| 641 | </h6> | 651 | </h6> |
| 642 | <div class="progress" style="height: 10px;"> | 652 | <div class="progress" style="height: 10px;"> |
| @@ -645,46 +655,46 @@ | @@ -645,46 +655,46 @@ | ||
| 645 | </div> | 655 | </div> |
| 646 | <div class="mb-3"> | 656 | <div class="mb-3"> |
| 647 | <h6 class="d-flex align-items-center"> | 657 | <h6 class="d-flex align-items-center"> |
| 648 | - <i class="fas fa-info-circle me-2"></i>状态信息 | ||
| 649 | - <span id="taskStatusBadge" class="ms-2 badge bg-info">等待中</span> | 658 | + <i class="fas fa-info-circle me-2"></i><span data-i18n="task-status-info">状态信息</span> |
| 659 | + <span id="taskStatusBadge" class="ms-2 badge bg-info" data-i18n="task-waiting">等待中</span> | ||
| 650 | </h6> | 660 | </h6> |
| 651 | <div id="taskStatusInfo" class="p-3 bg-light rounded border"> | 661 | <div id="taskStatusInfo" class="p-3 bg-light rounded border"> |
| 652 | <div class="row g-2"> | 662 | <div class="row g-2"> |
| 653 | <div class="col-md-6"> | 663 | <div class="col-md-6"> |
| 654 | - <p class="mb-1"><strong>任务ID:</strong> <span id="taskIdDisplay">-</span></p> | ||
| 655 | - <p class="mb-1"><strong>状态:</strong> <span id="taskStatusDisplay">-</span></p> | 664 | + <p class="mb-1"><strong data-i18n="task-id">任务ID:</strong> <span id="taskIdDisplay">-</span></p> |
| 665 | + <p class="mb-1"><strong data-i18n="task-status">状态:</strong> <span id="taskStatusDisplay">-</span></p> | ||
| 656 | </div> | 666 | </div> |
| 657 | <div class="col-md-6"> | 667 | <div class="col-md-6"> |
| 658 | - <p class="mb-1"><strong>开始时间:</strong> <span id="taskStartTimeDisplay">-</span></p> | ||
| 659 | - <p class="mb-1"><strong>完成时间:</strong> <span id="taskCompleteTimeDisplay">-</span></p> | 668 | + <p class="mb-1"><strong data-i18n="task-start-time">开始时间:</strong> <span id="taskStartTimeDisplay">-</span></p> |
| 669 | + <p class="mb-1"><strong data-i18n="task-complete-time">完成时间:</strong> <span id="taskCompleteTimeDisplay">-</span></p> | ||
| 660 | </div> | 670 | </div> |
| 661 | </div> | 671 | </div> |
| 662 | <div class="mt-2" id="taskDetailsContainer"> | 672 | <div class="mt-2" id="taskDetailsContainer"> |
| 663 | - <p class="mb-1"><strong>当前步骤:</strong> <span id="taskCurrentStepDisplay">等待开始</span></p> | ||
| 664 | - <p class="mb-0"><strong>耗时:</strong> <span id="taskElapsedTimeDisplay">0秒</span></p> | 673 | + <p class="mb-1"><strong data-i18n="task-current-step">当前步骤:</strong> <span id="taskCurrentStepDisplay" data-i18n="waiting-to-start">等待开始</span></p> |
| 674 | + <p class="mb-0"><strong data-i18n="task-elapsed-time">耗时:</strong> <span id="taskElapsedTimeDisplay">0秒</span></p> | ||
| 665 | </div> | 675 | </div> |
| 666 | </div> | 676 | </div> |
| 667 | </div> | 677 | </div> |
| 668 | <div> | 678 | <div> |
| 669 | <h6 class="d-flex align-items-center"> | 679 | <h6 class="d-flex align-items-center"> |
| 670 | - <i class="fas fa-chart-bar me-2"></i>结果预览 | ||
| 671 | - <button class="btn btn-sm btn-outline-secondary ms-auto" id="refreshPreviewBtn" title="刷新预览"> | 680 | + <i class="fas fa-chart-bar me-2"></i><span data-i18n="task-result-preview">结果预览</span> |
| 681 | + <button class="btn btn-sm btn-outline-secondary ms-auto" id="refreshPreviewBtn" title="刷新预览" data-i18n-title="refresh-preview"> | ||
| 672 | <i class="fas fa-sync-alt"></i> | 682 | <i class="fas fa-sync-alt"></i> |
| 673 | </button> | 683 | </button> |
| 674 | </h6> | 684 | </h6> |
| 675 | <div id="taskResultPreview" class="p-3 bg-light rounded border" style="max-height: 300px; overflow: auto;"> | 685 | <div id="taskResultPreview" class="p-3 bg-light rounded border" style="max-height: 300px; overflow: auto;"> |
| 676 | <div class="text-center py-4" id="previewLoadingIndicator"> | 686 | <div class="text-center py-4" id="previewLoadingIndicator"> |
| 677 | <div class="spinner-border text-primary" role="status"> | 687 | <div class="spinner-border text-primary" role="status"> |
| 678 | - <span class="visually-hidden">加载中...</span> | 688 | + <span class="visually-hidden" data-i18n="loading">加载中...</span> |
| 679 | </div> | 689 | </div> |
| 680 | - <p class="text-muted mt-2">任务运行中,正在准备预览数据...</p> | 690 | + <p class="text-muted mt-2" data-i18n="task-running-preparing">任务运行中,正在准备预览数据...</p> |
| 681 | </div> | 691 | </div> |
| 682 | <div id="previewContent" style="display: none;"> | 692 | <div id="previewContent" style="display: none;"> |
| 683 | - <p class="text-muted">任务完成后将显示结果预览...</p> | 693 | + <p class="text-muted" data-i18n="preview-after-task">任务完成后将显示结果预览...</p> |
| 684 | </div> | 694 | </div> |
| 685 | <div id="previewError" class="alert alert-danger" style="display: none;"> | 695 | <div id="previewError" class="alert alert-danger" style="display: none;"> |
| 686 | <i class="fas fa-exclamation-triangle me-2"></i> | 696 | <i class="fas fa-exclamation-triangle me-2"></i> |
| 687 | - <span id="errorMessage">加载预览时发生错误</span> | 697 | + <span id="errorMessage" data-i18n="preview-error">加载预览时发生错误</span> |
| 688 | </div> | 698 | </div> |
| 689 | </div> | 699 | </div> |
| 690 | <div class="mt-2 text-end"> | 700 | <div class="mt-2 text-end"> |
| @@ -695,13 +705,13 @@ | @@ -695,13 +705,13 @@ | ||
| 695 | <div class="modal-footer d-flex justify-content-between"> | 705 | <div class="modal-footer d-flex justify-content-between"> |
| 696 | <div> | 706 | <div> |
| 697 | <button type="button" class="btn btn-danger" id="cancelTaskBtn"> | 707 | <button type="button" class="btn btn-danger" id="cancelTaskBtn"> |
| 698 | - <i class="fas fa-stop-circle me-1"></i>取消任务 | 708 | + <i class="fas fa-stop-circle me-1"></i><span data-i18n="btn-cancel-task">取消任务</span> |
| 699 | </button> | 709 | </button> |
| 700 | </div> | 710 | </div> |
| 701 | <div> | 711 | <div> |
| 702 | - <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button> | 712 | + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal" data-i18n="btn-close">关闭</button> |
| 703 | <button type="button" class="btn btn-primary" id="viewResultBtn"> | 713 | <button type="button" class="btn btn-primary" id="viewResultBtn"> |
| 704 | - <i class="fas fa-external-link-alt me-1"></i>查看完整结果 | 714 | + <i class="fas fa-external-link-alt me-1"></i><span data-i18n="btn-view-full-result">查看完整结果</span> |
| 705 | </button> | 715 | </button> |
| 706 | </div> | 716 | </div> |
| 707 | </div> | 717 | </div> |
| @@ -715,6 +725,10 @@ | @@ -715,6 +725,10 @@ | ||
| 715 | <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script> | 725 | <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script> |
| 716 | <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.bundle.min.js"></script> | 726 | <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/js/bootstrap.bundle.min.js"></script> |
| 717 | <script src="https://cdn.jsdelivr.net/npm/jsoneditor@9.5.0/dist/jsoneditor.min.js"></script> | 727 | <script src="https://cdn.jsdelivr.net/npm/jsoneditor@9.5.0/dist/jsoneditor.min.js"></script> |
| 728 | + <!-- 添加i18next库 --> | ||
| 729 | + <script src="https://cdn.jsdelivr.net/npm/i18next@21.8.10/i18next.min.js"></script> | ||
| 730 | + <script src="https://cdn.jsdelivr.net/npm/jquery-i18next@1.2.1/jquery-i18next.min.js"></script> | ||
| 731 | + <script src="\static\js\i18n\translations.js"></script> | ||
| 718 | <script src="\static\js\workflow_editor.js"></script> | 732 | <script src="\static\js\workflow_editor.js"></script> |
| 719 | </body> | 733 | </body> |
| 720 | </html> | 734 | </html> |
-
Please register or login to post a comment