seeder-st2110-components 1.7.12 → 1.7.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { memo, useState, useCallback, useMemo, useEffect, useRef } from 'react';
2
- import { Tooltip, Modal, App, Form, Input, Alert, message, Dropdown, Spin, Divider, Typography, InputNumber, ConfigProvider, Badge, Switch, Select, List, Empty, Button, Space, Flex, Checkbox, Row, Col, Result } from 'antd';
2
+ import { Tooltip, Modal, App, Alert, Form, Input, message, Dropdown, Spin, Divider, Typography, InputNumber, ConfigProvider, Badge, Switch, Select, List, Empty, Button, Space, Flex, Checkbox, Row, Col, Result } from 'antd';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { useWebSocket, useInterval } from 'ahooks';
5
5
  import { LoadingOutlined, ExclamationCircleFilled, PlusOutlined } from '@ant-design/icons';
@@ -69,6 +69,260 @@ function _toPropertyKey$1(t) {
69
69
  return "symbol" == typeof i ? i : i + "";
70
70
  }
71
71
 
72
+ /**
73
+ * 国际化调试工具
74
+ * 在浏览器控制台运行 window.debugI18n() 查看当前国际化状态
75
+ */
76
+
77
+ const debugI18n = () => {
78
+ var _window$g_initialProp, _window$g_initialProp2, _window$g_initialProp3, _window$g_initialProp4, _window$g_initialProp5, _window$g_initialProp6;
79
+ if (typeof window === 'undefined') {
80
+ console.log('[i18n debug] Not in browser environment');
81
+ return;
82
+ }
83
+ console.group('🌍 I18n Debug Information');
84
+
85
+ // 1. 当前语言环境
86
+ console.log('📍 Current Locale Sources:');
87
+ console.log(' - window.g_initialProps?.locale:', (_window$g_initialProp = window.g_initialProps) === null || _window$g_initialProp === void 0 ? void 0 : _window$g_initialProp.locale);
88
+ console.log(' - window.g_initialProps?.___g_initialPropsFromServer?.locale:', (_window$g_initialProp2 = window.g_initialProps) === null || _window$g_initialProp2 === void 0 || (_window$g_initialProp2 = _window$g_initialProp2.___g_initialPropsFromServer) === null || _window$g_initialProp2 === void 0 ? void 0 : _window$g_initialProp2.locale);
89
+ try {
90
+ console.log(' - localStorage.umi-locale:', localStorage.getItem('umi-locale'));
91
+ } catch (e) {
92
+ console.log(' - localStorage: not available');
93
+ }
94
+ console.log(' - window.__COMPONENT_LOCALE__:', window.__COMPONENT_LOCALE__);
95
+
96
+ // 2. 语言包
97
+ console.log('\n📦 Available Message Sources:');
98
+ console.log(' - window.__COMPONENT_I18N_MESSAGES__:', window.__COMPONENT_I18N_MESSAGES__);
99
+ console.log(' - window.__PROJECT_I18N_MESSAGES__:', window.__PROJECT_I18N_MESSAGES__);
100
+ console.log(' - window.g_initialProps?.messages:', (_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages);
101
+
102
+ // 3. 合并后的语言包
103
+ const componentMessages = window.__COMPONENT_I18N_MESSAGES__ || {};
104
+ const projectMessages = window.__PROJECT_I18N_MESSAGES__ || {};
105
+ const umiMessages = ((_window$g_initialProp4 = window.g_initialProps) === null || _window$g_initialProp4 === void 0 ? void 0 : _window$g_initialProp4.messages) || {};
106
+ const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
107
+ console.log('\n🔧 Merged Locales:', Array.from(allLocales));
108
+ allLocales.forEach(locale => {
109
+ const merged = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
110
+ console.log("\n \uD83D\uDCC4 ".concat(locale, " (").concat(Object.keys(merged).length, " keys):"), merged);
111
+ });
112
+
113
+ // 4. 测试几个关键的 key
114
+ console.log('\n🧪 Test Translation:');
115
+ const testKeys = ['networkSettings.title', 'button.ok', 'button.cancel', 'button.apply', 'button.close'];
116
+ const currentLocale = ((_window$g_initialProp5 = window.g_initialProps) === null || _window$g_initialProp5 === void 0 ? void 0 : _window$g_initialProp5.locale) || ((_window$g_initialProp6 = window.g_initialProps) === null || _window$g_initialProp6 === void 0 || (_window$g_initialProp6 = _window$g_initialProp6.___g_initialPropsFromServer) === null || _window$g_initialProp6 === void 0 ? void 0 : _window$g_initialProp6.locale) || localStorage.getItem('umi-locale') || 'zh-CN';
117
+ const allMessages = {};
118
+ allLocales.forEach(locale => {
119
+ allMessages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
120
+ });
121
+ testKeys.forEach(key => {
122
+ var _allMessages$currentL, _allMessages$enUS;
123
+ const translation = ((_allMessages$currentL = allMessages[currentLocale]) === null || _allMessages$currentL === void 0 ? void 0 : _allMessages$currentL[key]) || ((_allMessages$enUS = allMessages['en-US']) === null || _allMessages$enUS === void 0 ? void 0 : _allMessages$enUS[key]) || '❌ NOT FOUND';
124
+ console.log(" - ".concat(key, ": ").concat(translation));
125
+ });
126
+ console.groupEnd();
127
+ };
128
+
129
+ // 自动在开发环境注册到 window
130
+ if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
131
+ window.debugI18n = debugI18n;
132
+ console.log('💡 I18n debug tool available. Run window.debugI18n() in console to check i18n status.');
133
+ }
134
+
135
+ /**
136
+ * seeder-st2110-components 组件库国际化 Hook
137
+ *
138
+ * 设计目标:
139
+ * 1. 不依赖特定的国际化库(react-intl, i18next 等)
140
+ * 2. 可以与主项目(Umi)的国际化集成
141
+ * 3. 支持简单的变量替换
142
+ * 4. 降级处理:如果没有翻译,显示 key 本身
143
+ */
144
+
145
+ /**
146
+ * 获取当前语言环境
147
+ * 优先从 Umi 全局变量读取,其次使用默认值
148
+ */
149
+ const getLocale = () => {
150
+ // 尝试从 Umi 获取语言设置
151
+ if (typeof window !== 'undefined') {
152
+ var _window$g_initialProp, _window$g_initialProp2;
153
+ // 方式 1:Umi 的 g_initialProps
154
+ if ((_window$g_initialProp = window.g_initialProps) !== null && _window$g_initialProp !== void 0 && _window$g_initialProp.locale) {
155
+ return window.g_initialProps.locale;
156
+ }
157
+ // 方式 2:Umi 的全局语言标记
158
+ if ((_window$g_initialProp2 = window.g_initialProps) !== null && _window$g_initialProp2 !== void 0 && (_window$g_initialProp2 = _window$g_initialProp2.___g_initialPropsFromServer) !== null && _window$g_initialProp2 !== void 0 && _window$g_initialProp2.locale) {
159
+ return window.g_initialProps.___g_initialPropsFromServer.locale;
160
+ }
161
+ // 方式 3:从 localStorage 读取(Umi 默认行为)
162
+ try {
163
+ const storedLocale = localStorage.getItem('umi-locale');
164
+ if (storedLocale) {
165
+ return storedLocale;
166
+ }
167
+ } catch (e) {
168
+ // localStorage 不可用时忽略
169
+ }
170
+ // 方式 4:组件库自定义语言标记
171
+ if (window.__COMPONENT_LOCALE__) {
172
+ return window.__COMPONENT_LOCALE__;
173
+ }
174
+ }
175
+ // 默认语言
176
+ return 'zh-CN';
177
+ };
178
+
179
+ /**
180
+ * 获取语言包
181
+ * 优先从主项目读取,其次使用组件库自带的语言包
182
+ */
183
+ const getMessages = () => {
184
+ if (typeof window !== 'undefined') {
185
+ var _window$g_initialProp3;
186
+ // 尝试从多个来源读取语言包
187
+ const messages = {};
188
+
189
+ // 1. 组件库注册的语言包
190
+ const componentMessages = window.__COMPONENT_I18N_MESSAGES__ || {};
191
+
192
+ // 2. 主项目的语言包
193
+ const projectMessages = window.__PROJECT_I18N_MESSAGES__ || {};
194
+
195
+ // 3. Umi 的语言包
196
+ const umiMessages = ((_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages) || {};
197
+
198
+ // 合并语言包(组件库的优先级最高,其次是主项目,最后是 Umi)
199
+ const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
200
+ allLocales.forEach(locale => {
201
+ messages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
202
+ });
203
+ return messages;
204
+ }
205
+ return {};
206
+ };
207
+
208
+ /**
209
+ * 格式化消息
210
+ * @param {string} id - 国际化 key
211
+ * @param {object} values - 变量替换值
212
+ * @param {string} locale - 语言环境
213
+ * @param {object} messages - 语言包
214
+ */
215
+ const formatMessage = function (_ref) {
216
+ var _messages$locale, _messages$enUS;
217
+ let {
218
+ id
219
+ } = _ref;
220
+ let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
221
+ let locale = arguments.length > 2 ? arguments[2] : undefined;
222
+ let messages = arguments.length > 3 ? arguments[3] : undefined;
223
+ const message = ((_messages$locale = messages[locale]) === null || _messages$locale === void 0 ? void 0 : _messages$locale[id]) || ((_messages$enUS = messages['en-US']) === null || _messages$enUS === void 0 ? void 0 : _messages$enUS[id]) || id;
224
+
225
+ // 支持变量替换 {min}, {max}, {value} 等
226
+ return message.replace(/\{(\w+)\}/g, (match, key) => {
227
+ return values[key] !== undefined ? values[key] : match;
228
+ });
229
+ };
230
+
231
+ /**
232
+ * 国际化 Hook
233
+ *
234
+ * @returns {{
235
+ * locale: string,
236
+ * formatMessage: function,
237
+ * messages: object
238
+ * }}
239
+ *
240
+ * @example
241
+ * const intl = useIntl();
242
+ * const title = intl.formatMessage({ id: 'networkSettings.title' });
243
+ * const message = intl.formatMessage({ id: 'validation.minLength' }, { min: 3 });
244
+ */
245
+ const useIntl = () => {
246
+ const locale = getLocale();
247
+ const messages = getMessages();
248
+ const formatMessageFn = function (_ref2) {
249
+ let {
250
+ id
251
+ } = _ref2;
252
+ let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
253
+ return formatMessage({
254
+ id
255
+ }, values, locale, messages);
256
+ };
257
+ return {
258
+ locale,
259
+ formatMessage: formatMessageFn,
260
+ messages
261
+ };
262
+ };
263
+
264
+ /**
265
+ * 设置语言环境(可选)
266
+ * 如果需要在运行时切换语言,可以调用此函数
267
+ *
268
+ * @param {string} locale - 语言代码,如 'zh-CN' 或 'en-US'
269
+ */
270
+ const setLocale = locale => {
271
+ if (typeof window !== 'undefined') {
272
+ window.__COMPONENT_LOCALE__ = locale;
273
+ }
274
+ };
275
+
276
+ /**
277
+ * 注册语言包(可选)
278
+ * 如果需要在运行时注册语言包,可以调用此函数
279
+ *
280
+ * @param {string} locale - 语言代码
281
+ * @param {object} messages - 语言包对象
282
+ */
283
+ const addMessages = (locale, messages) => {
284
+ if (typeof window !== 'undefined') {
285
+ if (!window.__COMPONENT_I18N_MESSAGES__) {
286
+ window.__COMPONENT_I18N_MESSAGES__ = {};
287
+ }
288
+ window.__COMPONENT_I18N_MESSAGES__[locale] = messages;
289
+ }
290
+ };
291
+
292
+ /**
293
+ * 初始化国际化
294
+ * 在组件库初始化时调用,注册默认语言包
295
+ */
296
+ const initI18n = () => {
297
+ // 注册中文语言包
298
+ addMessages('zh-CN', {
299
+ 'button.ok': '确定',
300
+ 'button.cancel': '取消',
301
+ 'button.save': '保存',
302
+ 'button.delete': '删除',
303
+ 'button.edit': '编辑',
304
+ 'button.add': '添加',
305
+ 'button.confirm': '确认',
306
+ 'button.close': '关闭',
307
+ 'button.apply': '应用'
308
+ // ... 其他默认翻译
309
+ });
310
+
311
+ // 注册英文语言包
312
+ addMessages('en-US', {
313
+ 'button.ok': 'OK',
314
+ 'button.cancel': 'Cancel',
315
+ 'button.save': 'Save',
316
+ 'button.delete': 'Delete',
317
+ 'button.edit': 'Edit',
318
+ 'button.add': 'Add',
319
+ 'button.confirm': 'Confirm',
320
+ 'button.close': 'Close',
321
+ 'button.apply': 'Apply'
322
+ // ... 其他默认翻译
323
+ });
324
+ };
325
+
72
326
  const formatBytes = function (bytes) {
73
327
  let decimals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
74
328
  if (bytes === 0 || !bytes || bytes < 0) return '0 Bytes';
@@ -85,12 +339,17 @@ const UsageItem = /*#__PURE__*/memo(_ref => {
85
339
  children,
86
340
  memTotal
87
341
  } = _ref;
342
+ const intl = useIntl();
88
343
  return /*#__PURE__*/jsx(Tooltip, {
89
344
  title: /*#__PURE__*/jsxs(Fragment, {
90
345
  children: [/*#__PURE__*/jsx("div", {
91
346
  children: title
92
- }), title === 'Memory Usage' && memTotal !== undefined && /*#__PURE__*/jsxs("div", {
93
- children: ["Total Memory: ", formatBytes(memTotal)]
347
+ }), title === intl.formatMessage({
348
+ id: 'usage.memory'
349
+ }) && memTotal !== undefined && /*#__PURE__*/jsxs("div", {
350
+ children: [intl.formatMessage({
351
+ id: 'usage.totalMemory'
352
+ }), ": ", formatBytes(memTotal)]
94
353
  })]
95
354
  }),
96
355
  destroyOnHidden: false,
@@ -198,43 +457,60 @@ const createMetricItem = (title, iconClass, value, unit) => {
198
457
  value: numValue
199
458
  };
200
459
  };
201
- const getItems = details => {
460
+ const getItems = (details, intl) => {
202
461
  const items = [];
203
462
  if (details.cpu_usage !== null && details.cpu_usage !== undefined) {
204
- items.push(createMetricItem('CPU Usage', 'seeder-icon-CPU', details.cpu_usage, '%'));
463
+ items.push(createMetricItem(intl.formatMessage({
464
+ id: 'usage.cpu'
465
+ }), 'seeder-icon-CPU', details.cpu_usage, '%'));
205
466
  }
206
467
  if (details.cpu_temp !== null && details.cpu_temp !== undefined) {
207
- items.push(createMetricItem('CPU Temperature', 'seeder-icon-CPUwendu', details.cpu_temp, '℃'));
468
+ items.push(createMetricItem(intl.formatMessage({
469
+ id: 'usage.cpuTemp'
470
+ }), 'seeder-icon-CPUwendu', details.cpu_temp, '℃'));
208
471
  }
209
472
  if (details.mem_usage !== null && details.mem_usage !== undefined) {
210
- items.push(_objectSpread2$1(_objectSpread2$1({}, createMetricItem('Memory Usage', 'seeder-icon-shiyongshuai', details.mem_usage, '%')), {}, {
473
+ items.push(_objectSpread2$1(_objectSpread2$1({}, createMetricItem(intl.formatMessage({
474
+ id: 'usage.memory'
475
+ }), 'seeder-icon-shiyongshuai', details.mem_usage, '%')), {}, {
211
476
  memTotal: details.mem_total
212
477
  }));
213
478
  }
214
479
  if (details.mem_temp !== null && details.mem_temp !== undefined) {
215
- items.push(createMetricItem('Memory Temperature', 'seeder-icon-wendu', details.mem_temp, '℃'));
480
+ items.push(createMetricItem(intl.formatMessage({
481
+ id: 'usage.memTemp'
482
+ }), 'seeder-icon-wendu', details.mem_temp, '℃'));
216
483
  }
217
484
  if (details.nic_temp !== null && details.nic_temp !== undefined) {
218
- items.push(createMetricItem('NIC Temperature', 'seeder-icon-wuliwangka', details.nic_temp, '℃'));
485
+ items.push(createMetricItem(intl.formatMessage({
486
+ id: 'usage.nicTemp'
487
+ }), 'seeder-icon-wuliwangka', details.nic_temp, '℃'));
219
488
  }
220
489
  if (details.hd_temp !== null && details.hd_temp !== undefined) {
221
- items.push(createMetricItem('Disk Temperature', 'seeder-icon-yingpan', details.hd_temp, '℃'));
490
+ items.push(createMetricItem(intl.formatMessage({
491
+ id: 'usage.diskTemp'
492
+ }), 'seeder-icon-yingpan', details.hd_temp, '℃'));
222
493
  }
223
494
  if (details.gpu_usage !== null && details.gpu_usage !== undefined) {
224
- items.push(createMetricItem('GPU Usage', 'seeder-icon-gpufuwu', details.gpu_usage, '%'));
495
+ items.push(createMetricItem(intl.formatMessage({
496
+ id: 'usage.gpu'
497
+ }), 'seeder-icon-gpufuwu', details.gpu_usage, '%'));
225
498
  }
226
499
  if (details.gpu_temp !== null && details.gpu_temp !== undefined) {
227
- items.push(createMetricItem('GPU Temperature', 'seeder-icon-CPUwendu', details.gpu_temp, '℃'));
500
+ items.push(createMetricItem(intl.formatMessage({
501
+ id: 'usage.gpuTemp'
502
+ }), 'seeder-icon-CPUwendu', details.gpu_temp, '℃'));
228
503
  }
229
504
  return items;
230
505
  };
231
506
  const useHardwareUsage = socketUrl => {
507
+ const intl = useIntl();
232
508
  const {
233
509
  ps_status
234
510
  } = useHardwareWebSocket$1(socketUrl);
235
511
  return useMemo(() => {
236
512
  if (!ps_status || typeof ps_status !== 'object') return null;
237
- const statusItems = getItems(getDetail(ps_status));
513
+ const statusItems = getItems(getDetail(ps_status), intl);
238
514
  return /*#__PURE__*/jsx("div", {
239
515
  className: "usage-container",
240
516
  children: statusItems.map((item, index) => /*#__PURE__*/jsx("div", {
@@ -253,14 +529,23 @@ var useHardwareUsage$1 = useHardwareUsage;
253
529
 
254
530
  const _excluded$4 = ["width", "okText", "cancelText", "styles"];
255
531
  const StyledModal$2 = props => {
532
+ const intl = useIntl();
256
533
  const {
257
534
  width = "520px",
258
- okText = "Apply",
259
- cancelText = "Close",
535
+ okText = "button.apply",
536
+ cancelText = "button.close",
260
537
  styles: propStyles = {}
261
538
  } = props,
262
539
  restProps = _objectWithoutProperties$1(props, _excluded$4);
263
540
 
541
+ // 处理国际化文本
542
+ const okButtonText = typeof okText === 'string' && okText.includes('.') ? intl.formatMessage({
543
+ id: okText
544
+ }) : okText;
545
+ const cancelButtonText = typeof cancelText === 'string' && cancelText.includes('.') ? intl.formatMessage({
546
+ id: cancelText
547
+ }) : cancelText;
548
+
264
549
  // 基础样式配置
265
550
  const baseStyles = {
266
551
  content: {
@@ -290,8 +575,8 @@ const StyledModal$2 = props => {
290
575
  const styles = _objectSpread2$1(_objectSpread2$1({}, baseStyles), propStyles);
291
576
  return /*#__PURE__*/jsx(Modal, _objectSpread2$1({
292
577
  width: width,
293
- okText: okText,
294
- cancelText: cancelText,
578
+ okText: okButtonText,
579
+ cancelText: cancelButtonText,
295
580
  styles: styles
296
581
  }, restProps));
297
582
  };
@@ -302,47 +587,79 @@ const AuthorizationModal = _ref => {
302
587
  onCancel,
303
588
  onOk,
304
589
  authData,
305
- title = 'Register License',
590
+ title = 'license.title',
306
591
  okText,
307
- cancelText = 'Ignore',
592
+ cancelText = 'license.button.ignore',
308
593
  width = 600
309
594
  } = _ref;
595
+ const intl = useIntl();
310
596
  const {
311
597
  message
312
598
  } = App.useApp();
313
599
  const [code, setCode] = useState('');
314
600
  const {
315
601
  accredit_status: isActivated,
316
- message: statusMessage = 'Unactivated',
602
+ message: statusMessage,
317
603
  bios_id: uuid,
318
604
  expires_time: expiresTime
319
605
  } = authData || {};
606
+
607
+ // 服务端返回的状态文本映射到国际化 key
608
+ const getStatusMessageKey = msg => {
609
+ if (!msg) return 'license.status.unactivated';
610
+
611
+ // 根据服务端返回的英文文本映射
612
+ const statusMap = {
613
+ 'Already activated': 'license.status.activated',
614
+ 'Unactivated': 'license.status.unactivated',
615
+ 'Expired': 'license.status.expired',
616
+ 'Invalid': 'license.status.invalid'
617
+ };
618
+ return statusMap[msg] || 'license.status.unactivated';
619
+ };
620
+ const statusMessageKey = getStatusMessageKey(statusMessage);
320
621
  const handleOk = () => {
321
622
  const trimmedCode = code.trim();
322
623
  if (!trimmedCode) {
323
- message.error('License key cannot be empty');
624
+ message.error(intl.formatMessage({
625
+ id: 'license.validation.keyRequired'
626
+ }));
324
627
  return;
325
628
  }
326
629
  onOk(trimmedCode);
327
630
  };
328
631
  const statusAlert = isActivated ? /*#__PURE__*/jsx(Alert, {
329
- message: "".concat(statusMessage, ", will expire on ").concat(expiresTime),
632
+ message: "".concat(intl.formatMessage({
633
+ id: statusMessageKey
634
+ }), ", ").concat(intl.formatMessage({
635
+ id: 'license.status.expiresOn'
636
+ }), " ").concat(expiresTime),
330
637
  type: "success",
331
638
  showIcon: true
332
639
  }) : /*#__PURE__*/jsx(Alert, {
333
- message: statusMessage,
640
+ message: intl.formatMessage({
641
+ id: statusMessageKey
642
+ }),
334
643
  type: "warning",
335
644
  showIcon: true
336
645
  });
337
- const defaultOkText = isActivated ? "Reactivate" : "Activate Now";
646
+ const defaultOkText = isActivated ? intl.formatMessage({
647
+ id: 'license.button.reactivate'
648
+ }) : intl.formatMessage({
649
+ id: 'license.button.activate'
650
+ });
338
651
  return /*#__PURE__*/jsx(StyledModal$3, {
339
- title: title,
652
+ title: intl.formatMessage({
653
+ id: title
654
+ }),
340
655
  width: width,
341
656
  open: true,
342
657
  onCancel: onCancel,
343
658
  onOk: handleOk,
344
659
  okText: okText || defaultOkText,
345
- cancelText: cancelText,
660
+ cancelText: intl.formatMessage({
661
+ id: cancelText
662
+ }),
346
663
  cancelButtonProps: {
347
664
  disabled: !isActivated
348
665
  },
@@ -363,14 +680,18 @@ const AuthorizationModal = _ref => {
363
680
  },
364
681
  children: statusAlert
365
682
  }), /*#__PURE__*/jsx(Form.Item, {
366
- label: "Machine Code",
683
+ label: intl.formatMessage({
684
+ id: 'license.machineCode'
685
+ }),
367
686
  required: true,
368
687
  children: /*#__PURE__*/jsx(Input, {
369
688
  value: uuid,
370
689
  readOnly: true
371
690
  })
372
691
  }), /*#__PURE__*/jsx(Form.Item, {
373
- label: "License Key",
692
+ label: intl.formatMessage({
693
+ id: 'license.key'
694
+ }),
374
695
  required: true,
375
696
  children: /*#__PURE__*/jsx(Input.TextArea, {
376
697
  value: code,
@@ -379,7 +700,9 @@ const AuthorizationModal = _ref => {
379
700
  minRows: 6,
380
701
  maxRows: 6
381
702
  },
382
- placeholder: "Enter your license key"
703
+ placeholder: intl.formatMessage({
704
+ id: 'license.placeholder.enterKey'
705
+ })
383
706
  })
384
707
  })]
385
708
  })
@@ -391,12 +714,13 @@ const DEFAULT_AUTH = {
391
714
  accredit_status: false,
392
715
  // 授权状态
393
716
  bios_id: '',
394
- // 主机id
395
- message: 'Unactivated',
717
+ // 主机 id
718
+ message: 'license.status.unactivated',
396
719
  // 激活信息
397
720
  expires_time: '' // 授权到期时间
398
721
  };
399
722
  const useAuth = options => {
723
+ const intl = useIntl();
400
724
  const {
401
725
  fetchAuthInfo,
402
726
  authorize,
@@ -449,7 +773,12 @@ const useAuth = options => {
449
773
  setAuthData(commands);
450
774
  closeModal();
451
775
  } else {
452
- messageApi.error(commands.ciphertext_status || 'Authorization failed');
776
+ // 处理错误消息的国际化
777
+ const errorMsg = commands.ciphertext_status || 'license.error.authorizationFailed';
778
+ const errorMessage = typeof errorMsg === 'string' && errorMsg.includes('.') ? intl.formatMessage({
779
+ id: errorMsg
780
+ }) : errorMsg;
781
+ messageApi.error(errorMessage);
453
782
  }
454
783
  }
455
784
  } catch (error) {
@@ -488,9 +817,12 @@ const useUpgrade = _ref => {
488
817
  uploadCompleteDelay = 3000,
489
818
  statusPollingInterval = 1000
490
819
  } = _ref;
820
+ const intl = useIntl();
491
821
  const [isSpinning, setIsSpinning] = useState(false);
492
822
  const [pollingInterval, setPollingInterval] = useState(undefined); // 间隔时间,当设置值为 undefined 时会停止计时器
493
- const [currentStatus, setCurrentStatus] = useState('idle'); // 'idle' | 'uploading' | 'Upload complete, starting upgrade...' | 'upgrading'
823
+ const [currentStatus, setCurrentStatus] = useState(intl.formatMessage({
824
+ id: 'upgrade.status.idle'
825
+ })); // 'idle' | 'uploading' | 'Upload complete, starting upgrade...' | 'upgrading'
494
826
  const [uploadProgress, setUploadProgress] = useState(0);
495
827
  const inputRef = useRef(null);
496
828
  // 控制并发上传
@@ -514,27 +846,29 @@ const useUpgrade = _ref => {
514
846
  }
515
847
  const licenseIndex = menuItems.findIndex(item => item.key === 'license');
516
848
 
517
- // 如果没有license,在末尾添加
849
+ // 如果没有 license,在末尾添加
518
850
  if (licenseIndex === -1) {
519
851
  const itemsToAdd = [];
520
852
  if (menuItems.length > 0) itemsToAdd.push({
521
853
  type: 'divider'
522
854
  });
523
- // if (!hasDownload) itemsToAdd.push({ key: "download", label: "Download Config File" });
855
+ // if (!hasDownload) itemsToAdd.push({ key: "download", label: intl.formatMessage({ id: 'upgrade.menu.download' }) });
524
856
  if (!hasUpload) itemsToAdd.push({
525
857
  key: "upload",
526
- label: "Software Update"
858
+ label: intl.formatMessage({
859
+ id: 'upgrade.menu.softwareUpdate'
860
+ })
527
861
  });
528
862
  return [...menuItems, ...itemsToAdd];
529
863
  }
530
864
 
531
- // 有license,在license前面插入
865
+ // 有 license,在 license 前面插入
532
866
  const beforeLicense = menuItems.slice(0, licenseIndex);
533
867
  const licenseItem = menuItems[licenseIndex];
534
868
  const afterLicense = menuItems.slice(licenseIndex + 1);
535
869
  const itemsToInsert = [];
536
870
 
537
- // 1. 前面的分隔符(如果beforeLicense不为空且最后一项不是分隔符)
871
+ // 1. 前面的分隔符(如果 beforeLicense 不为空且最后一项不是分隔符)
538
872
  if (beforeLicense.length > 0 && beforeLicense[beforeLicense.length - 1].type !== 'divider') {
539
873
  itemsToInsert.push({
540
874
  type: 'divider'
@@ -542,18 +876,20 @@ const useUpgrade = _ref => {
542
876
  }
543
877
 
544
878
  // 2. 添加缺少的项
545
- // if (!hasDownload) itemsToInsert.push({ key: "download", label: "Download Config File" });
879
+ // if (!hasDownload) itemsToInsert.push({ key: "download", label: intl.formatMessage({ id: 'upgrade.menu.download' }) });
546
880
  if (!hasUpload) itemsToInsert.push({
547
881
  key: "upload",
548
- label: "Software Update"
882
+ label: intl.formatMessage({
883
+ id: 'upgrade.menu.softwareUpdate'
884
+ })
549
885
  });
550
886
 
551
- // 3. 后面的分隔符(与license之间)
887
+ // 3. 后面的分隔符(与 license 之间)
552
888
  itemsToInsert.push({
553
889
  type: 'divider'
554
890
  });
555
891
  return [...beforeLicense, ...itemsToInsert, licenseItem, ...afterLicense];
556
- }, [menuItems]);
892
+ }, [menuItems, intl]);
557
893
  const handleMenuClick = _ref2 => {
558
894
  let {
559
895
  key
@@ -577,7 +913,9 @@ const useUpgrade = _ref => {
577
913
  const onDownload = async () => {
578
914
  if (!downloadFiles) {
579
915
  console.error('downloadFiles function is required for download operation');
580
- message.error('Download functionality not configured');
916
+ message.error(intl.formatMessage({
917
+ id: 'upgrade.error.downloadNotConfigured'
918
+ }));
581
919
  return;
582
920
  }
583
921
  try {
@@ -604,7 +942,7 @@ const useUpgrade = _ref => {
604
942
  });
605
943
  const url = window.URL.createObjectURL(blob);
606
944
 
607
- // 下面就是创建一个a标签并触发click事件,来下载该文件
945
+ // 下面就是创建一个 a 标签并触发 click 事件,来下载该文件
608
946
  const link = document.createElement('a');
609
947
  link.style.display = 'none';
610
948
  link.href = url;
@@ -613,12 +951,14 @@ const useUpgrade = _ref => {
613
951
  document.body.appendChild(link);
614
952
  link.click();
615
953
 
616
- // 最后移除a标签并删除创建的ObjectURL对象,防止内存泄漏
954
+ // 最后移除 a 标签并删除创建的 ObjectURL 对象,防止内存泄漏
617
955
  link.parentNode.removeChild(link);
618
956
  window.URL.revokeObjectURL(url);
619
957
  } catch (error) {
620
958
  console.error('Download failed:', error);
621
- message.error('Download failed');
959
+ message.error(intl.formatMessage({
960
+ id: 'upgrade.error.downloadFailed'
961
+ }));
622
962
  }
623
963
  };
624
964
  const onUpload = () => {
@@ -637,7 +977,9 @@ const useUpgrade = _ref => {
637
977
  }
638
978
  isUploadingRef.current = true;
639
979
  showLoader();
640
- setCurrentStatus('Uploading...');
980
+ setCurrentStatus(intl.formatMessage({
981
+ id: 'upgrade.status.uploading'
982
+ }));
641
983
  setUploadProgress(0);
642
984
 
643
985
  // 重置取消令牌
@@ -663,9 +1005,11 @@ const useUpgrade = _ref => {
663
1005
 
664
1006
  // 检查业务 code
665
1007
  if ((response === null || response === void 0 ? void 0 : response.code) !== 200) {
666
- // 即使上传成功,但如果服务器返回非200,说明有问题
1008
+ // 即使上传成功,但如果服务器返回非 200,说明有问题
667
1009
  if (isMountedRef.current) {
668
- const errorMsg = (response === null || response === void 0 ? void 0 : response.message) || 'Upload failed due to invalid file format';
1010
+ const errorMsg = (response === null || response === void 0 ? void 0 : response.message) || intl.formatMessage({
1011
+ id: 'upgrade.error.invalidFileFormat'
1012
+ });
669
1013
  message.error(errorMsg);
670
1014
  cancelRequest();
671
1015
  }
@@ -674,19 +1018,25 @@ const useUpgrade = _ref => {
674
1018
 
675
1019
  // 上传成功,进入等待升级阶段
676
1020
  if (!isMountedRef.current) return;
677
- setCurrentStatus('Upload complete, starting upgrade...');
1021
+ setCurrentStatus(intl.formatMessage({
1022
+ id: 'upgrade.status.uploadComplete'
1023
+ }));
678
1024
 
679
1025
  // 延迟后启动轮询
680
1026
  setTimeout(() => {
681
1027
  if (!isMountedRef.current) return;
682
1028
  setPollingInterval(statusPollingInterval);
683
- setCurrentStatus('Upgrading...');
1029
+ setCurrentStatus(intl.formatMessage({
1030
+ id: 'upgrade.status.upgrading'
1031
+ }));
684
1032
  }, uploadCompleteDelay);
685
1033
  } catch (error) {
686
1034
  if (!isMountedRef.current) return;
687
1035
  if (!axios.isCancel(error)) {
688
1036
  console.error("Upload error:", error);
689
- message.error('Upload failed');
1037
+ message.error(intl.formatMessage({
1038
+ id: 'upgrade.error.uploadFailed'
1039
+ }));
690
1040
  }
691
1041
  cancelRequest();
692
1042
  } finally {
@@ -733,7 +1083,9 @@ const useUpgrade = _ref => {
733
1083
  default:
734
1084
  // 其他 code 如 500、400 等
735
1085
  if (isMountedRef.current) {
736
- message.error(statusMessage || 'Upgrade process failed');
1086
+ message.error(statusMessage || intl.formatMessage({
1087
+ id: 'upgrade.error.upgradeFailed'
1088
+ }));
737
1089
  cancelRequest();
738
1090
  }
739
1091
  break;
@@ -799,7 +1151,9 @@ const useUpgrade = _ref => {
799
1151
  },
800
1152
  spin: true
801
1153
  }),
802
- tip: currentStatus === "Uploading..." ? "".concat(currentStatus, " ").concat(uploadProgress, "%") : currentStatus,
1154
+ tip: currentStatus === intl.formatMessage({
1155
+ id: 'upgrade.status.uploading'
1156
+ }) ? "".concat(currentStatus, " ").concat(uploadProgress, "%") : currentStatus,
803
1157
  size: "large",
804
1158
  fullscreen: true
805
1159
  })]
@@ -812,21 +1166,37 @@ const useSystemOperations = function () {
812
1166
  let {
813
1167
  onPowerOff,
814
1168
  onRestart,
815
- confirmTitle = "Confirm",
816
- cancelText = "No",
817
- okText = "Yes",
1169
+ confirmTitle = "system.confirm.title",
1170
+ cancelText = "system.button.cancel",
1171
+ okText = "system.button.confirm",
818
1172
  run
819
1173
  } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1174
+ const intl = useIntl();
820
1175
  const {
821
1176
  modal: AntdModal
822
1177
  } = App.useApp();
1178
+
1179
+ // 处理国际化文本
1180
+ const confirmTitleText = typeof confirmTitle === 'string' && confirmTitle.includes('.') ? intl.formatMessage({
1181
+ id: confirmTitle
1182
+ }) : confirmTitle;
1183
+ const cancelTextValue = typeof cancelText === 'string' && cancelText.includes('.') ? intl.formatMessage({
1184
+ id: cancelText
1185
+ }) : cancelText;
1186
+ const okTextValue = typeof okText === 'string' && okText.includes('.') ? intl.formatMessage({
1187
+ id: okText
1188
+ }) : okText;
823
1189
  const doAction = useCallback(action => {
824
1190
  try {
825
1191
  AntdModal.confirm({
826
1192
  icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
827
- title: "".concat(confirmTitle, " ").concat(action, "?"),
828
- cancelText,
829
- okText,
1193
+ title: "".concat(confirmTitleText, " ").concat(action === 'poweroff' ? intl.formatMessage({
1194
+ id: 'system.action.powerOff'
1195
+ }) : intl.formatMessage({
1196
+ id: 'system.action.restart'
1197
+ }), "?"),
1198
+ cancelText: cancelTextValue,
1199
+ okText: okTextValue,
830
1200
  onOk: () => {
831
1201
  if (action === 'poweroff' && onPowerOff) {
832
1202
  onPowerOff();
@@ -843,14 +1213,18 @@ const useSystemOperations = function () {
843
1213
  } catch (error) {
844
1214
  console.error("".concat(action.toUpperCase(), " ERROR: "), error);
845
1215
  }
846
- }, [AntdModal, confirmTitle, cancelText, okText, onPowerOff, onRestart]);
1216
+ }, [AntdModal, confirmTitleText, cancelTextValue, okTextValue, onPowerOff, onRestart, intl]);
847
1217
  const getMenuItems = useCallback(() => [{
848
1218
  key: "poweroff",
849
- label: "Power Off"
1219
+ label: intl.formatMessage({
1220
+ id: 'system.poweroff'
1221
+ })
850
1222
  }, {
851
1223
  key: "restart",
852
- label: "Restart"
853
- }], []);
1224
+ label: intl.formatMessage({
1225
+ id: 'system.restart'
1226
+ })
1227
+ }], [intl]);
854
1228
  const handleMenuClick = useCallback(_ref => {
855
1229
  let {
856
1230
  key
@@ -1157,438 +1531,177 @@ const useHeartbeat = function (sendMessage, readyState, config, logger) {
1157
1531
  }
1158
1532
  }
1159
1533
  }, currentConfig.interval);
1160
- }, [stopHeartbeat, logger]);
1161
-
1162
- // 自动管理心跳
1163
- useEffect(() => {
1164
- const currentState = stateRef.current;
1165
- if (currentState.enabled) {
1166
- if (currentState.readyState === 1) {
1167
- startHeartbeat();
1168
- } else {
1169
- stopHeartbeat();
1170
- }
1171
- } else {
1172
- stopHeartbeat();
1173
- }
1174
- return () => {
1175
- if (heartbeatTimerRef.current) {
1176
- clearInterval(heartbeatTimerRef.current);
1177
- heartbeatTimerRef.current = null;
1178
- }
1179
- };
1180
- }, [readyState, enabled, startHeartbeat, stopHeartbeat]);
1181
- const heartbeatImpl = useMemo(() => {
1182
- if (!enabled) {
1183
- return {
1184
- startHeartbeat: () => {},
1185
- stopHeartbeat: () => {},
1186
- getLastHeartbeatTime: () => null,
1187
- isEnabled: false
1188
- };
1189
- }
1190
- return {
1191
- startHeartbeat,
1192
- stopHeartbeat,
1193
- getLastHeartbeatTime: () => lastHeartbeatTimeRef.current,
1194
- isEnabled: true
1195
- };
1196
- }, [enabled, startHeartbeat, stopHeartbeat]);
1197
- return heartbeatImpl;
1198
- };
1199
- const useWebSocketWithFeatures = config => {
1200
- const {
1201
- url,
1202
- options = {},
1203
- heartbeat: heartbeatConfig = false,
1204
- enableLog = true
1205
- } = config;
1206
- const [isConnected, setIsConnected] = useState(false);
1207
-
1208
- // 创建 logger 实例
1209
- const logger = useMemo(() => {
1210
- if (enableLog) {
1211
- return createGlobalLogger(url);
1212
- }
1213
- return createDummyLogger();
1214
- }, [url, enableLog]);
1215
- const websocketOptions = useMemo(() => _objectSpread2$1(_objectSpread2$1({}, options), {}, {
1216
- onOpen: event => {
1217
- var _options$onOpen;
1218
- logger.log('INFO', 'WebSocket 连接成功', {
1219
- url,
1220
- readyState: getReadyStateText(1),
1221
- // 连接成功时 readyState 为 1
1222
- eventCode: event === null || event === void 0 ? void 0 : event.code
1223
- });
1224
- setIsConnected(true);
1225
- (_options$onOpen = options.onOpen) === null || _options$onOpen === void 0 || _options$onOpen.call(options, event);
1226
- },
1227
- onError: error => {
1228
- var _options$onError;
1229
- logger.log('ERROR', 'WebSocket 连接错误', {
1230
- url,
1231
- error: error.message,
1232
- errorType: error.type,
1233
- readyState: getReadyStateText(3) // 错误时 readyState 为 3
1234
- });
1235
- setIsConnected(false);
1236
- (_options$onError = options.onError) === null || _options$onError === void 0 || _options$onError.call(options, error);
1237
- },
1238
- onClose: event => {
1239
- var _options$onClose;
1240
- logger.log('WARN', 'WebSocket 连接断开', {
1241
- url,
1242
- code: event.code,
1243
- reason: event.reason,
1244
- wasClean: event.wasClean,
1245
- readyState: getReadyStateText(3) // 关闭时 readyState 为 3
1246
- });
1247
- setIsConnected(false);
1248
- (_options$onClose = options.onClose) === null || _options$onClose === void 0 || _options$onClose.call(options, event);
1249
- },
1250
- onReconnect: count => {
1251
- var _options$onReconnect;
1252
- logger.log('INFO', '尝试重新连接', {
1253
- url,
1254
- attempt: count,
1255
- maxAttempts: options.reconnectLimit || 10
1256
- });
1257
- (_options$onReconnect = options.onReconnect) === null || _options$onReconnect === void 0 || _options$onReconnect.call(options, count);
1258
- }
1259
- }), [url, options, logger]);
1260
- const {
1261
- latestMessage,
1262
- readyState,
1263
- sendMessage,
1264
- connect,
1265
- disconnect
1266
- } = useWebSocket(url, websocketOptions);
1267
- const heartbeatOptions = useMemo(() => heartbeatConfig === true ? {} : heartbeatConfig, [heartbeatConfig]);
1268
- const heartbeatEnabled = useMemo(() => heartbeatConfig !== false, [heartbeatConfig]);
1269
- const heartbeat = useHeartbeat(sendMessage, readyState, heartbeatOptions, logger, heartbeatEnabled);
1270
-
1271
- // 在全局暴露日志方法
1272
- useEffect(() => {
1273
- if (typeof window !== 'undefined' && enableLog) {
1274
- // 生成唯一的键名:基于URL进行base64编码
1275
- const key = "exportWebSocketLogs_".concat(btoa(url));
1276
- // 在window对象上添加方法
1277
- window[key] = () => logger.exportLogs();
1278
- }
1279
- return () => {
1280
- if (typeof window !== 'undefined' && enableLog) {
1281
- const key = "exportWebSocketLogs_".concat(btoa(url));
1282
- delete window[key];
1283
- }
1284
- };
1285
- }, [url, enableLog, logger]);
1286
- const loggerMethods = useMemo(() => ({
1287
- log: (level, message, data) => logger.log(level, message, data),
1288
- exportLogs: () => logger.exportLogs(),
1289
- getLogStats: () => logger.getLogStats(),
1290
- clearLogs: () => logger.clearLogs()
1291
- }), [logger]);
1292
- return {
1293
- latestMessage,
1294
- readyState,
1295
- sendMessage,
1296
- connect,
1297
- disconnect,
1298
- isConnected,
1299
- readyStateText: getReadyStateText(readyState),
1300
- // 心跳功能
1301
- heartbeat,
1302
- // 日志功能
1303
- logger: enableLog ? loggerMethods : null
1304
- };
1305
- };
1306
- var useWebSocketWithFeatures$1 = useWebSocketWithFeatures;
1307
-
1308
- // 在控制台中直接查看所有可用的导出方法 Object.keys(window).filter(key => key.startsWith('exportWebSocketLogs_'))
1309
- // 导出特定连接的日志 window['exportWebSocketLogs_d3M6Ly8xOTIuMTY4LjEyMy4yMDQvd3MvZHZyL3ZpZGVvX3N0YXR1c19jaGFuZ2U=']();
1310
-
1311
- /**
1312
- * 国际化调试工具
1313
- * 在浏览器控制台运行 window.debugI18n() 查看当前国际化状态
1314
- */
1315
-
1316
- const debugI18n = () => {
1317
- var _window$g_initialProp, _window$g_initialProp2, _window$g_initialProp3, _window$g_initialProp4, _window$g_initialProp5, _window$g_initialProp6;
1318
- if (typeof window === 'undefined') {
1319
- console.log('[i18n debug] Not in browser environment');
1320
- return;
1321
- }
1322
- console.group('🌍 I18n Debug Information');
1323
-
1324
- // 1. 当前语言环境
1325
- console.log('📍 Current Locale Sources:');
1326
- console.log(' - window.g_initialProps?.locale:', (_window$g_initialProp = window.g_initialProps) === null || _window$g_initialProp === void 0 ? void 0 : _window$g_initialProp.locale);
1327
- console.log(' - window.g_initialProps?.___g_initialPropsFromServer?.locale:', (_window$g_initialProp2 = window.g_initialProps) === null || _window$g_initialProp2 === void 0 || (_window$g_initialProp2 = _window$g_initialProp2.___g_initialPropsFromServer) === null || _window$g_initialProp2 === void 0 ? void 0 : _window$g_initialProp2.locale);
1328
- try {
1329
- console.log(' - localStorage.umi-locale:', localStorage.getItem('umi-locale'));
1330
- } catch (e) {
1331
- console.log(' - localStorage: not available');
1332
- }
1333
- console.log(' - window.__COMPONENT_LOCALE__:', window.__COMPONENT_LOCALE__);
1334
-
1335
- // 2. 语言包
1336
- console.log('\n📦 Available Message Sources:');
1337
- console.log(' - window.__COMPONENT_I18N_MESSAGES__:', window.__COMPONENT_I18N_MESSAGES__);
1338
- console.log(' - window.__PROJECT_I18N_MESSAGES__:', window.__PROJECT_I18N_MESSAGES__);
1339
- console.log(' - window.g_initialProps?.messages:', (_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages);
1340
-
1341
- // 3. 合并后的语言包
1342
- const componentMessages = window.__COMPONENT_I18N_MESSAGES__ || {};
1343
- const projectMessages = window.__PROJECT_I18N_MESSAGES__ || {};
1344
- const umiMessages = ((_window$g_initialProp4 = window.g_initialProps) === null || _window$g_initialProp4 === void 0 ? void 0 : _window$g_initialProp4.messages) || {};
1345
- const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
1346
- console.log('\n🔧 Merged Locales:', Array.from(allLocales));
1347
- allLocales.forEach(locale => {
1348
- const merged = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
1349
- console.log("\n \uD83D\uDCC4 ".concat(locale, " (").concat(Object.keys(merged).length, " keys):"), merged);
1350
- });
1351
-
1352
- // 4. 测试几个关键的 key
1353
- console.log('\n🧪 Test Translation:');
1354
- const testKeys = ['networkSettings.title', 'button.ok', 'button.cancel', 'button.apply', 'button.close'];
1355
- const currentLocale = ((_window$g_initialProp5 = window.g_initialProps) === null || _window$g_initialProp5 === void 0 ? void 0 : _window$g_initialProp5.locale) || ((_window$g_initialProp6 = window.g_initialProps) === null || _window$g_initialProp6 === void 0 || (_window$g_initialProp6 = _window$g_initialProp6.___g_initialPropsFromServer) === null || _window$g_initialProp6 === void 0 ? void 0 : _window$g_initialProp6.locale) || localStorage.getItem('umi-locale') || 'zh-CN';
1356
- const allMessages = {};
1357
- allLocales.forEach(locale => {
1358
- allMessages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
1359
- });
1360
- testKeys.forEach(key => {
1361
- var _allMessages$currentL, _allMessages$enUS;
1362
- const translation = ((_allMessages$currentL = allMessages[currentLocale]) === null || _allMessages$currentL === void 0 ? void 0 : _allMessages$currentL[key]) || ((_allMessages$enUS = allMessages['en-US']) === null || _allMessages$enUS === void 0 ? void 0 : _allMessages$enUS[key]) || '❌ NOT FOUND';
1363
- console.log(" - ".concat(key, ": ").concat(translation));
1364
- });
1365
- console.groupEnd();
1366
- };
1367
-
1368
- // 自动在开发环境注册到 window
1369
- if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
1370
- window.debugI18n = debugI18n;
1371
- console.log('💡 I18n debug tool available. Run window.debugI18n() in console to check i18n status.');
1372
- }
1373
-
1374
- /**
1375
- * seeder-st2110-components 组件库国际化 Hook
1376
- *
1377
- * 设计目标:
1378
- * 1. 不依赖特定的国际化库(react-intl, i18next 等)
1379
- * 2. 可以与主项目(Umi)的国际化集成
1380
- * 3. 支持简单的变量替换
1381
- * 4. 降级处理:如果没有翻译,显示 key 本身
1382
- */
1383
-
1384
- /**
1385
- * 获取当前语言环境
1386
- * 优先从 Umi 全局变量读取,其次使用默认值
1387
- */
1388
- const getLocale = () => {
1389
- // 尝试从 Umi 获取语言设置
1390
- if (typeof window !== 'undefined') {
1391
- var _window$g_initialProp, _window$g_initialProp2;
1392
- // 方式 1:Umi 的 g_initialProps
1393
- if ((_window$g_initialProp = window.g_initialProps) !== null && _window$g_initialProp !== void 0 && _window$g_initialProp.locale) {
1394
- return window.g_initialProps.locale;
1395
- }
1396
- // 方式 2:Umi 的全局语言标记
1397
- if ((_window$g_initialProp2 = window.g_initialProps) !== null && _window$g_initialProp2 !== void 0 && (_window$g_initialProp2 = _window$g_initialProp2.___g_initialPropsFromServer) !== null && _window$g_initialProp2 !== void 0 && _window$g_initialProp2.locale) {
1398
- return window.g_initialProps.___g_initialPropsFromServer.locale;
1399
- }
1400
- // 方式 3:从 localStorage 读取(Umi 默认行为)
1401
- try {
1402
- const storedLocale = localStorage.getItem('umi-locale');
1403
- if (storedLocale) {
1404
- return storedLocale;
1405
- }
1406
- } catch (e) {
1407
- // localStorage 不可用时忽略
1408
- }
1409
- // 方式 4:组件库自定义语言标记
1410
- if (window.__COMPONENT_LOCALE__) {
1411
- return window.__COMPONENT_LOCALE__;
1412
- }
1413
- }
1414
- // 默认语言
1415
- return 'zh-CN';
1416
- };
1417
-
1418
- /**
1419
- * 获取语言包
1420
- * 优先从主项目读取,其次使用组件库自带的语言包
1421
- */
1422
- const getMessages = () => {
1423
- if (typeof window !== 'undefined') {
1424
- var _window$g_initialProp3;
1425
- // 尝试从多个来源读取语言包
1426
- const messages = {};
1427
-
1428
- // 1. 组件库注册的语言包
1429
- const componentMessages = window.__COMPONENT_I18N_MESSAGES__ || {};
1430
-
1431
- // 2. 主项目的语言包
1432
- const projectMessages = window.__PROJECT_I18N_MESSAGES__ || {};
1433
-
1434
- // 3. Umi 的语言包
1435
- const umiMessages = ((_window$g_initialProp3 = window.g_initialProps) === null || _window$g_initialProp3 === void 0 ? void 0 : _window$g_initialProp3.messages) || {};
1436
-
1437
- // 合并语言包(组件库的优先级最高,其次是主项目,最后是 Umi)
1438
- const allLocales = new Set([...Object.keys(componentMessages), ...Object.keys(projectMessages), ...Object.keys(umiMessages)]);
1439
- allLocales.forEach(locale => {
1440
- messages[locale] = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, umiMessages[locale] || {}), projectMessages[locale] || {}), componentMessages[locale] || {});
1441
- });
1442
- return messages;
1443
- }
1444
- return {};
1445
- };
1446
-
1447
- /**
1448
- * 格式化消息
1449
- * @param {string} id - 国际化 key
1450
- * @param {object} values - 变量替换值
1451
- * @param {string} locale - 语言环境
1452
- * @param {object} messages - 语言包
1453
- */
1454
- const formatMessage = function (_ref) {
1455
- var _messages$locale, _messages$enUS;
1456
- let {
1457
- id
1458
- } = _ref;
1459
- let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1460
- let locale = arguments.length > 2 ? arguments[2] : undefined;
1461
- let messages = arguments.length > 3 ? arguments[3] : undefined;
1462
- const message = ((_messages$locale = messages[locale]) === null || _messages$locale === void 0 ? void 0 : _messages$locale[id]) || ((_messages$enUS = messages['en-US']) === null || _messages$enUS === void 0 ? void 0 : _messages$enUS[id]) || id;
1463
-
1464
- // 支持变量替换 {min}, {max}, {value} 等
1465
- return message.replace(/\{(\w+)\}/g, (match, key) => {
1466
- return values[key] !== undefined ? values[key] : match;
1467
- });
1468
- };
1469
-
1470
- /**
1471
- * 国际化 Hook
1472
- *
1473
- * @returns {{
1474
- * locale: string,
1475
- * formatMessage: function,
1476
- * messages: object
1477
- * }}
1478
- *
1479
- * @example
1480
- * const intl = useIntl();
1481
- * const title = intl.formatMessage({ id: 'networkSettings.title' });
1482
- * const message = intl.formatMessage({ id: 'validation.minLength' }, { min: 3 });
1483
- */
1484
- const useIntl = () => {
1485
- const locale = getLocale();
1486
- const messages = getMessages();
1487
- const formatMessageFn = function (_ref2) {
1488
- let {
1489
- id
1490
- } = _ref2;
1491
- let values = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1492
- return formatMessage({
1493
- id
1494
- }, values, locale, messages);
1495
- };
1496
- return {
1497
- locale,
1498
- formatMessage: formatMessageFn,
1499
- messages
1500
- };
1501
- };
1502
-
1503
- /**
1504
- * 设置语言环境(可选)
1505
- * 如果需要在运行时切换语言,可以调用此函数
1506
- *
1507
- * @param {string} locale - 语言代码,如 'zh-CN' 或 'en-US'
1508
- */
1509
- const setLocale = locale => {
1510
- if (typeof window !== 'undefined') {
1511
- window.__COMPONENT_LOCALE__ = locale;
1512
- }
1513
- };
1534
+ }, [stopHeartbeat, logger]);
1514
1535
 
1515
- /**
1516
- * 注册语言包(可选)
1517
- * 如果需要在运行时注册语言包,可以调用此函数
1518
- *
1519
- * @param {string} locale - 语言代码
1520
- * @param {object} messages - 语言包对象
1521
- */
1522
- const addMessages = (locale, messages) => {
1523
- if (typeof window !== 'undefined') {
1524
- if (!window.__COMPONENT_I18N_MESSAGES__) {
1525
- window.__COMPONENT_I18N_MESSAGES__ = {};
1536
+ // 自动管理心跳
1537
+ useEffect(() => {
1538
+ const currentState = stateRef.current;
1539
+ if (currentState.enabled) {
1540
+ if (currentState.readyState === 1) {
1541
+ startHeartbeat();
1542
+ } else {
1543
+ stopHeartbeat();
1544
+ }
1545
+ } else {
1546
+ stopHeartbeat();
1526
1547
  }
1527
- window.__COMPONENT_I18N_MESSAGES__[locale] = messages;
1528
- }
1548
+ return () => {
1549
+ if (heartbeatTimerRef.current) {
1550
+ clearInterval(heartbeatTimerRef.current);
1551
+ heartbeatTimerRef.current = null;
1552
+ }
1553
+ };
1554
+ }, [readyState, enabled, startHeartbeat, stopHeartbeat]);
1555
+ const heartbeatImpl = useMemo(() => {
1556
+ if (!enabled) {
1557
+ return {
1558
+ startHeartbeat: () => {},
1559
+ stopHeartbeat: () => {},
1560
+ getLastHeartbeatTime: () => null,
1561
+ isEnabled: false
1562
+ };
1563
+ }
1564
+ return {
1565
+ startHeartbeat,
1566
+ stopHeartbeat,
1567
+ getLastHeartbeatTime: () => lastHeartbeatTimeRef.current,
1568
+ isEnabled: true
1569
+ };
1570
+ }, [enabled, startHeartbeat, stopHeartbeat]);
1571
+ return heartbeatImpl;
1529
1572
  };
1573
+ const useWebSocketWithFeatures = config => {
1574
+ const {
1575
+ url,
1576
+ options = {},
1577
+ heartbeat: heartbeatConfig = false,
1578
+ enableLog = true
1579
+ } = config;
1580
+ const [isConnected, setIsConnected] = useState(false);
1530
1581
 
1531
- /**
1532
- * 初始化国际化
1533
- * 在组件库初始化时调用,注册默认语言包
1534
- */
1535
- const initI18n = () => {
1536
- // 注册中文语言包
1537
- addMessages('zh-CN', {
1538
- 'button.ok': '确定',
1539
- 'button.cancel': '取消',
1540
- 'button.save': '保存',
1541
- 'button.delete': '删除',
1542
- 'button.edit': '编辑',
1543
- 'button.add': '添加',
1544
- 'button.confirm': '确认',
1545
- 'button.close': '关闭',
1546
- 'button.apply': '应用',
1547
- 'menu.networkSettings': '网络设置',
1548
- 'menu.ptp': 'PTP',
1549
- 'menu.nmos': 'NMOS',
1550
- 'menu.preset': '预设',
1551
- 'menu.license': '许可证'
1552
- // ... 其他默认翻译
1553
- });
1582
+ // 创建 logger 实例
1583
+ const logger = useMemo(() => {
1584
+ if (enableLog) {
1585
+ return createGlobalLogger(url);
1586
+ }
1587
+ return createDummyLogger();
1588
+ }, [url, enableLog]);
1589
+ const websocketOptions = useMemo(() => _objectSpread2$1(_objectSpread2$1({}, options), {}, {
1590
+ onOpen: event => {
1591
+ var _options$onOpen;
1592
+ logger.log('INFO', 'WebSocket 连接成功', {
1593
+ url,
1594
+ readyState: getReadyStateText(1),
1595
+ // 连接成功时 readyState 为 1
1596
+ eventCode: event === null || event === void 0 ? void 0 : event.code
1597
+ });
1598
+ setIsConnected(true);
1599
+ (_options$onOpen = options.onOpen) === null || _options$onOpen === void 0 || _options$onOpen.call(options, event);
1600
+ },
1601
+ onError: error => {
1602
+ var _options$onError;
1603
+ logger.log('ERROR', 'WebSocket 连接错误', {
1604
+ url,
1605
+ error: error.message,
1606
+ errorType: error.type,
1607
+ readyState: getReadyStateText(3) // 错误时 readyState 为 3
1608
+ });
1609
+ setIsConnected(false);
1610
+ (_options$onError = options.onError) === null || _options$onError === void 0 || _options$onError.call(options, error);
1611
+ },
1612
+ onClose: event => {
1613
+ var _options$onClose;
1614
+ logger.log('WARN', 'WebSocket 连接断开', {
1615
+ url,
1616
+ code: event.code,
1617
+ reason: event.reason,
1618
+ wasClean: event.wasClean,
1619
+ readyState: getReadyStateText(3) // 关闭时 readyState 为 3
1620
+ });
1621
+ setIsConnected(false);
1622
+ (_options$onClose = options.onClose) === null || _options$onClose === void 0 || _options$onClose.call(options, event);
1623
+ },
1624
+ onReconnect: count => {
1625
+ var _options$onReconnect;
1626
+ logger.log('INFO', '尝试重新连接', {
1627
+ url,
1628
+ attempt: count,
1629
+ maxAttempts: options.reconnectLimit || 10
1630
+ });
1631
+ (_options$onReconnect = options.onReconnect) === null || _options$onReconnect === void 0 || _options$onReconnect.call(options, count);
1632
+ }
1633
+ }), [url, options, logger]);
1634
+ const {
1635
+ latestMessage,
1636
+ readyState,
1637
+ sendMessage,
1638
+ connect,
1639
+ disconnect
1640
+ } = useWebSocket(url, websocketOptions);
1641
+ const heartbeatOptions = useMemo(() => heartbeatConfig === true ? {} : heartbeatConfig, [heartbeatConfig]);
1642
+ const heartbeatEnabled = useMemo(() => heartbeatConfig !== false, [heartbeatConfig]);
1643
+ const heartbeat = useHeartbeat(sendMessage, readyState, heartbeatOptions, logger, heartbeatEnabled);
1554
1644
 
1555
- // 注册英文语言包
1556
- addMessages('en-US', {
1557
- 'button.ok': 'OK',
1558
- 'button.cancel': 'Cancel',
1559
- 'button.save': 'Save',
1560
- 'button.delete': 'Delete',
1561
- 'button.edit': 'Edit',
1562
- 'button.add': 'Add',
1563
- 'button.confirm': 'Confirm',
1564
- 'button.close': 'Close',
1565
- 'button.apply': 'Apply',
1566
- 'menu.networkSettings': 'Network Settings',
1567
- 'menu.ptp': 'PTP',
1568
- 'menu.nmos': 'NMOS',
1569
- 'menu.preset': 'Preset',
1570
- 'menu.license': 'License'
1571
- // ... 其他默认翻译
1572
- });
1645
+ // 在全局暴露日志方法
1646
+ useEffect(() => {
1647
+ if (typeof window !== 'undefined' && enableLog) {
1648
+ // 生成唯一的键名:基于URL进行base64编码
1649
+ const key = "exportWebSocketLogs_".concat(btoa(url));
1650
+ // 在window对象上添加方法
1651
+ window[key] = () => logger.exportLogs();
1652
+ }
1653
+ return () => {
1654
+ if (typeof window !== 'undefined' && enableLog) {
1655
+ const key = "exportWebSocketLogs_".concat(btoa(url));
1656
+ delete window[key];
1657
+ }
1658
+ };
1659
+ }, [url, enableLog, logger]);
1660
+ const loggerMethods = useMemo(() => ({
1661
+ log: (level, message, data) => logger.log(level, message, data),
1662
+ exportLogs: () => logger.exportLogs(),
1663
+ getLogStats: () => logger.getLogStats(),
1664
+ clearLogs: () => logger.clearLogs()
1665
+ }), [logger]);
1666
+ return {
1667
+ latestMessage,
1668
+ readyState,
1669
+ sendMessage,
1670
+ connect,
1671
+ disconnect,
1672
+ isConnected,
1673
+ readyStateText: getReadyStateText(readyState),
1674
+ // 心跳功能
1675
+ heartbeat,
1676
+ // 日志功能
1677
+ logger: enableLog ? loggerMethods : null
1678
+ };
1573
1679
  };
1680
+ var useWebSocketWithFeatures$1 = useWebSocketWithFeatures;
1681
+
1682
+ // 在控制台中直接查看所有可用的导出方法 Object.keys(window).filter(key => key.startsWith('exportWebSocketLogs_'))
1683
+ // 导出特定连接的日志 window['exportWebSocketLogs_d3M6Ly8xOTIuMTY4LjEyMy4yMDQvd3MvZHZyL3ZpZGVvX3N0YXR1c19jaGFuZ2U=']();
1574
1684
 
1575
1685
  // seeder-st2110-components 组件库中文语言包
1576
1686
  var zhCN = {
1577
1687
  // 通用按钮
1578
- 'button.ok': '确定',
1579
- 'button.cancel': '取消',
1580
- 'button.save': '保存',
1581
- 'button.delete': '删除',
1582
- 'button.edit': '编辑',
1583
- 'button.add': '添加',
1584
- 'button.confirm': '确认',
1585
1688
  'button.close': '关闭',
1586
1689
  'button.apply': '应用',
1587
- 'button.submit': '提交',
1588
- 'button.next': '下一步',
1589
- 'button.previous': '上一步',
1590
- 'button.refresh': '刷新',
1591
- 'button.retry': '重试',
1690
+ // 输入框占位符
1691
+ 'input.placeholder.enterInteger': '请输入整数',
1692
+ 'input.placeholder.enterPort': '请输入端口 (0-65535)',
1693
+ 'input.placeholder.enterPayload': '请输入 Payload (96-127)',
1694
+ // 使用率显示
1695
+ 'usage.memory': '内存使用率',
1696
+ 'usage.totalMemory': '内存总量',
1697
+ 'usage.cpu': 'CPU 使用率',
1698
+ 'usage.disk': '磁盘使用率',
1699
+ 'usage.cpuTemp': 'CPU 温度',
1700
+ 'usage.memTemp': '内存温度',
1701
+ 'usage.nicTemp': '网卡温度',
1702
+ 'usage.diskTemp': '硬盘温度',
1703
+ 'usage.gpu': 'GPU 使用率',
1704
+ 'usage.gpuTemp': 'GPU 温度',
1592
1705
  // 菜单
1593
1706
  'menu.networkSettings': '网络设置',
1594
1707
  'menu.ptp': 'PTP',
@@ -1599,6 +1712,7 @@ var zhCN = {
1599
1712
  'menu.system': '系统',
1600
1713
  // Network Settings Modal
1601
1714
  'networkSettings.title': '网络设置',
1715
+ 'networkSettings.name': '名称',
1602
1716
  'networkSettings.ipAddress': 'IP 地址',
1603
1717
  'networkSettings.subnetMask': '子网掩码',
1604
1718
  'networkSettings.restartRequired': '配置已修改。是否重启以应用更改?',
@@ -1607,176 +1721,131 @@ var zhCN = {
1607
1721
  'networkSettings.saveSuccess': '保存成功',
1608
1722
  // PTP Modal
1609
1723
  'ptp.title': 'PTP 设置',
1610
- 'ptp.enable': '启用 PTP',
1611
- 'ptp.status': 'PTP 状态',
1612
1724
  'ptp.domainNumber': '域编号',
1613
1725
  'ptp.priority1': '优先级 1',
1614
1726
  'ptp.priority2': '优先级 2',
1615
1727
  'ptp.clockClass': '时钟等级',
1728
+ 'ptp.clockClass.atomic': '原子钟 ({value})',
1729
+ 'ptp.clockClass.gps': 'GPS ({value})',
1730
+ 'ptp.clockClass.slaveOnly': '仅从时钟 ({value})',
1616
1731
  'ptp.clockAccuracy': '时钟精度',
1617
- 'ptp.offsetScaledLogVariance': '偏移缩放对数方差',
1618
- 'ptp.port': 'PTP 端口',
1619
- 'ptp.master': '主时钟',
1620
- 'ptp.slave': '从时钟',
1621
- 'ptp.grandmaster': '主时钟源',
1732
+ 'ptp.offsetScaledLogVariance': '时钟偏移方差',
1733
+ 'ptp.portIdentity': '端口标识',
1734
+ 'ptp.grandmasterIdentity': '主时钟 ID',
1735
+ 'ptp.utcOffset': 'UTC 偏移量',
1736
+ 'ptp.connected': '已连接',
1737
+ 'ptp.disconnected': '未连接',
1622
1738
  'ptp.locked': '已锁定',
1623
1739
  'ptp.unlocked': '未锁定',
1624
- 'ptp.saveSuccess': 'PTP 设置保存成功',
1625
- 'ptp.saveFailed': 'PTP 设置保存失败',
1740
+ 'ptp.saveSuccess': '保存成功',
1626
1741
  // NMOS Modal
1627
1742
  'nmos.title': 'NMOS 设置',
1628
- 'nmos.enable': '启用 NMOS',
1629
1743
  'nmos.hostAddress': '主机地址',
1630
- 'nmos.port': '端口',
1631
- 'nmos.registrationUrl': '注册 URL',
1632
- 'nmos.connectionUrl': '连接 URL',
1633
- 'nmos.nodeId': '节点 ID',
1634
- 'nmos.deviceId': '设备 ID',
1635
- 'nmos.saveSuccess': 'NMOS 设置保存成功',
1636
- 'nmos.saveFailed': 'NMOS 设置保存失败',
1744
+ 'nmos.domain': '',
1745
+ 'nmos.registrationPort': '注册端口',
1746
+ 'nmos.registryAddress': '注册服务器地址',
1747
+ 'nmos.registryVersion': '注册版本',
1748
+ 'nmos.loggingLevel': '日志级别',
1749
+ 'nmos.placeholder.selectHostAddress': '选择主机地址',
1750
+ 'nmos.placeholder.selectVersion': '选择版本',
1751
+ 'nmos.saveSuccess': '保存成功',
1637
1752
  // Preset Modal
1638
1753
  'preset.title': '预设管理',
1639
1754
  'preset.name': '名称',
1640
1755
  'preset.categories': '分类',
1641
1756
  'preset.description': '描述',
1642
- 'preset.save': '保存预设',
1643
- 'preset.load': '加载预设',
1644
- 'preset.delete': '删除预设',
1645
- 'preset.edit': '编辑预设',
1646
- 'preset.confirmDelete': '确认删除',
1647
- 'preset.deleteConfirmMessage': '确定要删除此预设吗?',
1648
- 'preset.saveSuccess': '预设保存成功',
1649
- 'preset.loadSuccess': '预设加载成功',
1650
- 'preset.deleteSuccess': '预设删除成功',
1651
- 'preset.saveFailed': '预设保存失败',
1652
- 'preset.loadFailed': '预设加载失败',
1653
- 'preset.deleteFailed': '预设删除失败',
1654
- 'preset.noPresets': '暂无预设',
1655
- 'preset.enterName': '输入预设名称',
1656
- 'preset.enterDescription': '输入预设描述',
1657
- 'preset.selectCategory': '选择分类',
1757
+ 'preset.placeholder.enterName': '请输入名称',
1758
+ 'preset.placeholder.enterDescription': '请输入描述',
1759
+ 'preset.header.name': '名称',
1760
+ 'preset.header.createTime': '创建时间',
1761
+ 'preset.header.description': '描述',
1762
+ 'preset.button.new': '新建预设',
1763
+ 'preset.button.delete': '删除',
1764
+ 'preset.button.load': '加载',
1765
+ 'preset.button.save': '保存',
1766
+ 'preset.button.edit': '编辑',
1767
+ 'preset.button.cancel': '取消',
1768
+ 'preset.empty.noData': '从列表中选择一个预设查看详情',
1769
+ 'preset.empty.create': '创建新预设',
1770
+ 'preset.untitled': '未命名',
1771
+ 'preset.delete.title': '删除预设',
1772
+ 'preset.delete.confirmMessage': '确定要删除预设',
1773
+ 'preset.load.title': '加载预设',
1774
+ 'preset.load.confirmMessage': '确定要加载预设',
1775
+ 'preset.load.loading': '加载中...',
1776
+ 'preset.success': '成功',
1777
+ 'preset.validation.nameRequired': '名称是必填项',
1778
+ 'preset.validation.categoryRequired': '请选择分类',
1779
+ 'preset.error.noSelectionOrIdMissing': '未选择预设或预设 ID 缺失',
1658
1780
  // License/Auth Modal
1659
- 'license.title': '许可证管理',
1660
- 'license.authCode': '授权码',
1661
- 'license.activate': '激活',
1662
- 'license.deactivate': '停用',
1663
- 'license.valid': '许可证有效',
1664
- 'license.expired': '许可证已过期',
1665
- 'license.invalid': '许可证无效',
1666
- 'license.activationSuccess': '激活成功',
1667
- 'license.deactivationSuccess': '停用成功',
1668
- 'license.activationFailed': '激活失败',
1669
- 'license.enterAuthCode': '输入授权码',
1670
- 'license.productInfo': '产品信息',
1671
- 'license.customerInfo': '客户信息',
1672
- 'license.expiryDate': '到期日期',
1673
- 'license.features': '功能特性',
1781
+ 'license.title': '注册许可证',
1782
+ 'license.machineCode': '机器码',
1783
+ 'license.key': '许可证密钥',
1784
+ 'license.placeholder.enterKey': '请输入许可证密钥',
1785
+ 'license.button.activate': '立即激活',
1786
+ 'license.button.reactivate': '重新激活',
1787
+ 'license.button.ignore': '忽略',
1788
+ 'license.status.unactivated': '未激活',
1789
+ 'license.status.activated': '已激活',
1790
+ 'license.status.expired': '已过期',
1791
+ 'license.status.invalid': '无效',
1792
+ 'license.status.expiresOn': '到期时间',
1793
+ 'license.validation.keyRequired': '许可证密钥不能为空',
1794
+ 'license.error.authorizationFailed': '授权失败',
1674
1795
  // 升级相关
1675
- 'upgrade.title': '系统升级',
1676
- 'upgrade.checking': '检查更新...',
1677
- 'upgrade.available': '有新版本可用',
1678
- 'upgrade.upToDate': '已是最新版本',
1679
- 'upgrade.downloading': '下载中...',
1680
- 'upgrade.installing': '安装中...',
1681
- 'upgrade.complete': '升级完成',
1682
- 'upgrade.failed': '升级失败',
1683
- 'upgrade.confirmRestart': '升级完成后需要重启,是否继续?',
1684
- 'upgrade.newVersion': '新版本',
1685
- 'upgrade.currentVersion': '当前版本',
1686
- 'upgrade.releaseNotes': '更新说明',
1687
- 'upgrade.download': '下载',
1688
- 'upgrade.install': '安装',
1689
- 'upgrade.cancel': '取消',
1796
+ 'upgrade.menu.download': '导出配置',
1797
+ 'upgrade.menu.softwareUpdate': '软件升级',
1798
+ 'upgrade.status.idle': '空闲',
1799
+ 'upgrade.status.uploading': '上传中',
1800
+ 'upgrade.status.uploadComplete': '上传完成,开始升级...',
1801
+ 'upgrade.status.upgrading': '升级中...',
1802
+ 'upgrade.error.downloadNotConfigured': '下载功能未配置',
1803
+ 'upgrade.error.downloadFailed': '下载失败',
1804
+ 'upgrade.error.uploadFailed': '上传失败',
1805
+ 'upgrade.error.invalidFileFormat': '上传失败:文件格式无效',
1806
+ 'upgrade.error.upgradeFailed': '升级失败',
1690
1807
  // 系统操作
1808
+ 'system.poweroff': '关机',
1691
1809
  'system.restart': '重启',
1692
- 'system.shutdown': '关机',
1693
- 'system.poweroff': '断电',
1694
- 'system.reboot': '重新启动',
1695
- 'system.confirmRestart': '确认重启',
1696
- 'system.confirmShutdown': '确认关机',
1697
- 'system.restartConfirmMessage': '确定要重启设备吗?',
1698
- 'system.shutdownConfirmMessage': '确定要关闭设备吗?',
1699
- 'system.restarting': '设备重启中...',
1700
- 'system.shuttingDown': '设备关机中...',
1701
- // 维护页面
1702
- 'maintenance.title': '系统维护',
1703
- 'maintenance.description': '设备正在维护中,请稍候...',
1704
- 'maintenance.restart': '设备正在重启',
1705
- 'maintenance.poweroff': '设备已关闭',
1706
- 'maintenance.redirecting': '页面跳转中...',
1707
- 'maintenance.backToHome': '返回首页',
1708
- // 表单验证
1709
- 'validation.required': '此项为必填项',
1710
- 'validation.invalidIP': 'IP 地址格式不正确',
1711
- 'validation.invalidPort': '端口号范围应为 1-65535',
1712
- 'validation.invalidEmail': '邮箱格式不正确',
1713
- 'validation.minLength': '最少需要 {min} 个字符',
1714
- 'validation.maxLength': '最多只能有 {max} 个字符',
1715
- 'validation.min': '最小值为 {min}',
1716
- 'validation.max': '最大值为 {max}',
1717
- 'validation.pattern': '格式不正确',
1718
- 'validation.unique': '该值已存在',
1719
- // 状态消息
1720
- 'status.loading': '加载中...',
1721
- 'status.saving': '保存中...',
1722
- 'status.deleting': '删除中...',
1723
- 'status.updating': '更新中...',
1724
- 'status.submitting': '提交中...',
1725
- 'status.success': '成功',
1726
- 'status.failed': '失败',
1727
- 'status.error': '错误',
1728
- 'status.pending': '等待中',
1729
- 'status.processing': '处理中',
1730
- 'status.completed': '已完成',
1731
- 'status.cancelled': '已取消',
1732
- // 确认对话框
1733
- 'confirm.title': '确认操作',
1734
- 'confirm.message': '确定要执行此操作吗?',
1735
- 'confirm.cancel': '取消',
1736
- 'confirm.ok': '确定',
1737
- // 空状态
1738
- 'empty.noData': '暂无数据',
1739
- 'empty.noResults': '暂无结果',
1740
- 'empty.noItems': '暂无项目',
1741
- // 通用标签
1742
- 'label.name': '名称',
1743
- 'label.description': '描述',
1744
- 'label.status': '状态',
1745
- 'label.type': '类型',
1746
- 'label.action': '操作',
1747
- 'label.actions': '操作',
1748
- 'label.settings': '设置',
1749
- 'label.configuration': '配置',
1750
- 'label.information': '信息',
1751
- 'label.version': '版本',
1752
- 'label.time': '时间',
1753
- 'label.date': '日期',
1754
- 'label.enable': '启用',
1755
- 'label.disable': '禁用',
1756
- // 占位符
1757
- 'placeholder.select': '请选择',
1758
- 'placeholder.enter': '请输入',
1759
- 'placeholder.search': '搜索',
1760
- 'placeholder.filter': '筛选'
1810
+ 'system.action.powerOff': '关机',
1811
+ 'system.action.restart': '重启',
1812
+ 'system.confirm.title': '确认操作',
1813
+ 'system.confirm.message': '确定要{action}系统吗?此操作无法撤销。',
1814
+ 'system.button.cancel': '取消',
1815
+ 'system.button.confirm': '确认',
1816
+ // Maintenance page
1817
+ 'maintenance.restarting': '系统正在重启...',
1818
+ 'maintenance.poweredOff': '系统已关闭',
1819
+ 'maintenance.waiting': '请等待系统启动...',
1820
+ 'maintenance.redirecting.countdown': '将在 {countdown} 秒后自动跳转',
1821
+ 'maintenance.waiting.long': '系统仍在启动中,这可能需要一些时间...',
1822
+ 'maintenance.retry': '重试连接',
1823
+ 'maintenance.offline.description': '系统当前处于离线状态,请联系管理员开启设备。',
1824
+ // LSM Label
1825
+ 'lsm.label': '标签',
1826
+ 'lsm.placeholder.select': '请选择标签'
1761
1827
  };
1762
1828
 
1763
1829
  // seeder-st2110-components component library English language pack
1764
1830
  var enUS = {
1765
1831
  // General buttons
1766
- 'button.ok': 'OK',
1767
- 'button.cancel': 'Cancel',
1768
- 'button.save': 'Save',
1769
- 'button.delete': 'Delete',
1770
- 'button.edit': 'Edit',
1771
- 'button.add': 'Add',
1772
- 'button.confirm': 'Confirm',
1773
1832
  'button.close': 'Close',
1774
1833
  'button.apply': 'Apply',
1775
- 'button.submit': 'Submit',
1776
- 'button.next': 'Next',
1777
- 'button.previous': 'Previous',
1778
- 'button.refresh': 'Refresh',
1779
- 'button.retry': 'Retry',
1834
+ // Input placeholders
1835
+ 'input.placeholder.enterInteger': 'Enter an integer',
1836
+ 'input.placeholder.enterPort': ' Enter port (0-65535)',
1837
+ 'input.placeholder.enterPayload': 'Enter payload (96-127)',
1838
+ // Usage display
1839
+ 'usage.memory': 'Memory Usage',
1840
+ 'usage.totalMemory': 'Total Memory',
1841
+ 'usage.cpu': 'CPU Usage',
1842
+ 'usage.disk': 'Disk Usage',
1843
+ 'usage.cpuTemp': 'CPU Temperature',
1844
+ 'usage.memTemp': 'Memory Temperature',
1845
+ 'usage.nicTemp': 'NIC Temperature',
1846
+ 'usage.diskTemp': 'Disk Temperature',
1847
+ 'usage.gpu': 'GPU Usage',
1848
+ 'usage.gpuTemp': 'GPU Temperature',
1780
1849
  // Menu
1781
1850
  'menu.networkSettings': 'Network Settings',
1782
1851
  'menu.ptp': 'PTP',
@@ -1787,165 +1856,118 @@ var enUS = {
1787
1856
  'menu.system': 'System',
1788
1857
  // Network Settings Modal
1789
1858
  'networkSettings.title': 'Network Settings',
1859
+ 'networkSettings.name': 'Name',
1790
1860
  'networkSettings.ipAddress': 'IP Address',
1791
1861
  'networkSettings.subnetMask': 'Netmask',
1792
1862
  'networkSettings.restartRequired': 'Configuration modified. Restart to apply changes?',
1793
1863
  'networkSettings.restartNow': 'Restart Now',
1794
1864
  'networkSettings.restartLater': 'Restart Later',
1795
- 'networkSettings.saveSuccess': 'saved successfully',
1865
+ 'networkSettings.saveSuccess': 'Success',
1796
1866
  // PTP Modal
1797
1867
  'ptp.title': 'PTP Settings',
1798
- 'ptp.enable': 'Enable PTP',
1799
- 'ptp.status': 'PTP Status',
1800
1868
  'ptp.domainNumber': 'Domain Number',
1801
1869
  'ptp.priority1': 'Priority 1',
1802
1870
  'ptp.priority2': 'Priority 2',
1803
1871
  'ptp.clockClass': 'Clock Class',
1872
+ 'ptp.clockClass.atomic': 'Atomic Clock ({value})',
1873
+ 'ptp.clockClass.gps': 'GPS ({value})',
1874
+ 'ptp.clockClass.slaveOnly': 'Slave-Only ({value})',
1804
1875
  'ptp.clockAccuracy': 'Clock Accuracy',
1805
1876
  'ptp.offsetScaledLogVariance': 'Offset Scaled Log Variance',
1806
- 'ptp.port': 'PTP Port',
1807
- 'ptp.master': 'Master',
1808
- 'ptp.slave': 'Slave',
1809
- 'ptp.grandmaster': 'Grandmaster',
1877
+ 'ptp.portIdentity': 'Port Identity',
1878
+ 'ptp.grandmasterIdentity': 'Grandmaster Identity',
1879
+ 'ptp.utcOffset': 'UTC Offset',
1880
+ 'ptp.connected': 'Connected',
1881
+ 'ptp.disconnected': 'Disconnected',
1810
1882
  'ptp.locked': 'Locked',
1811
1883
  'ptp.unlocked': 'Unlocked',
1812
- 'ptp.saveSuccess': 'PTP settings saved successfully',
1813
- 'ptp.saveFailed': 'Failed to save PTP settings',
1884
+ 'ptp.saveSuccess': 'Success',
1814
1885
  // NMOS Modal
1815
1886
  'nmos.title': 'NMOS Settings',
1816
- 'nmos.enable': 'Enable NMOS',
1817
1887
  'nmos.hostAddress': 'Host Address',
1818
- 'nmos.port': 'Port',
1819
- 'nmos.registrationUrl': 'Registration URL',
1820
- 'nmos.connectionUrl': 'Connection URL',
1821
- 'nmos.nodeId': 'Node ID',
1822
- 'nmos.deviceId': 'Device ID',
1823
- 'nmos.saveSuccess': 'NMOS settings saved successfully',
1824
- 'nmos.saveFailed': 'Failed to save NMOS settings',
1888
+ 'nmos.domain': 'Domain',
1889
+ 'nmos.registryAddress': 'Registry Address',
1890
+ 'nmos.registrationPort': 'Registry Port',
1891
+ 'nmos.registryVersion': 'Registry Version',
1892
+ 'nmos.loggingLevel': 'Logging Level',
1893
+ 'nmos.placeholder.selectHostAddress': 'Select IP address',
1894
+ 'nmos.placeholder.selectVersion': 'Select version',
1895
+ 'nmos.saveSuccess': 'Success',
1825
1896
  // Preset Modal
1826
1897
  'preset.title': 'Preset Management',
1827
1898
  'preset.name': 'Name',
1828
1899
  'preset.categories': 'Categories',
1829
1900
  'preset.description': 'Description',
1830
- 'preset.save': 'Save Preset',
1831
- 'preset.load': 'Load Preset',
1832
- 'preset.delete': 'Delete Preset',
1833
- 'preset.edit': 'Edit Preset',
1834
- 'preset.confirmDelete': 'Confirm Deletion',
1835
- 'preset.deleteConfirmMessage': 'Are you sure you want to delete this preset?',
1836
- 'preset.saveSuccess': 'Preset saved successfully',
1837
- 'preset.loadSuccess': 'Preset loaded successfully',
1838
- 'preset.deleteSuccess': 'Preset deleted successfully',
1839
- 'preset.saveFailed': 'Failed to save preset',
1840
- 'preset.loadFailed': 'Failed to load preset',
1841
- 'preset.deleteFailed': 'Failed to delete preset',
1842
- 'preset.noPresets': 'No presets',
1843
- 'preset.enterName': 'Enter preset name',
1844
- 'preset.enterDescription': 'Enter preset description',
1845
- 'preset.selectCategory': 'Select category',
1901
+ 'preset.placeholder.enterName': 'Enter name',
1902
+ 'preset.placeholder.enterDescription': 'Enter description',
1903
+ 'preset.header.name': 'Name',
1904
+ 'preset.header.createTime': 'Create Time',
1905
+ 'preset.header.description': 'Description',
1906
+ 'preset.button.new': 'New Preset',
1907
+ 'preset.button.delete': 'Delete',
1908
+ 'preset.button.load': 'Load',
1909
+ 'preset.button.save': 'Save',
1910
+ 'preset.button.edit': 'Edit',
1911
+ 'preset.button.cancel': 'Cancel',
1912
+ 'preset.empty.noData': 'Select a preset from the list to view details',
1913
+ 'preset.empty.create': 'Create New Preset',
1914
+ 'preset.untitled': 'Untitled',
1915
+ 'preset.delete.title': 'Delete Preset',
1916
+ 'preset.delete.confirmMessage': 'Are you sure you want to delete preset',
1917
+ 'preset.load.title': 'Load Preset',
1918
+ 'preset.load.confirmMessage': 'Are you sure you want to load preset',
1919
+ 'preset.load.loading': 'Loading...',
1920
+ 'preset.success': 'Success',
1921
+ 'preset.validation.nameRequired': 'Name is required',
1922
+ 'preset.validation.categoryRequired': 'No category selected',
1923
+ 'preset.error.noSelectionOrIdMissing': 'No preset selected or preset ID is missing',
1846
1924
  // License/Auth Modal
1847
- 'license.title': 'License Management',
1848
- 'license.authCode': 'Authorization Code',
1849
- 'license.activate': 'Activate',
1850
- 'license.deactivate': 'Deactivate',
1851
- 'license.valid': 'License Valid',
1852
- 'license.expired': 'License Expired',
1853
- 'license.invalid': 'License Invalid',
1854
- 'license.activationSuccess': 'Activation successful',
1855
- 'license.deactivationSuccess': 'Deactivation successful',
1856
- 'license.activationFailed': 'Activation failed',
1857
- 'license.enterAuthCode': 'Enter authorization code',
1858
- 'license.productInfo': 'Product Information',
1859
- 'license.customerInfo': 'Customer Information',
1860
- 'license.expiryDate': 'Expiry Date',
1861
- 'license.features': 'Features',
1925
+ 'license.title': 'Register License',
1926
+ 'license.machineCode': 'Machine Code',
1927
+ 'license.key': 'License Key',
1928
+ 'license.placeholder.enterKey': 'Enter your license key',
1929
+ 'license.button.activate': 'Activate Now',
1930
+ 'license.button.reactivate': 'Reactivate',
1931
+ 'license.button.ignore': 'Ignore',
1932
+ 'license.status.unactivated': 'Unactivated',
1933
+ 'license.status.activated': 'Already activated',
1934
+ 'license.status.expired': 'Expired',
1935
+ 'license.status.invalid': 'Invalid',
1936
+ 'license.status.expiresOn': 'Expires on',
1937
+ 'license.validation.keyRequired': 'License key cannot be empty',
1938
+ 'license.error.authorizationFailed': 'Authorization failed',
1862
1939
  // Upgrade related
1863
- 'upgrade.title': 'System Upgrade',
1864
- 'upgrade.checking': 'Checking for updates...',
1865
- 'upgrade.available': 'New version available',
1866
- 'upgrade.upToDate': 'Up to date',
1867
- 'upgrade.downloading': 'Downloading...',
1868
- 'upgrade.installing': 'Installing...',
1869
- 'upgrade.complete': 'Upgrade complete',
1870
- 'upgrade.failed': 'Upgrade failed',
1871
- 'upgrade.confirmRestart': 'Device restart required after upgrade. Continue?',
1872
- 'upgrade.newVersion': 'New Version',
1873
- 'upgrade.currentVersion': 'Current Version',
1874
- 'upgrade.releaseNotes': 'Release Notes',
1875
- 'upgrade.download': 'Download',
1876
- 'upgrade.install': 'Install',
1877
- 'upgrade.cancel': 'Cancel',
1940
+ 'upgrade.menu.download': 'Download Config File',
1941
+ 'upgrade.menu.softwareUpdate': 'Software Update',
1942
+ 'upgrade.status.idle': 'Idle',
1943
+ 'upgrade.status.uploading': 'Uploading...',
1944
+ 'upgrade.status.uploadComplete': 'Upload complete, starting upgrade...',
1945
+ 'upgrade.status.upgrading': 'Upgrading...',
1946
+ 'upgrade.error.downloadNotConfigured': 'Download functionality not configured',
1947
+ 'upgrade.error.downloadFailed': 'Download failed',
1948
+ 'upgrade.error.uploadFailed': 'Upload failed',
1949
+ 'upgrade.error.invalidFileFormat': 'Upload failed: Invalid file format',
1950
+ 'upgrade.error.upgradeFailed': 'Upgrade failed',
1878
1951
  // System operations
1879
- 'system.restart': 'Restart',
1880
- 'system.shutdown': 'Shutdown',
1881
1952
  'system.poweroff': 'Power Off',
1882
- 'system.reboot': 'Reboot',
1883
- 'system.confirmRestart': 'Confirm Restart',
1884
- 'system.confirmShutdown': 'Confirm Shutdown',
1885
- 'system.restartConfirmMessage': 'Are you sure you want to restart the device?',
1886
- 'system.shutdownConfirmMessage': 'Are you sure you want to shutdown the device?',
1887
- 'system.restarting': 'Device is restarting...',
1888
- 'system.shuttingDown': 'Device is shutting down...',
1953
+ 'system.restart': 'Restart',
1954
+ 'system.action.powerOff': 'power off',
1955
+ 'system.action.restart': 'restart',
1956
+ 'system.confirm.title': 'Confirmation Required',
1957
+ 'system.confirm.message': 'Are you sure you want to {action} the system? This action cannot be undone.',
1958
+ 'system.button.cancel': 'Cancel',
1959
+ 'system.button.confirm': 'Confirm',
1889
1960
  // Maintenance page
1890
- 'maintenance.title': 'System Maintenance',
1891
- 'maintenance.description': 'Device is under maintenance, please wait...',
1892
- 'maintenance.restart': 'Device is restarting',
1893
- 'maintenance.poweroff': 'Device is powered off',
1894
- 'maintenance.redirecting': 'Redirecting...',
1895
- 'maintenance.backToHome': 'Back to Home',
1896
- // Form validation
1897
- 'validation.required': 'This field is required',
1898
- 'validation.invalidIP': 'Invalid IP address format',
1899
- 'validation.invalidPort': 'Port number should be 1-65535',
1900
- 'validation.invalidEmail': 'Invalid email format',
1901
- 'validation.minLength': 'Minimum {min} characters required',
1902
- 'validation.maxLength': 'Maximum {max} characters allowed',
1903
- 'validation.min': 'Minimum value is {min}',
1904
- 'validation.max': 'Maximum value is {max}',
1905
- 'validation.pattern': 'Invalid format',
1906
- 'validation.unique': 'This value already exists',
1907
- // Status messages
1908
- 'status.loading': 'Loading...',
1909
- 'status.saving': 'Saving...',
1910
- 'status.deleting': 'Deleting...',
1911
- 'status.updating': 'Updating...',
1912
- 'status.submitting': 'Submitting...',
1913
- 'status.success': 'Success',
1914
- 'status.failed': 'Failed',
1915
- 'status.error': 'Error',
1916
- 'status.pending': 'Pending',
1917
- 'status.processing': 'Processing',
1918
- 'status.completed': 'Completed',
1919
- 'status.cancelled': 'Cancelled',
1920
- // Confirmation dialogs
1921
- 'confirm.title': 'Confirm Action',
1922
- 'confirm.message': 'Are you sure you want to proceed?',
1923
- 'confirm.cancel': 'Cancel',
1924
- 'confirm.ok': 'OK',
1925
- // Empty states
1926
- 'empty.noData': 'No Data',
1927
- 'empty.noResults': 'No Results',
1928
- 'empty.noItems': 'No Items',
1929
- // General labels
1930
- 'label.name': 'Name',
1931
- 'label.description': 'Description',
1932
- 'label.status': 'Status',
1933
- 'label.type': 'Type',
1934
- 'label.action': 'Action',
1935
- 'label.actions': 'Actions',
1936
- 'label.settings': 'Settings',
1937
- 'label.configuration': 'Configuration',
1938
- 'label.information': 'Information',
1939
- 'label.version': 'Version',
1940
- 'label.time': 'Time',
1941
- 'label.date': 'Date',
1942
- 'label.enable': 'Enable',
1943
- 'label.disable': 'Disable',
1944
- // Placeholders
1945
- 'placeholder.select': 'Please select',
1946
- 'placeholder.enter': 'Please enter',
1947
- 'placeholder.search': 'Search',
1948
- 'placeholder.filter': 'Filter'
1961
+ 'maintenance.restarting': 'System is restarting...',
1962
+ 'maintenance.poweredOff': 'System is powered off',
1963
+ 'maintenance.waiting': 'Please wait while the system is starting up...',
1964
+ 'maintenance.redirecting.countdown': 'Redirecting automatically in {countdown} second{countdown, plural, one {} other {s}}',
1965
+ 'maintenance.waiting.long': 'Still starting up... This may take a moment.',
1966
+ 'maintenance.retry': 'Retry connection',
1967
+ 'maintenance.offline.description': 'The system is currently offline. Please contact your administrator to power it on.',
1968
+ // LSM Label
1969
+ 'lsm.label': 'Label',
1970
+ 'lsm.placeholder.select': 'Select label'
1949
1971
  };
1950
1972
 
1951
1973
  const NetworkFieldGroup = _ref => {
@@ -1961,7 +1983,7 @@ const NetworkFieldGroup = _ref => {
1961
1983
  const defaultFieldConfig = {
1962
1984
  name: {
1963
1985
  label: intl.formatMessage({
1964
- id: 'label.name'
1986
+ id: 'networkSettings.name'
1965
1987
  }),
1966
1988
  enabled: true
1967
1989
  },
@@ -1980,8 +2002,8 @@ const NetworkFieldGroup = _ref => {
1980
2002
  };
1981
2003
  const mergedFieldConfig = _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, defaultFieldConfig), fieldConfig), {}, {
1982
2004
  netmask: {
1983
- label: "Netmask",
1984
- enabled: (_fieldConfig$netmask$ = (_fieldConfig$netmask = fieldConfig.netmask) === null || _fieldConfig$netmask === void 0 ? void 0 : _fieldConfig$netmask.enabled) !== null && _fieldConfig$netmask$ !== void 0 ? _fieldConfig$netmask$ : defaultFieldConfig.netmask.enabled // 合并 enabled
2005
+ label: defaultFieldConfig.netmask.label,
2006
+ enabled: (_fieldConfig$netmask$ = (_fieldConfig$netmask = fieldConfig.netmask) === null || _fieldConfig$netmask === void 0 ? void 0 : _fieldConfig$netmask.enabled) !== null && _fieldConfig$netmask$ !== void 0 ? _fieldConfig$netmask$ : defaultFieldConfig.netmask.enabled
1985
2007
  }
1986
2008
  });
1987
2009
  return /*#__PURE__*/jsxs(Fragment, {
@@ -2383,86 +2405,86 @@ var NetworkSettingsModal$1 = /*#__PURE__*/memo(NetworkSettingsModal);
2383
2405
 
2384
2406
  const defaultFieldConfigs = {
2385
2407
  clock_class: {
2386
- label: 'Clock Class',
2408
+ label: 'ptp.clockClass',
2387
2409
  formType: 'select',
2388
2410
  options: [{
2389
2411
  value: 6,
2390
- label: 'Atomic Clock (6)'
2412
+ label: 'ptp.clockClass.atomic'
2391
2413
  }, {
2392
2414
  value: 7,
2393
- label: 'GPS (7)'
2415
+ label: 'ptp.clockClass.gps'
2394
2416
  }, {
2395
2417
  value: 248,
2396
- label: 'Slave-Only (248)'
2418
+ label: 'ptp.clockClass.slaveOnly'
2397
2419
  }],
2398
2420
  readOnly: true
2399
2421
  },
2400
2422
  clock_accuracy: {
2401
- label: 'Clock Accuracy',
2423
+ label: 'ptp.clockAccuracy',
2402
2424
  formType: 'number',
2403
2425
  readOnly: true
2404
2426
  },
2405
2427
  offset_scaled_log_variance: {
2406
- label: 'Offset Scaled Log Variance',
2428
+ label: 'ptp.offsetScaledLogVariance',
2407
2429
  formType: 'number',
2408
2430
  readOnly: true
2409
2431
  },
2410
2432
  grandmaster_priority1: {
2411
- label: 'Priority 1',
2433
+ label: 'ptp.priority1',
2412
2434
  formType: 'number',
2413
2435
  readOnly: true
2414
2436
  },
2415
2437
  grandmaster_priority2: {
2416
- label: 'Priority 2',
2438
+ label: 'ptp.priority2',
2417
2439
  formType: 'number',
2418
2440
  readOnly: true
2419
2441
  },
2420
2442
  grandmaster_identity: {
2421
- label: 'Grandmaster Identity',
2443
+ label: 'ptp.grandmasterIdentity',
2422
2444
  formType: 'text',
2423
2445
  readOnly: true
2424
2446
  },
2425
2447
  master_port_id: {
2426
- label: 'Port Identity',
2448
+ label: 'ptp.portIdentity',
2427
2449
  formType: 'text',
2428
2450
  readOnly: true
2429
2451
  },
2430
2452
  t1_domain_number: {
2431
- label: 'Domain',
2453
+ label: 'ptp.domainNumber',
2432
2454
  formType: 'number',
2433
2455
  min: 0,
2434
2456
  max: 127,
2435
2457
  readOnly: false
2436
2458
  },
2437
2459
  master_utc_offset: {
2438
- label: 'UTC Offset',
2460
+ label: 'ptp.utcOffset',
2439
2461
  formType: 'number',
2440
2462
  readOnly: true
2441
2463
  },
2442
2464
  is_connected: {
2443
- label: 'Connected Status',
2465
+ label: 'ptp.connected',
2444
2466
  formType: 'badge',
2445
2467
  statusMap: {
2446
2468
  0: {
2447
- text: 'Disconnected',
2469
+ text: 'ptp.disconnected',
2448
2470
  color: 'red'
2449
2471
  },
2450
2472
  1: {
2451
- text: 'Connected',
2473
+ text: 'ptp.connected',
2452
2474
  color: 'green'
2453
2475
  }
2454
2476
  }
2455
2477
  },
2456
2478
  is_locked: {
2457
- label: 'Locked Status',
2479
+ label: 'ptp.locked',
2458
2480
  formType: 'badge',
2459
2481
  statusMap: {
2460
2482
  0: {
2461
- text: 'Unlocked',
2483
+ text: 'ptp.unlocked',
2462
2484
  color: 'red'
2463
2485
  },
2464
2486
  1: {
2465
- text: 'Locked',
2487
+ text: 'ptp.locked',
2466
2488
  color: 'green'
2467
2489
  }
2468
2490
  }
@@ -2505,6 +2527,7 @@ const PtpModal = _ref => {
2505
2527
  modalProps = {},
2506
2528
  formProps = {}
2507
2529
  } = _ref;
2530
+ const intl = useIntl();
2508
2531
  const [ptpStatus, setPtpStatus] = useState(null);
2509
2532
  const [loading, setLoading] = useState(false);
2510
2533
  const [form] = Form.useForm();
@@ -2535,13 +2558,26 @@ const PtpModal = _ref => {
2535
2558
  if (!ptpStatus) return [];
2536
2559
  return convertPtpStatusToArray(ptpStatus, fieldConfigs, fieldOrder);
2537
2560
  }, [ptpStatus, fieldConfigs, fieldOrder]);
2561
+
2562
+ // 渲染 Form.Item 的 label
2563
+ const renderLabel = item => {
2564
+ // 如果 label 是国际化 key(包含点号),则使用 formatMessage
2565
+ if (item.label && typeof item.label === 'string' && item.label.includes('.')) {
2566
+ return intl.formatMessage({
2567
+ id: item.label
2568
+ });
2569
+ }
2570
+ return item.label;
2571
+ };
2538
2572
  const handleSubmit = async () => {
2539
2573
  const values = await form.getFieldsValue();
2540
2574
  setLoading(true);
2541
2575
  try {
2542
2576
  const response = await updatePtpInfo(values);
2543
2577
  if (response) {
2544
- message.success('Success');
2578
+ message.success(intl.formatMessage({
2579
+ id: 'ptp.saveSuccess'
2580
+ }));
2545
2581
  setTimeout(() => {
2546
2582
  onClose();
2547
2583
  }, 1500);
@@ -2553,11 +2589,18 @@ const PtpModal = _ref => {
2553
2589
  }
2554
2590
  };
2555
2591
  const renderFormItem = item => {
2556
- var _item$statusMap, _item$min, _item$max;
2592
+ var _item$options, _item$statusMap, _item$min, _item$max;
2557
2593
  switch (item.formType) {
2558
2594
  case 'select':
2595
+ const selectOptions = (_item$options = item.options) === null || _item$options === void 0 ? void 0 : _item$options.map(opt => _objectSpread2$1(_objectSpread2$1({}, opt), {}, {
2596
+ label: intl.formatMessage({
2597
+ id: opt.label
2598
+ }, {
2599
+ value: opt.value
2600
+ })
2601
+ }));
2559
2602
  return /*#__PURE__*/jsx(Select, {
2560
- options: item.options,
2603
+ options: selectOptions,
2561
2604
  disabled: item.readOnly
2562
2605
  });
2563
2606
  case 'switch':
@@ -2578,7 +2621,9 @@ const PtpModal = _ref => {
2578
2621
  },
2579
2622
  children: /*#__PURE__*/jsx(Badge, {
2580
2623
  color: status.color,
2581
- text: status.text
2624
+ text: intl.formatMessage({
2625
+ id: status.text
2626
+ })
2582
2627
  })
2583
2628
  });
2584
2629
  case 'number':
@@ -2599,11 +2644,17 @@ const PtpModal = _ref => {
2599
2644
 
2600
2645
  // 合并默认模态框属性和传入的属性
2601
2646
  const mergedModalProps = _objectSpread2$1({
2602
- title: "PTP",
2647
+ title: intl.formatMessage({
2648
+ id: 'ptp.title'
2649
+ }),
2603
2650
  width: 650,
2604
2651
  open,
2605
- okText: "Apply",
2606
- cancelText: "Close",
2652
+ okText: intl.formatMessage({
2653
+ id: 'button.apply'
2654
+ }),
2655
+ cancelText: intl.formatMessage({
2656
+ id: 'button.close'
2657
+ }),
2607
2658
  onCancel: onClose,
2608
2659
  onOk: handleSubmit,
2609
2660
  confirmLoading: loading
@@ -2624,7 +2675,7 @@ const PtpModal = _ref => {
2624
2675
  return /*#__PURE__*/jsx(StyledModal$3, _objectSpread2$1(_objectSpread2$1({}, mergedModalProps), {}, {
2625
2676
  children: /*#__PURE__*/jsx(Form, _objectSpread2$1(_objectSpread2$1({}, mergedFormProps), {}, {
2626
2677
  children: ptpStatusArray.map(item => /*#__PURE__*/jsx(Form.Item, {
2627
- label: item.label,
2678
+ label: renderLabel(item),
2628
2679
  name: item.key,
2629
2680
  initialValue: item.value,
2630
2681
  children: renderFormItem(item)
@@ -2643,10 +2694,21 @@ const LeftList = /*#__PURE__*/memo(_ref => {
2643
2694
  onRemove,
2644
2695
  hasPresets = dataSource.length > 0,
2645
2696
  texts = {
2646
- newButton: "New Preset",
2647
- removeButton: "Delete"
2697
+ newButton: "preset.button.new",
2698
+ removeButton: "preset.button.delete"
2648
2699
  }
2649
2700
  } = _ref;
2701
+ const intl = useIntl();
2702
+
2703
+ // 格式化文本的辅助函数
2704
+ const fmt = key => {
2705
+ if (typeof key === 'string' && key.includes('.')) {
2706
+ return intl.formatMessage({
2707
+ id: key
2708
+ });
2709
+ }
2710
+ return key;
2711
+ };
2650
2712
  return /*#__PURE__*/jsxs("div", {
2651
2713
  className: "h-full left-list-wrapper",
2652
2714
  children: [/*#__PURE__*/jsx("div", {
@@ -2656,13 +2718,13 @@ const LeftList = /*#__PURE__*/memo(_ref => {
2656
2718
  className: "grid grid-cols-3 gap-2 w-full list-header",
2657
2719
  children: [/*#__PURE__*/jsx("div", {
2658
2720
  className: "min-w-0",
2659
- children: "Name"
2721
+ children: fmt('preset.header.name')
2660
2722
  }), /*#__PURE__*/jsx("div", {
2661
2723
  className: "min-w-0",
2662
- children: "Create Time"
2724
+ children: fmt('preset.header.createTime')
2663
2725
  }), /*#__PURE__*/jsx("div", {
2664
2726
  className: "min-w-0",
2665
- children: "Description"
2727
+ children: fmt('preset.header.description')
2666
2728
  })]
2667
2729
  }),
2668
2730
  dataSource: dataSource,
@@ -2680,7 +2742,7 @@ const LeftList = /*#__PURE__*/memo(_ref => {
2680
2742
  children: /*#__PURE__*/jsx(Typography.Text, {
2681
2743
  ellipsis: true,
2682
2744
  title: item.name,
2683
- children: item.name || "Untitled Preset"
2745
+ children: item.name || fmt('preset.untitled')
2684
2746
  })
2685
2747
  }), /*#__PURE__*/jsx("div", {
2686
2748
  className: "min-w-0",
@@ -2710,7 +2772,7 @@ const LeftList = /*#__PURE__*/memo(_ref => {
2710
2772
  onClick: onAddNew,
2711
2773
  className: "p-0 h-auto",
2712
2774
  icon: /*#__PURE__*/jsx(PlusOutlined, {}),
2713
- children: "Create New Preset"
2775
+ children: fmt('preset.empty.create')
2714
2776
  })
2715
2777
  })
2716
2778
  })
@@ -2776,26 +2838,44 @@ const RightDetailForm = /*#__PURE__*/memo(_ref3 => {
2776
2838
  originalPresetData,
2777
2839
  fields = {
2778
2840
  name: {
2779
- label: "Name",
2780
- placeholder: "Enter name",
2841
+ label: "preset.name",
2842
+ placeholder: "preset.placeholder.enterName",
2781
2843
  required: true
2844
+ },
2845
+ category_list: {
2846
+ label: "preset.categories"
2847
+ },
2848
+ description: {
2849
+ label: "preset.description",
2850
+ placeholder: "preset.placeholder.enterDescription"
2782
2851
  }
2783
2852
  },
2784
2853
  texts = {
2785
- loadButton: "Load",
2786
- saveButton: "Save",
2787
- editButton: "Edit",
2788
- cancelButton: "Cancel"
2854
+ loadButton: "preset.button.load",
2855
+ saveButton: "preset.button.save",
2856
+ editButton: "preset.button.edit",
2857
+ cancelButton: "preset.button.cancel"
2789
2858
  },
2790
2859
  presetChanged,
2791
2860
  // 作用:在切换选中预设时强制触发 Checkbox 的重新初始化
2792
2861
  enableEdit = true
2793
2862
  } = _ref3;
2863
+ const intl = useIntl();
2794
2864
  const [initialSelected, setInitialSelected] = useState([]);
2795
2865
  const [isEditMode, setIsEditMode] = useState(false); // 是否进入编辑模式
2796
2866
  const currentSelected = Form.useWatch('category_list', form) || [];
2797
2867
 
2798
- // 检查是否包含category_list字段
2868
+ // 格式化文本的辅助函数
2869
+ const fmt = key => {
2870
+ if (typeof key === 'string' && key.includes('.')) {
2871
+ return intl.formatMessage({
2872
+ id: key
2873
+ });
2874
+ }
2875
+ return key;
2876
+ };
2877
+
2878
+ // 检查是否包含 category_list 字段
2799
2879
  const hasCategoryList = fields.category_list !== null && fields.category_list !== undefined;
2800
2880
 
2801
2881
  // 初始化 category_list 的选择状态
@@ -2888,39 +2968,15 @@ const RightDetailForm = /*#__PURE__*/memo(_ref3 => {
2888
2968
  },
2889
2969
  children: [/*#__PURE__*/jsx(Form.Item, {
2890
2970
  name: "name",
2891
- label: fields.name.label
2892
- // rules={[
2893
- // {
2894
- // required: fields.name.required,
2895
- // validator: async (_, value) => {
2896
- // if (!value || value.trim() === '') {
2897
- // return Promise.reject(new Error('Preset name cannot be empty or spaces only'));
2898
- // }
2899
- // }
2900
- // }
2901
- // ]}
2902
- ,
2971
+ label: fmt(fields.name.label),
2903
2972
  required: true,
2904
2973
  children: /*#__PURE__*/jsx(Input, {
2905
- placeholder: fields.name.placeholder,
2974
+ placeholder: fmt(fields.name.placeholder),
2906
2975
  disabled: shouldDisableNameAndDesc
2907
2976
  })
2908
2977
  }), hasCategoryList && /*#__PURE__*/jsx(Form.Item, {
2909
2978
  name: "category_list",
2910
- label: fields.category_list.label
2911
- // rules={[
2912
- // {
2913
- // required: fields.category_list.required,
2914
- // message: 'Please select at least one category',
2915
- // validator: (_, value) => {
2916
- // if (value && value.length > 0) {
2917
- // return Promise.resolve();
2918
- // }
2919
- // return Promise.reject(new Error('Please select at least one category'));
2920
- // }
2921
- // }
2922
- // ]}
2923
- ,
2979
+ label: fmt(fields.category_list.label),
2924
2980
  required: true,
2925
2981
  children: /*#__PURE__*/jsx(Checkbox.Group, {
2926
2982
  className: "grid grid-cols-2 gap-2",
@@ -2934,10 +2990,10 @@ const RightDetailForm = /*#__PURE__*/memo(_ref3 => {
2934
2990
  })
2935
2991
  }), fields.description && /*#__PURE__*/jsx(Form.Item, {
2936
2992
  name: "description",
2937
- label: fields.description.label,
2993
+ label: fmt(fields.description.label),
2938
2994
  children: /*#__PURE__*/jsx(Input.TextArea, {
2939
2995
  rows: 4,
2940
- placeholder: fields.description.placeholder,
2996
+ placeholder: fmt(fields.description.placeholder),
2941
2997
  disabled: shouldDisableNameAndDesc,
2942
2998
  style: {
2943
2999
  resize: 'none'
@@ -3005,24 +3061,24 @@ const Preset = _ref => {
3005
3061
  // 字段配置
3006
3062
  fields = {
3007
3063
  name: {
3008
- label: "Name",
3009
- placeholder: "Enter name",
3064
+ label: "preset.name",
3065
+ placeholder: "preset.placeholder.enterName",
3010
3066
  required: true
3011
3067
  }
3012
3068
  },
3013
3069
  texts = {
3014
- title: "Preset Management",
3015
- emptyText: "Select a preset from the list to view details",
3016
- deleteConfirm: "Are you sure you want to delete preset",
3017
- loadConfirm: "Are you sure you want to load preset",
3018
- loadText: "Loading...",
3019
- successText: "Success",
3020
- newButton: "New Preset",
3021
- removeButton: "Delete",
3022
- loadButton: "Load",
3023
- saveButton: "Save",
3024
- editButton: "Edit",
3025
- cancelButton: "Cancel"
3070
+ title: "preset.title",
3071
+ emptyText: "preset.empty.noData",
3072
+ deleteConfirm: "preset.delete.confirmMessage",
3073
+ loadConfirm: "preset.load.confirmMessage",
3074
+ loadText: "preset.load.loading",
3075
+ successText: "preset.success",
3076
+ newButton: "preset.button.new",
3077
+ removeButton: "preset.button.delete",
3078
+ loadButton: "preset.button.load",
3079
+ saveButton: "preset.button.save",
3080
+ editButton: "preset.button.edit",
3081
+ cancelButton: "preset.button.cancel"
3026
3082
  },
3027
3083
  // 样式定制
3028
3084
  width = 1000,
@@ -3031,6 +3087,7 @@ const Preset = _ref => {
3031
3087
  // 功能配置
3032
3088
  enableEdit = true
3033
3089
  } = _ref;
3090
+ const intl = useIntl();
3034
3091
  const {
3035
3092
  message,
3036
3093
  modal
@@ -3040,6 +3097,16 @@ const Preset = _ref => {
3040
3097
  const [loading, setLoading] = useState(false);
3041
3098
  const [presetChanged, setPresetChanged] = useState(0);
3042
3099
  const [form] = Form.useForm();
3100
+
3101
+ // 格式化文本的辅助函数
3102
+ const fmt = useCallback(key => {
3103
+ if (typeof key === 'string' && key.includes('.')) {
3104
+ return intl.formatMessage({
3105
+ id: key
3106
+ });
3107
+ }
3108
+ return key;
3109
+ }, [intl]);
3043
3110
  const fetchPresetList = useCallback(async () => {
3044
3111
  try {
3045
3112
  const data = await getPresetList();
@@ -3087,16 +3154,16 @@ const Preset = _ref => {
3087
3154
  const handleRemove = useCallback(async () => {
3088
3155
  if (!selectedPreset) return;
3089
3156
 
3090
- // 检查是否为新建的未保存数据(无id)
3157
+ // 检查是否为新建的未保存数据(无 id)
3091
3158
  const isUnsavedPreset = !selectedPreset.id;
3092
- const presetName = selectedPreset.name || 'Untitled Preset';
3159
+ const presetName = selectedPreset.name || fmt('preset.untitled');
3093
3160
  try {
3094
3161
  modal.confirm({
3095
3162
  icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
3096
- title: 'Delete Preset',
3097
- content: "".concat(texts.deleteConfirm, " \"").concat(presetName, "\"?"),
3098
- cancelText: 'Cancel',
3099
- okText: 'Delete',
3163
+ title: fmt('preset.delete.title'),
3164
+ content: "".concat(fmt('preset.delete.confirmMessage'), " \"").concat(presetName, "\"?"),
3165
+ cancelText: fmt('button.cancel'),
3166
+ okText: fmt('button.delete'),
3100
3167
  onOk: async () => {
3101
3168
  // 在删除前记录当前选中项的位置
3102
3169
  const currentIndex = presetList.findIndex(item => isUnsavedPreset ? !item.id : item.id === selectedPreset.id);
@@ -3104,7 +3171,7 @@ const Preset = _ref => {
3104
3171
  await removePreset({
3105
3172
  id: selectedPreset.id
3106
3173
  });
3107
- message.success(texts.successText);
3174
+ message.success(fmt('preset.success'));
3108
3175
  } else {
3109
3176
  // 移除未保存的预设
3110
3177
  setPresetList(prev => prev.filter(item => !!item.id));
@@ -3143,17 +3210,17 @@ const Preset = _ref => {
3143
3210
  } catch (error) {
3144
3211
  console.error('Failed to delete preset:', error);
3145
3212
  }
3146
- }, [selectedPreset, form, modal, message, texts, removePreset, getPresetList]);
3213
+ }, [selectedPreset, form, modal, message, removePreset, getPresetList, fmt]);
3147
3214
  const handleLoadPreset = useCallback(async loadData => {
3148
3215
  if (!loadData) return;
3149
3216
  let modalInstance = null;
3150
3217
  let resolveOk = null; // 用于控制 confirm 关闭时机
3151
3218
 
3152
3219
  modalInstance = modal.confirm({
3153
- title: 'Load Preset',
3154
- content: "".concat(texts.loadConfirm, " \"").concat(loadData.name, "\"?"),
3155
- cancelText: 'Cancel',
3156
- okText: 'Load',
3220
+ title: fmt('preset.load.title'),
3221
+ content: "".concat(fmt('preset.load.confirmMessage'), " \"").concat(loadData.name, "\"?"),
3222
+ cancelText: fmt('button.cancel'),
3223
+ okText: fmt('preset.button.load'),
3157
3224
  // onOk 返回一个 pending Promise
3158
3225
  onOk: () => {
3159
3226
  return new Promise((resolve, reject) => {
@@ -3161,7 +3228,7 @@ const Preset = _ref => {
3161
3228
 
3162
3229
  // 立即切换为 loading 状态
3163
3230
  modalInstance.update({
3164
- title: texts.loadText,
3231
+ title: fmt('preset.load.loading'),
3165
3232
  content: /*#__PURE__*/jsx(Spin, {
3166
3233
  size: "large",
3167
3234
  className: "block mx-auto"
@@ -3187,11 +3254,11 @@ const Preset = _ref => {
3187
3254
  category_list: loadData.category_list
3188
3255
  }));
3189
3256
 
3190
- // 成功:1秒后自动关闭
3257
+ // 成功:1 秒后自动关闭
3191
3258
  setTimeout(() => {
3192
3259
  var _resolveOk;
3193
3260
  (_resolveOk = resolveOk) === null || _resolveOk === void 0 || _resolveOk();
3194
- message.success(texts.successText);
3261
+ message.success(fmt('preset.success'));
3195
3262
  // 加载成功的外部回调
3196
3263
  if (onLoadSuccess) {
3197
3264
  onLoadSuccess(loadData);
@@ -3213,7 +3280,7 @@ const Preset = _ref => {
3213
3280
  // 用户取消
3214
3281
  }
3215
3282
  });
3216
- }, [loadPreset, texts, message, modal, onLoadSuccess, onLoadError]);
3283
+ }, [loadPreset, message, modal, onLoadSuccess, onLoadError, fmt]);
3217
3284
  const handleSave = useCallback(async () => {
3218
3285
  setLoading(true);
3219
3286
  try {
@@ -3223,7 +3290,7 @@ const Preset = _ref => {
3223
3290
  // 验证预设名称
3224
3291
  if ((_fields$name = fields.name) !== null && _fields$name !== void 0 && _fields$name.required) {
3225
3292
  if (!values.name || values.name.trim() === '') {
3226
- message.error('Name is required.');
3293
+ message.error(fmt('preset.validation.nameRequired'));
3227
3294
  return; // 直接返回 不执行
3228
3295
  }
3229
3296
  }
@@ -3231,12 +3298,12 @@ const Preset = _ref => {
3231
3298
  // 验证分类列表
3232
3299
  if ((_fields$category_list2 = fields.category_list) !== null && _fields$category_list2 !== void 0 && _fields$category_list2.required) {
3233
3300
  if (!values.category_list || values.category_list.length === 0) {
3234
- message.error('No category selected.');
3301
+ message.error(fmt('preset.validation.categoryRequired'));
3235
3302
  return;
3236
3303
  }
3237
3304
  }
3238
3305
  await savePreset(values);
3239
- message.success(texts.successText);
3306
+ message.success(fmt('preset.success'));
3240
3307
  const savedPresetName = values.name;
3241
3308
 
3242
3309
  // 刷新列表
@@ -3258,10 +3325,10 @@ const Preset = _ref => {
3258
3325
  } finally {
3259
3326
  setLoading(false);
3260
3327
  }
3261
- }, [form, message, texts, savePreset, getPresetList]);
3328
+ }, [form, message, fields, savePreset, getPresetList, fmt]);
3262
3329
  const handleUpdate = useCallback(async () => {
3263
3330
  if (!selectedPreset || !selectedPreset.id) {
3264
- message.error('No preset selected or preset ID is missing.');
3331
+ message.error(fmt('preset.error.noSelectionOrIdMissing'));
3265
3332
  return;
3266
3333
  }
3267
3334
  setLoading(true);
@@ -3272,7 +3339,7 @@ const Preset = _ref => {
3272
3339
  // 验证预设名称
3273
3340
  if ((_fields$name2 = fields.name) !== null && _fields$name2 !== void 0 && _fields$name2.required) {
3274
3341
  if (!values.name || values.name.trim() === '') {
3275
- message.error('Name is required.');
3342
+ message.error(fmt('preset.validation.nameRequired'));
3276
3343
  return; // 直接返回 不执行
3277
3344
  }
3278
3345
  }
@@ -3292,21 +3359,21 @@ const Preset = _ref => {
3292
3359
  if (updatedPreset) {
3293
3360
  setSelectedPreset(updatedPreset);
3294
3361
  }
3295
- message.success(texts.successText);
3362
+ message.success(fmt('preset.success'));
3296
3363
  } catch (error) {
3297
3364
  console.error('Failed to update preset:', error);
3298
3365
  throw error;
3299
3366
  } finally {
3300
3367
  setLoading(false);
3301
3368
  }
3302
- }, [form, message, texts, updatePreset, selectedPreset]);
3369
+ }, [form, message, fields, updatePreset, selectedPreset, fmt]);
3303
3370
 
3304
3371
  // 初始化数据
3305
3372
  useEffect(() => {
3306
3373
  fetchPresetList();
3307
3374
  }, [fetchPresetList]);
3308
3375
  return /*#__PURE__*/jsx(StyledModal$3, {
3309
- title: texts.title,
3376
+ title: fmt(texts.title),
3310
3377
  width: width,
3311
3378
  open: open,
3312
3379
  wrapClassName: "preset-management ".concat(className),
@@ -3332,8 +3399,8 @@ const Preset = _ref => {
3332
3399
  onAddNew: handleAddNew,
3333
3400
  onRemove: handleRemove,
3334
3401
  texts: {
3335
- newButton: texts.newButton,
3336
- removeButton: texts.removeButton
3402
+ newButton: fmt(texts.newButton),
3403
+ removeButton: fmt(texts.removeButton)
3337
3404
  }
3338
3405
  })
3339
3406
  }), /*#__PURE__*/jsx(Col, {
@@ -3350,10 +3417,10 @@ const Preset = _ref => {
3350
3417
  ,
3351
3418
  fields: fields,
3352
3419
  texts: {
3353
- loadButton: texts.loadButton,
3354
- saveButton: texts.saveButton,
3355
- editButton: texts.editButton,
3356
- cancelButton: texts.cancelButton
3420
+ loadButton: fmt(texts.loadButton),
3421
+ saveButton: fmt(texts.saveButton),
3422
+ editButton: fmt(texts.editButton),
3423
+ cancelButton: fmt(texts.cancelButton)
3357
3424
  },
3358
3425
  presetChanged: presetChanged,
3359
3426
  enableEdit: enableEdit
@@ -3364,7 +3431,7 @@ const Preset = _ref => {
3364
3431
  className: "h-full text-gray-400",
3365
3432
  children: /*#__PURE__*/jsx(Empty, {
3366
3433
  image: Empty.PRESENTED_IMAGE_SIMPLE,
3367
- description: texts.emptyText
3434
+ description: fmt(texts.emptyText)
3368
3435
  })
3369
3436
  })
3370
3437
  })]
@@ -4619,43 +4686,64 @@ const SystemOperations = _ref => {
4619
4686
  onRestartSuccess,
4620
4687
  beforeAction,
4621
4688
  // 在执行关机/重启前调用
4622
- powerOffLabel = "Power Off",
4623
- restartLabel = "Restart",
4689
+ powerOffLabel = "system.poweroff",
4690
+ restartLabel = "system.restart",
4624
4691
  iconClassName = "seeder-iconfont seeder-icon-guanji1 text-xl text-neutral-400",
4625
- confirmMessage = "Are you sure you want to {action} the system? This action cannot be undone.",
4626
- confirmTitle = "Confirmation Required",
4627
- cancelText = "Cancel",
4628
- okText = "Confirm"
4692
+ confirmMessage = "system.confirm.message",
4693
+ confirmTitle = "system.confirm.title",
4694
+ cancelText = "system.button.cancel",
4695
+ okText = "system.button.confirm"
4629
4696
  } = _ref;
4697
+ const intl = useIntl();
4630
4698
  const {
4631
4699
  modal
4632
4700
  } = App.useApp();
4633
4701
  const menuItems = [{
4634
4702
  key: "poweroff",
4635
- label: powerOffLabel
4636
- },
4637
- // {
4638
- // key: "reboot",
4639
- // label: rebootLabel, // 硬重启 物理重启
4640
- // },
4641
- {
4703
+ label: typeof powerOffLabel === 'string' && powerOffLabel.includes('.') ? intl.formatMessage({
4704
+ id: powerOffLabel
4705
+ }) : powerOffLabel
4706
+ }, {
4642
4707
  key: "restart",
4643
- label: restartLabel // 软重启 服务重启
4708
+ label: typeof restartLabel === 'string' && restartLabel.includes('.') ? intl.formatMessage({
4709
+ id: restartLabel
4710
+ }) : restartLabel
4644
4711
  }];
4645
4712
  const doAction = action => {
4646
4713
  try {
4647
- // 根据action决定显示的确认信息
4714
+ // 根据 action 决定显示的确认信息
4648
4715
  const actionLabels = {
4649
- poweroff: "power off",
4650
- restart: "restart"
4716
+ poweroff: intl.formatMessage({
4717
+ id: 'system.action.powerOff'
4718
+ }),
4719
+ restart: intl.formatMessage({
4720
+ id: 'system.action.restart'
4721
+ })
4651
4722
  };
4652
4723
  const actionText = actionLabels[action] || action;
4724
+
4725
+ // 处理标题和消息的国际化
4726
+ const titleText = typeof confirmTitle === 'string' && confirmTitle.includes('.') ? intl.formatMessage({
4727
+ id: confirmTitle
4728
+ }) : confirmTitle;
4729
+
4730
+ // 如果是国际化 key,使用 intl.formatMessage 处理参数
4731
+ // 如果是普通文本,使用 replace 替换占位符
4732
+ const messageText = typeof confirmMessage === 'string' && confirmMessage.includes('.') ? intl.formatMessage({
4733
+ id: confirmMessage
4734
+ }, {
4735
+ action: actionText
4736
+ }) : typeof confirmMessage === 'string' ? confirmMessage.replace('{action}', actionText) : confirmMessage;
4653
4737
  modal.confirm({
4654
4738
  icon: /*#__PURE__*/jsx(ExclamationCircleFilled, {}),
4655
- title: confirmTitle,
4656
- content: confirmMessage.replace('{action}', actionText),
4657
- cancelText,
4658
- okText,
4739
+ title: titleText,
4740
+ content: messageText,
4741
+ cancelText: typeof cancelText === 'string' && cancelText.includes('.') ? intl.formatMessage({
4742
+ id: cancelText
4743
+ }) : cancelText,
4744
+ okText: typeof okText === 'string' && okText.includes('.') ? intl.formatMessage({
4745
+ id: okText
4746
+ }) : okText,
4659
4747
  onOk: async () => {
4660
4748
  // 先执行 beforeAction(用于 enterMaintenanceMode)
4661
4749
  if (typeof beforeAction === 'function') {
@@ -4841,9 +4929,10 @@ const CommonHeader = _ref => {
4841
4929
  var CommonHeader$1 = CommonHeader;
4842
4930
 
4843
4931
  const LSMLabelField = props => {
4932
+ const intl = useIntl();
4844
4933
  const [lsmList, setLsmList] = useState([]);
4845
4934
  const {
4846
- label = "Label",
4935
+ label = "lsm.label",
4847
4936
  onLsmSelect,
4848
4937
  fetchLsmData,
4849
4938
  formItemProps = {},
@@ -4867,7 +4956,9 @@ const LSMLabelField = props => {
4867
4956
  loadLsmData();
4868
4957
  }, [fetchLsmData]);
4869
4958
  return /*#__PURE__*/jsx(Form.Item, _objectSpread2$1(_objectSpread2$1({
4870
- label: label
4959
+ label: typeof label === 'string' && label.includes('.') ? intl.formatMessage({
4960
+ id: label
4961
+ }) : label
4871
4962
  }, formItemProps), {}, {
4872
4963
  children: /*#__PURE__*/jsx(Select, _objectSpread2$1(_objectSpread2$1(_objectSpread2$1({}, field), selectProps), {}, {
4873
4964
  options: lsmList,
@@ -4879,7 +4970,9 @@ const LSMLabelField = props => {
4879
4970
  field.onChange(value);
4880
4971
  onLsmSelect === null || onLsmSelect === void 0 || onLsmSelect(value === undefined ? undefined : option);
4881
4972
  },
4882
- placeholder: selectProps.placeholder || 'Please select label'
4973
+ placeholder: selectProps.placeholder || intl.formatMessage({
4974
+ id: 'lsm.placeholder.select'
4975
+ })
4883
4976
  }))
4884
4977
  }));
4885
4978
  };
@@ -13354,6 +13447,7 @@ const NmosModal = _ref => {
13354
13447
  modalProps = {},
13355
13448
  formProps = {}
13356
13449
  } = _ref;
13450
+ const intl = useIntl();
13357
13451
  const [nmosSettings, setNmosSettings] = useState(null);
13358
13452
  const [loading, setLoading] = useState(false);
13359
13453
  const [form] = Form.useForm();
@@ -13394,7 +13488,9 @@ const NmosModal = _ref => {
13394
13488
  try {
13395
13489
  const response = await updateNmosSettings(_objectSpread2$1(_objectSpread2$1({}, nmosSettings), values));
13396
13490
  if (response) {
13397
- message.success('Success');
13491
+ message.success(intl.formatMessage({
13492
+ id: 'nmos.saveSuccess'
13493
+ }));
13398
13494
  setTimeout(() => {
13399
13495
  onClose();
13400
13496
  }, 1500);
@@ -13406,9 +13502,17 @@ const NmosModal = _ref => {
13406
13502
  }
13407
13503
  };
13408
13504
  return /*#__PURE__*/jsx(StyledModal$1, _objectSpread2$1(_objectSpread2$1({
13409
- title: "NMOS",
13505
+ title: intl.formatMessage({
13506
+ id: 'nmos.title'
13507
+ }),
13410
13508
  width: 650,
13411
13509
  open: open,
13510
+ okText: intl.formatMessage({
13511
+ id: 'button.apply'
13512
+ }),
13513
+ cancelText: intl.formatMessage({
13514
+ id: 'button.close'
13515
+ }),
13412
13516
  onOk: handleSubmit,
13413
13517
  onCancel: onClose,
13414
13518
  confirmLoading: loading,
@@ -13427,7 +13531,9 @@ const NmosModal = _ref => {
13427
13531
  disabled: loading
13428
13532
  }, formProps), {}, {
13429
13533
  children: [/*#__PURE__*/jsx(Form.Item, {
13430
- label: "Host Addresses",
13534
+ label: intl.formatMessage({
13535
+ id: 'nmos.hostAddress'
13536
+ }),
13431
13537
  name: "host_addresses",
13432
13538
  children: /*#__PURE__*/jsx(Select, {
13433
13539
  mode: "multiple",
@@ -13436,19 +13542,27 @@ const NmosModal = _ref => {
13436
13542
  label: "display_name",
13437
13543
  value: "ip_address"
13438
13544
  },
13439
- placeholder: "Select host address",
13545
+ placeholder: intl.formatMessage({
13546
+ id: 'nmos.placeholder.selectHostAddress'
13547
+ }),
13440
13548
  allowClear: true
13441
13549
  })
13442
13550
  }), /*#__PURE__*/jsx(Form.Item, {
13443
- label: "Domain",
13551
+ label: intl.formatMessage({
13552
+ id: 'nmos.domain'
13553
+ }),
13444
13554
  name: "domain",
13445
13555
  children: /*#__PURE__*/jsx(Input, {})
13446
13556
  }), /*#__PURE__*/jsx(Form.Item, {
13447
- label: "Registry Address",
13557
+ label: intl.formatMessage({
13558
+ id: 'nmos.registryAddress'
13559
+ }),
13448
13560
  name: "registry_address",
13449
13561
  children: /*#__PURE__*/jsx(Input, {})
13450
13562
  }), /*#__PURE__*/jsx(Form.Item, {
13451
- label: "Registry Port",
13563
+ label: intl.formatMessage({
13564
+ id: 'nmos.registrationPort'
13565
+ }),
13452
13566
  name: "registration_port",
13453
13567
  children: /*#__PURE__*/jsx(InputNumber, _objectSpread2$1(_objectSpread2$1({}, numberProps), {}, {
13454
13568
  min: 0,
@@ -13458,7 +13572,9 @@ const NmosModal = _ref => {
13458
13572
  }
13459
13573
  }))
13460
13574
  }), /*#__PURE__*/jsx(Form.Item, {
13461
- label: "Registry Version",
13575
+ label: intl.formatMessage({
13576
+ id: 'nmos.registryVersion'
13577
+ }),
13462
13578
  name: "registry_version",
13463
13579
  children: /*#__PURE__*/jsx(Select, {
13464
13580
  options: [{
@@ -13474,10 +13590,14 @@ const NmosModal = _ref => {
13474
13590
  label: "v1.3",
13475
13591
  value: "v1.3"
13476
13592
  }],
13477
- placeholder: "Select version"
13593
+ placeholder: intl.formatMessage({
13594
+ id: 'nmos.placeholder.selectVersion'
13595
+ })
13478
13596
  })
13479
13597
  }), /*#__PURE__*/jsx(Form.Item, {
13480
- label: "Logging Level",
13598
+ label: intl.formatMessage({
13599
+ id: 'nmos.loggingLevel'
13600
+ }),
13481
13601
  name: "logging_level",
13482
13602
  children: /*#__PURE__*/jsx(InputNumber, _objectSpread2$1(_objectSpread2$1({}, numberProps), {}, {
13483
13603
  min: -40,
@@ -13585,11 +13705,12 @@ const MaintenancePage = _ref => {
13585
13705
  redirectPath = '/',
13586
13706
  onRedirect,
13587
13707
  maxRetries = 90,
13588
- // 最多重试90次(约180秒)
13708
+ // 最多重试 90 次(约 180 秒)
13589
13709
  checkInterval = 2000,
13590
- // 每2秒重试
13710
+ // 每 2 秒重试
13591
13711
  countdownSeconds = 30 // 倒计时初始值,单位秒
13592
13712
  } = _ref;
13713
+ const intl = useIntl();
13593
13714
  const [countdown, setCountdown] = useState(countdownSeconds);
13594
13715
  const {
13595
13716
  error,
@@ -13628,7 +13749,11 @@ const MaintenancePage = _ref => {
13628
13749
  cleanup();
13629
13750
  };
13630
13751
  }, [isRestart, healthCheckUrl, startPolling, cleanup]);
13631
- const title = isRestart ? "System is restarting..." : "System is powered off";
13752
+ const title = isRestart ? intl.formatMessage({
13753
+ id: 'maintenance.restarting'
13754
+ }) : intl.formatMessage({
13755
+ id: 'maintenance.poweredOff'
13756
+ });
13632
13757
  const subTitle = isRestart ? /*#__PURE__*/jsxs(Space, {
13633
13758
  direction: "vertical",
13634
13759
  size: 8,
@@ -13636,13 +13761,21 @@ const MaintenancePage = _ref => {
13636
13761
  alignItems: 'center'
13637
13762
  },
13638
13763
  children: [/*#__PURE__*/jsx(Typography.Text, {
13639
- children: "Please wait while the system is starting up..."
13640
- }), countdown > 0 && /*#__PURE__*/jsxs(Typography.Text, {
13764
+ children: intl.formatMessage({
13765
+ id: 'maintenance.waiting'
13766
+ })
13767
+ }), countdown > 0 && /*#__PURE__*/jsx(Typography.Text, {
13641
13768
  type: "secondary",
13642
- children: ["Redirecting automatically in ", countdown, " second", countdown !== 1 ? 's' : '']
13769
+ children: intl.formatMessage({
13770
+ id: 'maintenance.redirecting.countdown'
13771
+ }, {
13772
+ countdown
13773
+ })
13643
13774
  }), countdown <= 0 && !error && /*#__PURE__*/jsx(Typography.Text, {
13644
13775
  type: "secondary",
13645
- children: "Still starting up... This may take a moment."
13776
+ children: intl.formatMessage({
13777
+ id: 'maintenance.waiting.long'
13778
+ })
13646
13779
  }), error && /*#__PURE__*/jsxs(Fragment, {
13647
13780
  children: [/*#__PURE__*/jsx(Alert, {
13648
13781
  type: "error",
@@ -13654,11 +13787,15 @@ const MaintenancePage = _ref => {
13654
13787
  }), /*#__PURE__*/jsx(Button, {
13655
13788
  type: "link",
13656
13789
  onClick: manualRetry,
13657
- children: "Retry connection"
13790
+ children: intl.formatMessage({
13791
+ id: 'maintenance.retry'
13792
+ })
13658
13793
  })]
13659
13794
  })]
13660
13795
  }) : /*#__PURE__*/jsx(Typography.Text, {
13661
- children: "The system is currently offline. Please contact your administrator to power it on."
13796
+ children: intl.formatMessage({
13797
+ id: 'maintenance.offline.description'
13798
+ })
13662
13799
  });
13663
13800
  return /*#__PURE__*/jsx("div", {
13664
13801
  className: "maintenance-page",
@@ -14022,10 +14159,17 @@ const BoundedInput = _ref => {
14022
14159
  min = 0,
14023
14160
  max = 100,
14024
14161
  autoCorrect = false,
14025
- placeholder = 'Enter an integer',
14162
+ placeholder = 'input.placeholder.enterInteger',
14026
14163
  disabled = false
14027
14164
  } = _ref,
14028
14165
  props = _objectWithoutProperties$1(_ref, _excluded);
14166
+ const intl = useIntl();
14167
+
14168
+ // 处理国际化文本
14169
+ const placeholderText = typeof placeholder === 'string' && placeholder.includes('.') ? intl.formatMessage({
14170
+ id: placeholder
14171
+ }) : placeholder;
14172
+
14029
14173
  // 1. 处理输入变更:只管记录,不修正,不打断
14030
14174
  const handleChange = val => {
14031
14175
  if (val === null || val === undefined) {
@@ -14061,7 +14205,7 @@ const BoundedInput = _ref => {
14061
14205
  value: value,
14062
14206
  onChange: handleChange,
14063
14207
  onBlur: handleBlur,
14064
- placeholder: placeholder
14208
+ placeholder: placeholderText
14065
14209
  // 只有开启自动修正时,才把 min/max 传给组件
14066
14210
  ,
14067
14211
  min: autoCorrect ? min : undefined,
@@ -14087,7 +14231,7 @@ const BoundedInput = _ref => {
14087
14231
  const PortInput = props => /*#__PURE__*/jsx(BoundedInput, _objectSpread2$1({
14088
14232
  min: 0,
14089
14233
  max: 65535,
14090
- placeholder: "Enter port (0-65535)"
14234
+ placeholder: "input.placeholder.enterPort"
14091
14235
  }, props));
14092
14236
 
14093
14237
  /**
@@ -14096,7 +14240,7 @@ const PortInput = props => /*#__PURE__*/jsx(BoundedInput, _objectSpread2$1({
14096
14240
  const PayloadInput = props => /*#__PURE__*/jsx(BoundedInput, _objectSpread2$1({
14097
14241
  min: 96,
14098
14242
  max: 127,
14099
- placeholder: "Enter payload (96-127)"
14243
+ placeholder: "input.placeholder.enterPayload"
14100
14244
  }, props));
14101
14245
 
14102
14246
  export { AuthorizationModal$1 as AuthorizationModal, CommonHeader$1 as CommonHeader, DraggableNumberInput, LSMLabelField$1 as LSMLabelField, MaintenancePage, NetworkSettingsModal$1 as NetworkSettingsModal, NmosModal$1 as NmosModal, PayloadInput, PortInput, PresetModal, PtpModal$1 as PtpModal, StyledModal$3 as StyledModal, SystemOperations$1 as SystemOperations, UpgradeManager$1 as UpgradeManager, addMessages, debugI18n, initI18n, enUS as localesEnUS, zhCN as localesZhCN, setLocale, useAuth, useHardwareUsage$1 as useHardwareUsage, useIntl, usePageReload$1 as usePageReload, useSystemOperations$1 as useSystemOperations, useUpgrade$1 as useUpgrade, useWebSocketWithFeatures$1 as useWebSocketWithFeatures };