diff --git a/static/js/i18n/spider_translations.js b/static/js/i18n/spider_translations.js new file mode 100644 index 0000000..42f3f69 --- /dev/null +++ b/static/js/i18n/spider_translations.js @@ -0,0 +1,267 @@ +// 爬虫控制面板翻译资源文件 +// 包含中文(zh-CN)和英文(en-US)的翻译 + +const spiderI18nResources = { + 'zh-CN': { + translation: { + // 页面标题和导航 + 'page-title': '爬虫控制面板', + + // 卡片标题 + 'topic-selection': '选择话题类型', + 'spider-parameters': '爬虫参数配置', + 'content-filters': '内容筛选配置', + 'account-config': '账号配置', + 'parallel-config': '并行配置', + 'db-config': '数据库配置', + 'ai-assistant': 'AI配置助手', + 'spider-status': '爬虫状态', + + // 话题选择部分 + 'add-custom-topic': '添加自定义话题', + 'custom-topic-placeholder': '输入自定义话题', + 'btn-add': '添加', + 'selected-topics': '已选择的话题:', + + // 爬虫参数部分 + 'crawl-depth': '爬取深度', + 'crawl-depth-hint': '每个话题爬取的页数(1-10)', + 'interval': '爬取间隔(秒)', + 'interval-hint': '每次请求之间的间隔时间', + 'max-retries': '最大重试次数', + 'timeout': '请求超时时间(秒)', + + // 筛选器部分 + 'help': '帮助', + 'filter-conditions': '筛选条件说明:', + 'filter-condition-1': '数值条件:设置大于某个值进行筛选,如点赞数>1000', + 'filter-condition-2': '正则匹配:使用正则表达式匹配内容,如包含特定关键词', + 'filter-condition-3': '多个条件之间是"与"的关系,即同时满足才会保留', + 'filter-tip': '提示:合理设置筛选条件可以提高数据质量', + 'interaction-filter': '互动数据筛选', + 'likes-gt': '点赞数大于', + 'comments-gt': '评论数大于', + 'reposts-gt': '转发数大于', + 'reads-gt': '阅读数大于', + 'regex-filter': '内容正则筛选', + 'add-regex-filter': '添加正则筛选', + 'advanced-options': '高级选项', + 'only-original': '仅爬取原创内容', + 'must-have-media': '必须包含图片或视频', + 'only-verified': '仅认证用户的内容', + + // 账号配置部分 + 'btn-add-account': '添加账号', + 'how-to-get-cookie': '如何获取Cookie?', + 'cookie-step-1': '登录微博网页版', + 'cookie-step-2': '按F12打开开发者工具', + 'cookie-step-3': '切换到Network标签页', + 'cookie-step-4': '刷新页面,找到请求头中的Cookie值', + 'cookie-warning': '注意:请勿泄露您的Cookie信息!', + 'account-tip': '提示:添加多个账号可以提高爬取效率,系统会自动在账号间轮换。', + 'no-account-warning': '请至少添加一个账号', + 'username': '用户名', + 'username-placeholder': '微博用户名', + 'password': '密码', + 'password-placeholder': '微博密码', + 'cookie': 'Cookie', + 'cookie-placeholder': '请输入微博Cookie', + 'save-cookie': '保存Cookie(加密存储)', + 'status-pending': '状态:待验证', + 'btn-validate-account': '验证账号', + 'status-validating': '状态:验证中...', + 'status-success': '状态:验证成功', + 'status-failed': '状态:验证失败 - ', + 'error-empty-cookie': 'Cookie不能为空', + + // 正则筛选器 + 'regex-pattern': '正则表达式', + 'regex-pattern-placeholder': '输入正则表达式', + 'match-target': '匹配目标', + 'target-content': '微博内容', + 'target-author': '作者名', + 'target-location': '发布位置', + 'inverse-match': '反向匹配(不包含匹配项)', + + // 并行配置 + 'max-concurrent': '最大并行数', + 'max-concurrent-hint': '同时进行爬取的最大话题数(1-5)', + 'requests-per-minute': '每分钟请求数限制', + 'requests-per-minute-hint': '避免请求过于频繁(30-120)', + + // 数据库配置 + 'db-type': '数据库类型', + 'host': '主机地址', + 'port': '端口', + 'db-name': '数据库名', + 'username-db': '用户名', + 'password-db': '密码', + 'btn-test-connection': '测试连接', + 'db-connect-success': '数据库连接测试成功!', + 'db-connect-fail': '数据库连接测试失败:', + 'db-connect-error': '测试连接时发生错误:', + + // AI配置助手 + 'ai-prompt-label': '用自然语言描述您的爬虫需求', + 'ai-prompt-placeholder': '例如:我想爬取最近一周关于人工智能的热门微博,重点关注转发量超过1000的内容,每个话题爬取前5页内容。', + 'btn-generate-config': '生成配置', + 'auto-apply': '自动应用生成的配置', + 'ai-suggestion': 'AI助手建议:', + 'ai-config-applied': 'AI配置已自动应用', + 'ai-config-error': '生成配置时出错:', + 'empty-prompt-error': '请输入您的爬虫需求描述!', + + // 操作按钮 + 'btn-start': '开始爬取', + 'btn-save-config': '保存配置', + 'config-saved': '配置已保存!', + 'save-failed': '保存失败:', + 'save-error': '保存出错:', + + // 爬虫状态 + 'task-started': '爬虫任务已启动...', + 'start-failed': '启动失败:', + 'error': '错误:', + + // 验证错误提示 + 'select-topic-error': '请至少选择一个话题!', + 'invalid-regex-error': '正则表达式 "{0}" 格式无效!', + 'need-account-error': '请至少添加一个账号!', + 'empty-cookie-error': '存在未配置Cookie的账号,请检查!', + 'concurrent-limit-error': '最大并行数必须在1-5之间!', + 'request-limit-error': '每分钟请求数必须在30-120之间!', + 'db-config-error': '请完整填写数据库配置信息!' + } + }, + 'en-US': { + translation: { + // Page title and navigation + 'page-title': 'Spider Control Panel', + + // Card titles + 'topic-selection': 'Select Topic Types', + 'spider-parameters': 'Spider Parameters', + 'content-filters': 'Content Filters', + 'account-config': 'Account Configuration', + 'parallel-config': 'Parallel Configuration', + 'db-config': 'Database Configuration', + 'ai-assistant': 'AI Configuration Assistant', + 'spider-status': 'Spider Status', + + // Topic selection section + 'add-custom-topic': 'Add Custom Topic', + 'custom-topic-placeholder': 'Enter custom topic', + 'btn-add': 'Add', + 'selected-topics': 'Selected Topics:', + + // Spider parameters section + 'crawl-depth': 'Crawl Depth', + 'crawl-depth-hint': 'Number of pages to crawl for each topic (1-10)', + 'interval': 'Interval (seconds)', + 'interval-hint': 'Time between requests', + 'max-retries': 'Maximum Retries', + 'timeout': 'Request Timeout (seconds)', + + // Filters section + 'help': 'Help', + 'filter-conditions': 'Filter conditions:', + 'filter-condition-1': 'Numeric conditions: Set values to filter by, e.g., likes > 1000', + 'filter-condition-2': 'Regex matching: Use regular expressions to match content, e.g., contain specific keywords', + 'filter-condition-3': 'Multiple conditions are combined with AND logic', + 'filter-tip': 'Tip: Setting proper filters can improve data quality', + 'interaction-filter': 'Interaction Data Filters', + 'likes-gt': 'Likes greater than', + 'comments-gt': 'Comments greater than', + 'reposts-gt': 'Reposts greater than', + 'reads-gt': 'Reads greater than', + 'regex-filter': 'Content Regex Filters', + 'add-regex-filter': 'Add Regex Filter', + 'advanced-options': 'Advanced Options', + 'only-original': 'Only crawl original content', + 'must-have-media': 'Must contain images or videos', + 'only-verified': 'Only content from verified users', + + // Account configuration section + 'btn-add-account': 'Add Account', + 'how-to-get-cookie': 'How to get the Cookie?', + 'cookie-step-1': 'Login to Weibo web version', + 'cookie-step-2': 'Press F12 to open developer tools', + 'cookie-step-3': 'Switch to Network tab', + 'cookie-step-4': 'Refresh page and find Cookie value in request headers', + 'cookie-warning': 'Warning: Do not expose your Cookie information!', + 'account-tip': 'Tip: Adding multiple accounts can improve crawling efficiency, the system will automatically rotate between accounts.', + 'no-account-warning': 'Please add at least one account', + 'username': 'Username', + 'username-placeholder': 'Weibo username', + 'password': 'Password', + 'password-placeholder': 'Weibo password', + 'cookie': 'Cookie', + 'cookie-placeholder': 'Please enter Weibo Cookie', + 'save-cookie': 'Save Cookie (encrypted storage)', + 'status-pending': 'Status: Pending verification', + 'btn-validate-account': 'Validate Account', + 'status-validating': 'Status: Validating...', + 'status-success': 'Status: Validation successful', + 'status-failed': 'Status: Validation failed - ', + 'error-empty-cookie': 'Cookie cannot be empty', + + // Regex filters + 'regex-pattern': 'Regular Expression', + 'regex-pattern-placeholder': 'Enter regular expression', + 'match-target': 'Match Target', + 'target-content': 'Weibo content', + 'target-author': 'Author name', + 'target-location': 'Posting location', + 'inverse-match': 'Inverse match (exclude matches)', + + // Parallel configuration + 'max-concurrent': 'Maximum Concurrent Tasks', + 'max-concurrent-hint': 'Maximum number of topics to crawl simultaneously (1-5)', + 'requests-per-minute': 'Requests Per Minute Limit', + 'requests-per-minute-hint': 'Avoid too frequent requests (30-120)', + + // Database configuration + 'db-type': 'Database Type', + 'host': 'Host', + 'port': 'Port', + 'db-name': 'Database Name', + 'username-db': 'Username', + 'password-db': 'Password', + 'btn-test-connection': 'Test Connection', + 'db-connect-success': 'Database connection test successful!', + 'db-connect-fail': 'Database connection test failed: ', + 'db-connect-error': 'Error while testing connection: ', + + // AI assistant + 'ai-prompt-label': 'Describe your crawling requirements in natural language', + '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.', + 'btn-generate-config': 'Generate Configuration', + 'auto-apply': 'Auto-apply generated configuration', + 'ai-suggestion': 'AI Assistant Suggestion:', + 'ai-config-applied': 'AI configuration applied automatically', + 'ai-config-error': 'Error generating configuration: ', + 'empty-prompt-error': 'Please enter your crawler requirements!', + + // Action buttons + 'btn-start': 'Start Crawling', + 'btn-save-config': 'Save Configuration', + 'config-saved': 'Configuration saved!', + 'save-failed': 'Save failed: ', + 'save-error': 'Error saving: ', + + // Spider status + 'task-started': 'Crawler task started...', + 'start-failed': 'Start failed: ', + 'error': 'Error: ', + + // Validation error messages + 'select-topic-error': 'Please select at least one topic!', + 'invalid-regex-error': 'Regular expression "{0}" is invalid!', + 'need-account-error': 'Please add at least one account!', + 'empty-cookie-error': 'There are accounts without Cookie configuration, please check!', + 'concurrent-limit-error': 'Maximum concurrent tasks must be between 1-5!', + 'request-limit-error': 'Requests per minute must be between 30-120!', + 'db-config-error': 'Please complete all database configuration fields!' + } + } +}; \ No newline at end of file diff --git a/static/js/i18n/translations.js b/static/js/i18n/translations.js new file mode 100644 index 0000000..adc20f9 --- /dev/null +++ b/static/js/i18n/translations.js @@ -0,0 +1,209 @@ +// 翻译资源文件 +// 包含中文(zh-CN)和英文(en-US)的翻译 + +const i18nResources = { + 'zh-CN': { + translation: { + // 页面标题 + 'page-title': '工作流编辑器 - 微博舆情分析系统', + 'navbar-brand': '工作流编辑器', + + // 导航菜单 + 'nav-visual-editor': '可视化编辑', + 'nav-template-mgmt': '模板管理', + 'nav-task-list': '任务列表', + + // 按钮 + 'btn-save': '保存', + 'btn-run': '运行', + 'btn-cancel': '取消', + 'btn-close': '关闭', + 'btn-create-new': '新建', + 'btn-validate': '验证', + 'btn-undo': '撤销', + 'btn-redo': '重做', + 'btn-zoom-in': '放大', + 'btn-zoom-out': '缩小', + 'btn-fit-view': '适应视图', + 'btn-export': '导出工作流', + 'btn-import': '导入工作流', + 'btn-cancel-task': '取消任务', + 'btn-view-full-result': '查看完整结果', + + // 选项卡 + 'tab-components': '组件', + 'tab-templates': '模板', + + // 组件类别 + 'comp-data-source': '数据源', + 'comp-data-processing': '数据处理', + 'comp-model-analysis': '模型分析', + 'comp-visualization': '可视化', + + // 组件 + 'comp-database': '数据库', + 'comp-file': '文件', + 'comp-crawler': '爬虫', + 'comp-filter': '过滤', + 'comp-sort': '排序', + 'comp-aggregate': '聚合', + 'comp-sentiment': '情感分析', + 'comp-topic': '话题分类', + 'comp-keywords': '关键词提取', + 'comp-summarize': '文本摘要', + 'comp-chart': '图表', + 'comp-table': '表格', + 'comp-wordcloud': '词云', + + // 模板相关 + 'templates-crawler': '爬虫模板', + 'templates-analysis': '分析流程模板', + 'modal-save-template': '保存为模板', + 'template-name': '模板名称', + 'template-description': '描述', + 'template-icon': '图标', + + // 图标名称 + 'icon-chart': '图表', + 'icon-filter': '过滤', + 'icon-crawler': '爬虫', + 'icon-ai': 'AI分析', + 'icon-database': '数据库', + 'icon-wordcloud': '词云', + + // 属性面板 + 'properties-title': '组件属性', + + // 工作流状态 + 'workflow-status-message': '工作流就绪。拖拽左侧组件到画布创建节点。', + 'nodes': '节点', + 'connections': '连接', + + // 运行工作流 + 'modal-run-workflow': '运行工作流', + 'run-workflow-confirm': '确认要运行当前工作流吗?', + 'save-before-run': '运行前保存工作流', + + // 任务状态 + 'modal-task-status': '任务执行状态', + 'task-progress': '进度', + 'task-status-info': '状态信息', + 'task-waiting': '等待中', + 'task-id': '任务ID:', + 'task-status': '状态:', + 'task-start-time': '开始时间:', + 'task-complete-time': '完成时间:', + 'task-current-step': '当前步骤:', + 'waiting-to-start': '等待开始', + 'task-elapsed-time': '耗时:', + 'task-result-preview': '结果预览', + 'refresh-preview': '刷新预览', + 'loading': '加载中...', + 'task-running-preparing': '任务运行中,正在准备预览数据...', + 'preview-after-task': '任务完成后将显示结果预览...', + 'preview-error': '加载预览时发生错误' + } + }, + 'en-US': { + translation: { + // Page title + 'page-title': 'Workflow Editor - Weibo Public Opinion Analysis System', + 'navbar-brand': 'Workflow Editor', + + // Navigation menu + 'nav-visual-editor': 'Visual Editor', + 'nav-template-mgmt': 'Template Management', + 'nav-task-list': 'Task List', + + // Buttons + 'btn-save': 'Save', + 'btn-run': 'Run', + 'btn-cancel': 'Cancel', + 'btn-close': 'Close', + 'btn-create-new': 'Create New', + 'btn-validate': 'Validate', + 'btn-undo': 'Undo', + 'btn-redo': 'Redo', + 'btn-zoom-in': 'Zoom In', + 'btn-zoom-out': 'Zoom Out', + 'btn-fit-view': 'Fit View', + 'btn-export': 'Export Workflow', + 'btn-import': 'Import Workflow', + 'btn-cancel-task': 'Cancel Task', + 'btn-view-full-result': 'View Full Results', + + // Tabs + 'tab-components': 'Components', + 'tab-templates': 'Templates', + + // Component categories + 'comp-data-source': 'Data Sources', + 'comp-data-processing': 'Data Processing', + 'comp-model-analysis': 'Model Analysis', + 'comp-visualization': 'Visualization', + + // Components + 'comp-database': 'Database', + 'comp-file': 'File', + 'comp-crawler': 'Crawler', + 'comp-filter': 'Filter', + 'comp-sort': 'Sort', + 'comp-aggregate': 'Aggregate', + 'comp-sentiment': 'Sentiment Analysis', + 'comp-topic': 'Topic Classification', + 'comp-keywords': 'Keyword Extraction', + 'comp-summarize': 'Text Summarization', + 'comp-chart': 'Chart', + 'comp-table': 'Table', + 'comp-wordcloud': 'Word Cloud', + + // Template related + 'templates-crawler': 'Crawler Templates', + 'templates-analysis': 'Analysis Flow Templates', + 'modal-save-template': 'Save as Template', + 'template-name': 'Template Name', + 'template-description': 'Description', + 'template-icon': 'Icon', + + // Icon names + 'icon-chart': 'Chart', + 'icon-filter': 'Filter', + 'icon-crawler': 'Crawler', + 'icon-ai': 'AI Analysis', + 'icon-database': 'Database', + 'icon-wordcloud': 'Word Cloud', + + // Properties panel + 'properties-title': 'Component Properties', + + // Workflow status + 'workflow-status-message': 'Workflow ready. Drag components from the left panel to create nodes.', + 'nodes': 'Nodes', + 'connections': 'Connections', + + // Run workflow + 'modal-run-workflow': 'Run Workflow', + 'run-workflow-confirm': 'Are you sure you want to run the current workflow?', + 'save-before-run': 'Save workflow before running', + + // Task status + 'modal-task-status': 'Task Execution Status', + 'task-progress': 'Progress', + 'task-status-info': 'Status Information', + 'task-waiting': 'Waiting', + 'task-id': 'Task ID:', + 'task-status': 'Status:', + 'task-start-time': 'Start Time:', + 'task-complete-time': 'Complete Time:', + 'task-current-step': 'Current Step:', + 'waiting-to-start': 'Waiting to start', + 'task-elapsed-time': 'Elapsed Time:', + 'task-result-preview': 'Result Preview', + 'refresh-preview': 'Refresh Preview', + 'loading': 'Loading...', + 'task-running-preparing': 'Task is running, preparing preview data...', + 'preview-after-task': 'Results preview will be displayed after the task is completed...', + 'preview-error': 'Error loading preview' + } + } +}; \ No newline at end of file diff --git a/static/js/workflow_editor.js b/static/js/workflow_editor.js index 5f44a4d..e2afbbb 100644 --- a/static/js/workflow_editor.js +++ b/static/js/workflow_editor.js @@ -1,5 +1,65 @@ let workflowEditorInitialized = false; +// 初始化i18next多语言支持 +function initializeI18n() { + // 获取浏览器语言,默认为中文 + const browserLang = navigator.language || 'zh-CN'; + const defaultLang = browserLang.startsWith('zh') ? 'zh-CN' : 'en-US'; + + // 初始化i18next + i18next.init({ + lng: localStorage.getItem('preferred_language') || defaultLang, + resources: i18nResources, + fallbackLng: 'zh-CN', + }).then(function(t) { + // 更新当前语言显示 + updateLanguageDisplay(); + + // 应用翻译到所有元素 + applyTranslations(); + }); +} + +// 更新语言显示 +function updateLanguageDisplay() { + const currentLang = i18next.language; + const displayName = currentLang === 'zh-CN' ? '中文' : 'English'; + document.getElementById('currentLanguage').textContent = displayName; +} + +// 应用翻译到所有元素 +function applyTranslations() { + // 翻译data-i18n属性的元素 + document.querySelectorAll('[data-i18n]').forEach(element => { + const key = element.getAttribute('data-i18n'); + element.textContent = i18next.t(key); + }); + + // 翻译title属性 + document.querySelectorAll('[data-i18n-title]').forEach(element => { + const key = element.getAttribute('data-i18n-title'); + element.title = i18next.t(key); + }); + + // 更新页面标题 + document.title = i18next.t('page-title'); +} + +// 切换语言 +function switchLanguage(lang) { + // 保存语言偏好到本地存储 + localStorage.setItem('preferred_language', lang); + + // 更改i18next语言 + i18next.changeLanguage(lang).then(() => { + // 更新语言显示 + updateLanguageDisplay(); + + // 应用翻译 + applyTranslations(); + }); +} + document.addEventListener('DOMContentLoaded', function() { // 检查是否已初始化,防止多次执行 if (workflowEditorInitialized) { @@ -8,6 +68,17 @@ document.addEventListener('DOMContentLoaded', function() { } workflowEditorInitialized = true; + // 初始化多语言支持 + initializeI18n(); + + // 添加语言切换事件 + document.querySelectorAll('.language-option').forEach(option => { + option.addEventListener('click', function() { + const lang = this.getAttribute('data-lang'); + switchLanguage(lang); + }); + }); + // 工作流编辑器的主要元素 const workflowCanvas = document.getElementById('workflowCanvas'); const connectionsSvg = document.getElementById('connectionsSvg'); diff --git a/templates/spider_control.html b/templates/spider_control.html index b85542f..eb7987a 100644 --- a/templates/spider_control.html +++ b/templates/spider_control.html @@ -384,6 +384,7 @@ // 初始化页面 window.onload = function() { + updateLanguage(); // 设置初始语言 loadPredefinedTopics(); }; @@ -807,12 +808,12 @@ const data = await response.json(); if (data.success) { - alert('数据库连接测试成功!'); + alert(currentLang === 'zh' ? '数据库连接测试成功!' : 'Database connection test successful!'); } else { - alert('数据库连接测试失败:' + data.message); + alert((currentLang === 'zh' ? '数据库连接测试失败:' : 'Database connection test failed: ') + data.message); } } catch (error) { - alert('测试连接时发生错误:' + error.message); + alert((currentLang === 'zh' ? '测试连接时发生错误:' : 'Error during connection test: ') + error.message); } } @@ -857,13 +858,13 @@ .then(response => response.json()) .then(data => { if (data.success) { - alert('配置已保存!'); + alert(currentLang === 'zh' ? '配置已保存!' : 'Configuration saved!'); } else { - alert('保存失败:' + data.message); + alert((currentLang === 'zh' ? '保存失败:' : 'Save failed: ') + data.message); } }) .catch(error => { - alert('保存出错:' + error.message); + alert((currentLang === 'zh' ? '保存出错:' : 'Error saving: ') + error.message); }); } @@ -891,7 +892,7 @@ async function generateConfig() { const prompt = document.getElementById('aiPrompt').value.trim(); if (!prompt) { - alert('请输入您的爬虫需求描述!'); + alert(currentLang === 'zh' ? '请输入您的爬虫需求描述!' : 'Please enter your crawler requirements!'); return; } @@ -933,13 +934,13 @@ updateSelectedTopicsList(); // 添加提示 - updateCrawlLog('AI配置已自动应用'); + updateCrawlLog(currentLang === 'zh' ? 'AI配置已自动应用' : 'AI configuration automatically applied'); } } else { throw new Error(data.message); } } catch (error) { - aiSuggestion.textContent = '生成配置时出错:' + error.message; + aiSuggestion.textContent = (currentLang === 'zh' ? '生成配置时出错:' : 'Error generating configuration: ') + error.message; aiResponse.style.display = 'block'; } } diff --git a/templates/workflow_editor.html b/templates/workflow_editor.html index e0f4069..422f00a 100644 --- a/templates/workflow_editor.html +++ b/templates/workflow_editor.html @@ -3,7 +3,7 @@ - 工作流编辑器 - 微博舆情分析系统 + 工作流编辑器 - 微博舆情分析系统 @@ -359,7 +359,7 @@