/** * @file i18n.js * @brief RTU Web Manager — 多语言国际化框架 * * @details 预留式设计, 当前支持 zh (中文) / en (English), * 新增语言只需在 strings 对象中添加新语言键即可。 * * 使用方式: * t('nav.dashboard') → 仪表盘 / Dashboard * t(['out.signals', count]) → 开出信号 (20) / Out Signals (20) * * 语言切换: * I18n.setLang('zh') / I18n.setLang('en') * 切换后写入 localStorage.rtu_lang 并刷新页面 */ var I18n = { current: 'zh', strings: { /* ---- 简体中文 ---- */ zh: { /* App */ 'app.title': 'RTU 管理系统', 'app.version': 'RTU Web v3.0', /* Status */ 'status.connected': '已连接', 'status.disconnected': '已断开', 'status.connecting': '连接中…', /* Navigation */ 'nav.section.overview': '概览', 'nav.section.signal_mgmt': '信号管理', 'nav.section.tools': '工具', 'nav.dashboard': '仪表盘', 'nav.out': '开出信号', 'nav.in': '开入信号', 'nav.yk': '遥控信号', 'nav.ao': '参数设置', 'nav.param': '定值管理', 'nav.datacenter': '数据中心', 'nav.plc_debug': 'PLC 调试', 'nav.plc_config': 'PLC 配置', 'nav.monitor': '实时监控', 'nav.terminal': '命令终端', /* Login */ 'login.title': 'RTU 管理系统', 'login.username': '用户名', 'login.password': '密码', 'login.signin': '登录', 'login.error': '用户名或密码错误 (admin/admin)', 'login.success': '登录成功', /* Dashboard */ 'dash.title': '仪表盘', 'dash.quick_actions': '快捷操作', 'dash.connection': '连接信息', 'dash.export_xml': '导出全部 XML', 'dash.import_xml': '从 XML 导入', 'dash.open_terminal': '打开终端', 'dash.open_monitor': '打开监控', 'dash.url': '地址', 'dash.status': '状态', 'dash.out.desc': '开出信号注册', 'dash.in.desc': '开入信号链接', 'dash.yk.desc': '遥控信号管理', 'dash.ao.desc': '模拟输出参数', 'dash.param.desc': '定值区参数', /* Signals */ 'signal.add': '添加', 'signal.delete_sel': '批量删除', 'signal.set': '设置', 'signal.delete': '删除', 'signal.no_data': '暂无信号数据,请先添加', 'signal.confirm_del': '确认删除信号', 'signal.confirm_del_msg': '确定删除信号', 'signal.confirm_batch_del': '确认批量删除', 'signal.confirm_batch_msg': '确定删除选中的', 'signal.add_title': '添加信号', 'signal.saddr': '信号地址', 'signal.desc': '描述', 'signal.type': '数据类型', 'signal.link': '链接目标', 'signal.ctrl': '控制类型', 'signal.ctrl_direct': '直控', 'signal.ctrl_sbo': '选控 (SBO)', 'signal.val': '值', 'signal.action': '操作', 'signal.set_title': '设置数值', 'signal.new_val': '新值', 'signal.zone': '定值区', /* Datacenter */ 'dc.title': '数据中心 — 信号浏览器', 'dc.no_signal': '暂无信号数据', 'dc.saddr': '信号地址', 'dc.desc': '描述', 'dc.type': '类型', 'dc.val': '值', 'dc.action': '操作', 'dc.refresh': '刷 新', 'dc.search_placeholder': '搜索 saddr/desc…', 'dc.sel_count': '已选 {n} 个信号', 'dc.add_to_config': '添加到配置页', 'dc.confirm_add': '确定将 {n} 个信号添加到', 'dc.added': '已发送 {n} 个添加请求', 'dc.no_selected': '请先勾选要添加的信号', 'dc.querying': '正在从 RTU 查询数据中心…', 'dc.refreshed': '数据中心已刷新', 'mon.recv': '接收', /* Terminal */ 'term.title': '命令终端', 'term.placeholder': '输入命令…', 'term.welcome': 'RTU 命令终端 — 输入 help 查看帮助\n\n', 'term.prompt': 'rtu>', /* PLC */ 'plc_debug.title': 'PLC 调试 — 开出信号', 'plc_debug.refresh': '通过 WebSocket 自动刷新', 'plc_debug.led_col': '指示灯', 'plc_debug.sig_col': '开出信号', 'plc_debug.btn_col': '按键', 'plc_debug.unbound': '未绑定', 'plc_debug.no_led': '暂无指示灯 — 点击 "+ LED" 添加', 'plc_debug.no_btn': '暂无按键 — 点击 "+ Button" 添加', 'plc_debug.no_sig': '暂无开出信号 — 请先在 Out 页面注册', 'plc_debug.bind_title': '绑定开出信号', 'plc_debug.toggle': '翻转', 'plc_debug.add_led': '+ LED', 'plc_debug.add_btn': '+ Button', 'plc_debug.del_sel': '删除选中', 'plc_debug.refresh_btn': '刷新', 'plc_debug.to_led': '→ LED', 'plc_debug.to_btn': '→ BTN', 'plc_config.title': 'PLC 逻辑配置', 'plc_config.file': '配置文件: config/PLC/Reclose_logic.xml', 'plc_config.add_input': '+输入', 'plc_config.add_output': '+输出', 'plc_config.load_xml': '加载 XML', 'plc_config.save_xml': '保存 XML', 'plc_config.clear': '清空', 'plc_config.delete': '删除节点', 'plc_config.zoom_in': '放大', 'plc_config.zoom_out': '缩小', 'plc_config.zoom_fit': '适应', 'plc_config.edit_title': '编辑节点', 'plc_config.edit_save': '保存', 'plc_config.help': '点击节点选中 | 拖拽移动 | 点击输出圆点→点击输入圆点连线 | 滚轮缩放 | 拖拽空白区平移', /* Toast */ 'toast.ws_error': 'WebSocket 未连接', 'toast.saddr_required': '信号地址不能为空', 'toast.add_sent': '添加请求已发送', 'toast.del_sent': '已删除', 'toast.batch_del_sent': '个信号已删除', 'toast.set_sent': '设置请求已发送', 'toast.no_selected': '请先选择信号', 'toast.xml_exported': 'XML 已导出', 'toast.no_export': '无信号数据可导出', 'toast.xml_importing': '正在导入信号…', 'toast.xml_parse_error': 'XML 解析失败', 'toast.xml_no_signals': '未找到信号元素', 'toast.confirm': '确认', 'toast.cancel': '取消', /* Language */ 'lang.label': 'Language', }, /* ---- English ---- */ en: { /* App */ 'app.title': 'RTU Web Manager', 'app.version': 'RTU Web v3.0', /* Status */ 'status.connected': 'Connected', 'status.disconnected': 'Disconnected', 'status.connecting': 'Connecting…', /* Navigation */ 'nav.section.overview': 'Overview', 'nav.section.signal_mgmt': 'Signal Management', 'nav.section.tools': 'Tools', 'nav.dashboard': 'Dashboard', 'nav.out': 'Out Signals', 'nav.in': 'In Signals', 'nav.yk': 'YK Controls', 'nav.ao': 'AO Parameters', 'nav.param': 'Param Settings', 'nav.datacenter': 'Datacenter', 'nav.plc_debug': 'PLC Debug', 'nav.plc_config': 'PLC Config', 'nav.monitor': 'Monitor', 'nav.terminal': 'Terminal', /* Login */ 'login.title': 'RTU Web Manager', 'login.username': 'Username', 'login.password': 'Password', 'login.signin': 'Sign In', 'login.error': 'Invalid credentials (admin/admin)', 'login.success': 'Login successful', /* Dashboard */ 'dash.title': 'Dashboard', 'dash.quick_actions': 'Quick Actions', 'dash.connection': 'Connection Info', 'dash.export_xml': 'Export All to XML', 'dash.import_xml': 'Import from XML', 'dash.open_terminal': 'Open Terminal', 'dash.open_monitor': 'Open Monitor', 'dash.url': 'URL', 'dash.status': 'Status', 'dash.out.desc': 'Output signal registrations', 'dash.in.desc': 'Input signal links', 'dash.yk.desc': 'Remote control signals', 'dash.ao.desc': 'Analog output parameters', 'dash.param.desc': 'Setting zone parameters', /* Signals */ 'signal.add': 'Add', 'signal.delete_sel': 'Delete Selected', 'signal.set': 'Set', 'signal.delete': 'Delete', 'signal.no_data': 'No signals registered. Use Add button above.', 'signal.confirm_del': 'Confirm Delete', 'signal.confirm_del_msg': 'Delete signal', 'signal.confirm_batch_del': 'Confirm Batch Delete', 'signal.confirm_batch_msg': 'Delete', 'signal.add_title': 'Add Signal', 'signal.saddr': 'Signal Address', 'signal.desc': 'Description', 'signal.type': 'Data Type', 'signal.link': 'Link Target', 'signal.ctrl': 'Control Type', 'signal.ctrl_direct': 'Direct', 'signal.ctrl_sbo': 'SBO', 'signal.val': 'Value', 'signal.action': 'Action', 'signal.set_title': 'Set Value', 'signal.new_val': 'New Value', 'signal.zone': 'Zone', /* Datacenter */ 'dc.title': 'Datacenter — Signal Explorer', 'dc.no_signal': 'No signals found', 'dc.saddr': 'SAddr', 'dc.desc': 'Desc', 'dc.type': 'Type', 'dc.val': 'Value', 'dc.action': 'Action', /* Monitor */ 'mon.title': 'WebSocket Traffic Monitor', 'mon.clear': 'Clear', 'mon.pause': 'Pause', 'mon.resume': 'Resume', 'mon.total': 'Total', 'mon.sent': 'Sent', 'mon.recv': 'Recv', /* Terminal */ 'term.title': 'Command Terminal', 'term.placeholder': 'Enter command…', 'term.welcome': 'RTU Command Terminal — Type \'help\' to start.\n\n', 'term.prompt': 'rtu>', /* PLC */ 'plc_debug.title': 'PLC Debug — Out Signals', 'plc_debug.refresh': 'Auto-refresh via WebSocket', 'plc_debug.led_col': 'LED Indicators', 'plc_debug.sig_col': 'Out Signals', 'plc_debug.btn_col': 'Buttons', 'plc_debug.unbound': 'Unbound', 'plc_debug.no_led': 'No LEDs — click "+ LED" to add', 'plc_debug.no_btn': 'No Buttons — click "+ Button" to add', 'plc_debug.no_sig': 'No out signals — register first', 'plc_debug.bind_title': 'Bind Out Signal', 'plc_debug.toggle': 'Toggle', 'plc_debug.add_led': '+ LED', 'plc_debug.add_btn': '+ Button', 'plc_debug.del_sel': 'Delete Selected', 'plc_debug.refresh_btn': 'Refresh', 'plc_debug.to_led': '→ LED', 'plc_debug.to_btn': '→ BTN', 'plc_config.title': 'PLC Logic Configuration', 'plc_config.file': 'Config: config/PLC/Reclose_logic.xml', 'plc_config.add_input': '+Input', 'plc_config.add_output': '+Output', 'plc_config.load_xml': 'Load XML', 'plc_config.save_xml': 'Save XML', 'plc_config.clear': 'Clear', 'plc_config.delete': 'Delete', 'plc_config.zoom_in': 'Zoom In', 'plc_config.zoom_out': 'Zoom Out', 'plc_config.zoom_fit': 'Fit', 'plc_config.edit_title': 'Edit Node', 'plc_config.edit_save': 'Save', 'plc_config.help': 'Click node to select | Drag to move | Click output pin → input pin to wire | Scroll to zoom | Drag empty area to pan', /* Toast */ 'toast.ws_error': 'WebSocket not connected', 'toast.saddr_required': 'Signal address is required', 'toast.add_sent': 'Add request sent', 'toast.del_sent': 'Deleted', 'toast.batch_del_sent': 'signals deleted', 'toast.set_sent': 'Set request sent', 'toast.no_selected': 'No signals selected', 'toast.xml_exported': 'XML exported', 'toast.no_export': 'No signals to export', 'toast.xml_importing': 'Importing signals…', 'toast.xml_parse_error': 'XML parse error', 'toast.xml_no_signals': 'No signal elements found', 'toast.confirm': 'Confirm', 'toast.cancel': 'Cancel', /* Language */ 'lang.label': '语言', } }, /* ---- API ---- */ /** * @brief 获取翻译字符串 * @param {string} key 翻译键 * @return 当前语言的翻译文本 */ t: function(key) { var dict = this.strings[this.current]; return (dict && dict[key]) ? dict[key] : (this.strings['en'][key] || key); }, /** * @brief 切换语言 * @param {string} lang 语言代码 ('zh' | 'en' | …) */ setLang: function(lang) { if (this.strings[lang]) { this.current = lang; localStorage.setItem('rtu_lang', lang); window.location.reload(); } }, /** * @brief 初始化 — 加载用户偏好或自动检测浏览器语言 */ init: function() { var saved = localStorage.getItem('rtu_lang'); if (saved && this.strings[saved]) { this.current = saved; } else { var nav = (navigator.language || '').toLowerCase(); this.current = (nav.indexOf('zh') === 0) ? 'zh' : 'en'; } } };