564 lines
54 KiB
JavaScript
564 lines
54 KiB
JavaScript
// Generaate missing locale keys (best-effort) for zh + en.
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
const root = 'src';
|
||
const exts = ['.tsx', '.ts', '.jsx', '.js'];
|
||
const excludeDirs = ['locales', 'node_modules', 'i18n'];
|
||
|
||
function walk(dir) {
|
||
const out = [];
|
||
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
||
const full = path.join(dir, e.name);
|
||
if (e.isDirectory()) { if (!excludeDirs.includes(e.name)) out.push(...walk(full)); }
|
||
else if (exts.includes(path.extname(e.name))) out.push(full);
|
||
}
|
||
return out;
|
||
}
|
||
|
||
function load(p) {
|
||
let s = fs.readFileSync(p, 'utf8');
|
||
s = s.replace(/const\s+\w+\s*=\s*\{/, 'var obj = {');
|
||
s = s.replace(/export\s+default\s+\w+;?/, '');
|
||
s = s.replace(/\bconst\b/g, 'var');
|
||
return new Function(s + '\nreturn obj;')();
|
||
}
|
||
function flat(o, p, r) {
|
||
p = p || ''; r = r || {};
|
||
for (const k of Object.keys(o)) {
|
||
const key = p ? p + '.' + k : k;
|
||
if (o[k] && typeof o[k] === 'object' && !Array.isArray(o[k])) flat(o[k], key, r);
|
||
else r[key] = o[k];
|
||
}
|
||
return r;
|
||
}
|
||
function unflat() { return {}; }
|
||
|
||
const zhObj = load('src/locales/zh/index.ts');
|
||
const enObj = load('src/locales/en/index.ts');
|
||
const zhMap = flat(zhObj);
|
||
const enMap = flat(enObj);
|
||
|
||
// ---- token dictionaries ----
|
||
// camelCase token -> Chinese (for inferring zh of missing keys)
|
||
const tokZh = {
|
||
tl: '时间线', timeline: '时间线', mock: '模拟', device: '设备', devices: '设备',
|
||
sensor: '传感器', camera: '摄像头', station: '基站', battery: '电量', temp: '温度', temperature: '温度',
|
||
uav: '无人机', drone: '无人机', mower: '割草机', robot: '机器人', video: '视频',
|
||
status: '状态', task: '任务', tasks: '任务', complete: '完成', completed: '已完成', completing: '完成中',
|
||
start: '开始', end: '结束', startcleaning: '开始清洗', startinspection: '开始巡检', startmowing: '开始除草',
|
||
standby: '待机', ready: '就绪', return: '返航', supply: '补给', finish: '完成', inspection: '巡检', inspect: '巡检',
|
||
mow: '除草', maintenance: '维护', repair: '维修', clean: '清洗', cleaning: '清洗',
|
||
msg: '消息', message: '消息', no: '编号', alarm: '告警', rule: '规则', rules: '规则',
|
||
param: '参数', params: '参数', left: '左', right: '右', forward: '前', backward: '后', gain: '增益',
|
||
speed: '速度', chip: '芯片', uid: 'UID', sign: '标识', route: '路线', routes: '路线', path: '路径', point: '点', points: '点',
|
||
indoor: '室内', outdoor: '室外', wide: '广角', zoom: '变焦', lens: '镜头', ir: '红外', switch: '切换',
|
||
fail: '失败', failed: '失败', success: '成功', fetch: '获取', save: '保存', create: '创建', created: '已创建',
|
||
generate: '生成', export: '导出', import: '导入', download: '下载', upload: '上传', search: '搜索', reset: '重置',
|
||
confirm: '确认', cancel: '取消', view: '查看', select: '选择', selected: '已选', name: '名称', type: '类型',
|
||
time: '时间', date: '日期', total: '共', count: '数量', today: '今日', yesterday: '昨日',
|
||
week: '周', month: '月', day: '日', year: '年', online: '在线', offline: '离线',
|
||
error: '错误', errors: '错误', warning: '警告', info: '提示', critical: '严重', important: '重要', general: '一般',
|
||
pending: '待处理', closed: '已关闭', handled: '已处理', restored: '已恢复', ignored: '已忽略', falsealarm: '误报',
|
||
level: '级别', source: '来源', result: '结果', trend: '趋势', distribution: '分布', statistics: '统计',
|
||
subscription: '订阅', history: '历史', realtime: '实时', overview: '概览', analysis: '分析', diagnosis: '诊断',
|
||
defect: '缺陷', thermal: '热成像', component: '组件', string: '组串', inverter: '逆变器', efficiency: '效率',
|
||
risk: '风险', confidence: '置信度', location: '位置', suggestion: '建议', plan: '计划', execute: '执行',
|
||
mowing: '除草', inspect: '巡检', work: '工作', order: '工单', user: '用户', role: '角色', roles: '角色',
|
||
permission: '权限', menu: '菜单', organization: '组织', notice: '通知', data: '数据', safety: '安全',
|
||
access: '接入', protocol: '协议', longitude: '经度', latitude: '纬度', timezone: '时区', capacity: '容量',
|
||
address: '地址', leader: '负责人', contact: '联系', icon: '图标', sort: '排序', parent: '上级',
|
||
directory: '目录', button: '按钮', theme: '主题', light: '浅色', dark: '深色', language: '语言', version: '版本',
|
||
serial: '序列', verify: '验证', bind: '绑定', code: '码', list: '列表', refresh: '刷新', delete: '删除',
|
||
edit: '编辑', add: '新增', update: '更新', enable: '启用', disable: '停用', normal: '正常', abnormal: '异常',
|
||
loading: '加载中', generating: '生成中', processing: '处理中', exported: '已导出', uploadfile: '上传文件',
|
||
uploadimage: '上传图片', startanalysis: '开始分析', analysisresult: '分析结果', detected: '检测到',
|
||
noresult: '无结果', none: '无', unknown: '未知', invalid: '无效', gps: 'GPS', dgps: 'DGPS', rtk: 'RTK',
|
||
fixed: '固定', float: '浮点', config: '配置', configured: '已配置', connection: '连接', connect: '连接',
|
||
request: '请求', permissionreq: '权限请求', recover: '恢复', resume: '恢复', pause: '暂停', stopped: '停用',
|
||
working: '作业中', workingrobots: '作业中机器人', stat: '统计', alert: '告警', alerts: '告警',
|
||
deviceenvironment: '设备环境', currenttemp: '当前温度', humidity: '环境湿度', positionaccuracy: '定位精度',
|
||
networklatency: '网络延迟', waterrisk: '积水风险', preset: '预设', searchplaceholder: '搜索', unnamed: '未命名',
|
||
deleteroute: '删除航线', executeroute: '执行航线', taskboard: '任务看板', pendingtask: '待执行任务',
|
||
executing: '执行中', executingellipsis: '执行中', pausedtask: '已暂停任务', executeroutetask: '执行路线任务',
|
||
routeinfo: '路线信息', routename: '路线名称', selectexecdevice: '选择执行设备', panorama: '全景',
|
||
wdsun: '日', wdmon: '一', wtue: '二', wdwend: '三', wdthu: '四', wdfri: '五', wdsat: '六',
|
||
deviceserial: '设备编号', fillrequired: '请填写', selectexectime: '选择执行时间', taskcreated: '任务创建成功',
|
||
createfailed: '创建失败', createtaskerror: '创建任务异常', newtask: '新建任务', inputtaskname: '请输入任务名称',
|
||
executeroutelabel: '执行路线', selectroute: '选择路线', repeatplan: '重复计划', execdate: '执行日期',
|
||
selectexecdate: '选择执行日期', exectime: '执行时间', savetask: '保存任务', devicecontrol: '设备控制',
|
||
realtimevideo: '实时视频', takeoff: '起飞', land: '降落', returnhome: '返航', emergencystop: '紧急停止',
|
||
rotateleft: '左旋', rotateright: '右旋', gimbalpitch: '云台俯仰', gimbályaw: '云台偏航', zoomin: '放大', zoomout: '缩小',
|
||
wayline: '航线', waylinetask: '航线任务', robottask: '机器人任务', devicename: '设备名称', devicetype: '设备类型',
|
||
devicemodel: '设备型号', onlinestatus: '在线状态', lastheartbeat: '最后心跳', batterylevel: '电量',
|
||
signalstrength: '信号强度', control: '控制', uploadwayline: '上传航线', downloadwayline: '下载航线',
|
||
executetask: '执行任务', taskname: '任务名称', taskstatus: '任务状态', flighttime: '飞行时间', altitude: '高度',
|
||
distance: '距离', starttime: '开始时间', endtime: '结束时间', drone: '无人机', camera2: '摄像头',
|
||
creator: '创建者', executionplan: '执行计划', executioncycle: '执行周期', statusnew: '新建',
|
||
statuspaused: '暂停中', statusfinished: '执行成功', statusfailed: '执行失败', confirmdeletetask: '确定要删除该任务吗',
|
||
confirmcanceltask: '确定要取消该任务吗', confirmpausetask: '确定要暂停该任务吗', clearrealtime: '清空实时',
|
||
cleartrack: '清空实时轨迹', clearplanroute: '清空规划航线', controlmode: '控制模式', localmode: '本地',
|
||
remotemode: '远程', heading: '航向', initialized: '已初始化', uninitialized: '未初始化', taskpool: '任务池',
|
||
taskexecutionplan: '任务执行计划', taskhistory: '历史任务', createtask: '创建任务', startdate: '开始日期',
|
||
enddate: '结束日期', allrobots: '全部机器人', operationsuggestion: '作业编排建议', good: '良好',
|
||
devicelocation: '设备定位', devicevideo: '设备视频', robotpanorama: '机器人全景',
|
||
dayplan: '按天计划', weekplan: '按周计划', monthplan: '按月计划', daysuffix: '日', unknownplan: '未知计划',
|
||
mon: '周一', tue: '周二', wed: '周三', thu: '周四', fri: '周五', sat: '周六', sun: '周日',
|
||
vs: '较', unit: '单位', unitplan: '条', unitrobot: '台', unittimes: '次', completionrate: '完成率',
|
||
alertscount: '告警数量', costsaving: '节省成本', monthlyaccumulated: '本月累计', daily: '日', target: '目标',
|
||
installedcapacity: '装机容量', generationtrend: '发电趋势', irradiance: '辐照度', actual: '实际', predict: '预测',
|
||
invertterefficiency: '逆变器效率', maintenanceprogress: '运维进度', stationoverview: '电站概览',
|
||
recentinspection: '近期巡检', aianalysissummary: 'AI分析摘要', realtimealerts: '实时告警',
|
||
deviceonlinestatus: '设备在线状态', weatherinfo: '天气信息', cleaningsuggestion: '清洗建议',
|
||
cleanordergenerated: '清洗工单生成成功', pleaseelectstation: '请选择电站', generatecleanorder: '生成清洗工单',
|
||
kwh: 'kWh', kwp: 'kWp', undermaintenance: '维护中', abnormal2: '异常', normal2: '正常',
|
||
moduleinfo: '模块信息', heat: '热', hotspot: '热斑', component0: '组件', datapoint: '数据点', datapoints: '数据点',
|
||
exportfilename: '导出文件', processing2: '处理中', loadfailed: '加载失败', loaddetailfailed: '加载详情失败',
|
||
requesterror: '请求错误', handlesuccess: '处理成功', handlefail: '处理失败', alarmno: '告警编号',
|
||
devicedatas: '设备数据', working2: '作业中', mockdevice: '模拟设备', mocksensor: '模拟传感器',
|
||
mocktemp: '模拟温度', mocktempexceed: '模拟温度超限', mockbattery: '模拟电量', mockbatterylow: '模拟电量低',
|
||
mockvideosignal: '模拟视频信号', mockvideosignallost: '模拟视频信号丢失', mockrule: '模拟规则',
|
||
mocksub: '模拟订阅', mocksubops: '模拟运维', mocksubadmin: '模拟管理员', mocksubdevice: '模拟设备',
|
||
sms: '短信', email: '邮件', apppush: 'App推送', subscriptionname: '订阅名称', notifychannel: '通知渠道',
|
||
devicesensor: '设备传感器', devicebattery: '设备电量', alarmlevel: '告警级别', alarmtype: '告警类型',
|
||
alarmsource: '告警来源', alarmtime: '告警时间', handlestatus: '处理状态', handleresult: '处理结果',
|
||
handletime: '处理时间', handler: '处理人', handleremark: '处理备注', handle: '处理', closealert: '关闭告警',
|
||
confirmalert: '确认告警', exportalert: '导出告警', critical2: '严重', important2: '重要', general2: '一般',
|
||
info2: '提示', reopen: '重新打开', sevenDayTrend: '近7天趋势', sevenDayTrend2: '近7天趋势',
|
||
criticalAlert: '严重告警', importantAlert: '重要告警', generalAlert: '一般告警', infoAlert: '提示告警',
|
||
daySuffix2: '日', daySuffix3: '日', exported2: '已导出', loadDetailFailed2: '加载详情失败',
|
||
requestError2: '请求错误', handleSuccess2: '处理成功', handleFail2: '处理失败', alarmNo2: '告警编号',
|
||
locationUnknown: '未知位置', none2: '无', good2: '良好',
|
||
taskCompletedMsg: '任务完成消息', confirmDeleteTitle: '确认删除', confirmDeleteContent: '确认删除内容',
|
||
confirmDeleteOk: '确认删除', routeDeletedSuccess: '路线删除成功', deleteFailRetry: '删除失败重试',
|
||
deleteFailNetwork: '删除失败网络', taskListRefreshFail: '任务列表刷新失败', routeNoPathPoints: '路线无路径点',
|
||
waylineFallback: '航线兜底', waylineListFetchFail: '航线列表获取失败', fillRequiredFields: '请填写必填项',
|
||
createTaskSuccess: '创建任务成功', createTaskFail: '创建任务失败', createTaskException: '创建任务异常',
|
||
trendYesterday: '较昨日', trendFlat: '持平', taskListFetchFail: '任务列表获取失败',
|
||
fetchParamFail: '参数获取失败', paramSaveSuccess: '参数保存成功', paramSaveFail: '参数保存失败',
|
||
paramSaveException: '参数保存异常', paramLeftForwardGain: '左前增益', paramLeftBackwardGain: '左后增益',
|
||
paramRightForwardGain: '右前增益', paramRightBackwardGain: '右后增益', paramRunSpeed: '运行速度',
|
||
paramChipUidSign: '芯片UID标识', timelineStatusStart: '开始', timelineStatusReady: '就绪',
|
||
timelineStatusReturn: '返航', timelineStatusComplete: '完成', tlStartCleaning: '开始清洗',
|
||
tlStartInspection: '开始巡检', tlStartMowing: '开始除草', tlStandbyReady: '待机就绪',
|
||
tlReturnSupply: '返航补给', tlFinishInspection: '完成巡检', tlFinishMowing: '完成除草',
|
||
stationCameraNotFound: '基站摄像头未找到', switchStationCameraFail: '切换基站摄像头失败',
|
||
switchDroneLensFail: '切换无人机镜头失败', wideLens: '广角镜头', zoomLens: '变焦镜头', irLens: '红外镜头',
|
||
rainNo: '无雨', pointMarked: '已标记点', minThreePoints: '至少三个点', pathPlanDone: '路径规划完成',
|
||
pathPlanFailRetry: '路径规划失败重试', completePathFirst: '请先完成路径', inputPlotName: '输入区域名称',
|
||
connectionFailed: '连接失败', permissionRequestTitle: '权限请求', requestControlPermission: '请求控制权限',
|
||
selectNoDrone: '未选择无人机', commandIssued: '指令已下发', commandFailed: '指令下发失败',
|
||
videoConfigured: '视频已配置', noVideo: '无视频', working3: '作业中', online2: '在线', offline2: '离线',
|
||
// generic fallbacks
|
||
page: '页面', setting: '设置', settings: '设置', manage: '管理', management: '管理', center: '中心',
|
||
report2: '报表', log2: '日志', profile: '个人中心', login: '登录', logout: '退出', station2: '电站',
|
||
monitor2: '监控', ai: 'AI', optimization: '优化', task2: '任务', order2: '工单', alert2: '告警',
|
||
device2: '设备', system2: '系统', user2: '用户', role2: '角色',
|
||
};
|
||
|
||
// Comprehensive English-token -> Chinese lexicon (covers tokens from missing keys)
|
||
const lex = {
|
||
a01: '', ab: '', abnormal: '异常', account: '账号', accumulated: '累计', action: '操作', activated: '已激活', active: '启用',
|
||
add: '新增', added: '已添加', additional: '额外', admin: '管理员', advice: '建议', after: '之后', ai: 'AI', airport: '机场', airspace: '空域',
|
||
alarm: '告警', alert: '告警', alerts: '告警', algo: '算法', algorithm: '算法', alias: '别名', all: '全部', altitude: '高度', ambient: '环境',
|
||
analysis: '分析', and: '与', angle: '角度', api: 'API', app: '应用', approval: '审批', area: '区域', arm: '布防', array: '阵列', assign: '分配',
|
||
assigned: '已分配', async: '异步', auto: '自动', average: '平均', avg: '平均', avoid: '避开', back: '返回', backward: '后退', basic: '基础',
|
||
batch: '批量', battery: '电量', belonging: '所属', block: '区块', board: '看板', bound: '边界', bow: '船首', breakpoint: '断点', btn: '按钮',
|
||
by: '按', calendar: '日历', call: '呼叫', camera: '摄像头', cameras: '摄像头', can: '可', cancel: '取消', canceled: '已取消', cancelled: '已取消',
|
||
capacity: '容量', cargo: '货物', cause: '原因', center: '中心', change: '变更', channel: '渠道', channels: '渠道', charge: '充电', chassis: '底盘',
|
||
check: '检查', chip: '芯片', choose: '选择', clean: '清洗', cleaning: '清洗', clear: '清空', cleared: '已清空', click: '点击', climb: '爬升',
|
||
closed: '已关闭', closure: '闭合', code: '码', col: '列', colon: '冒号', comm: '通信', command: '指令', communicating: '通信中', communication: '通信',
|
||
compare: '对比', complete: '完成', completed: '已完成', completion: '完成', component: '组件', condition: '条件', conditions: '条件',
|
||
config: '配置', configured: '已配置', confirm: '确认', connected: '已连接', connection: '连接', contact: '联系', content: '内容', continuous: '连续',
|
||
control: '控制', controlling: '控制中', coordinated: '协同', count: '数量', cover: '覆盖', coverage: '覆盖', create: '创建', created: '已创建',
|
||
critical: '严重', cum: '累计', current: '当前', curve: '曲线', custom: '自定义', cycle: '周期', daily: '每日', data: '数据', date: '日期',
|
||
day: '日', days: '天', debug: '调试', default: '默认', del: '删除', delete: '删除', deleted: '已删除', demo: '演示', desc: '描述', description: '描述',
|
||
detail: '详情', details: '详情', detect: '检测', detected: '已检测', detection: '检测', deviation: '偏差', device: '设备', devices: '设备',
|
||
dgps: 'DGPS', diagnosis: '诊断', diff: '差异', ding: '钉钉', directory: '目录', dispatch: '派单', dispatchable: '可派单', display: '显示',
|
||
distribution: '分布', dock: '停靠', dome: '穹顶', done: '已完成', down: '下降', drag: '拖拽', drive: '驱动', drone: '无人机', drones: '无人机',
|
||
dual: '双', duty: '值班', edit: '编辑', effect: '效果', email: '邮件', emergency: '紧急', empty: '空', enabled: '已启用', end: '结束', ended: '已结束',
|
||
energy: '能量', engineer: '工程师', env: '环境', equipment: '设备', error: '错误', estimated: '预计', event: '事件', events: '事件', exceed: '超限',
|
||
excel: 'Excel', exception: '异常', exec: '执行', execute: '执行', executed: '已执行', executing: '执行中', execution: '执行', expired: '已过期',
|
||
export: '导出', fail: '失败', failed: '失败', failure: '失败', fallback: '兜底', fan: '风扇', fence: '围栏', fetch: '获取', fields: '字段', file: '文件',
|
||
fill: '填写', finish: '完成', fire: '火警', firmware: '固件', first: '先', fixed: '固定', flag: '标志', flat: '持平', flight: '飞行', float: '浮点',
|
||
fly: '飞行', forbidden: '禁止', formats: '格式', forward: '前进', found: '找到', frequency: '频率', fri: '周五', from: '从', front: '前', fuel: '燃料',
|
||
full: '全', gain: '增益', gantt: '甘特', gate: '闸门', ge: '地理', gear: '档位', general: '一般', generate: '生成', generated: '已生成',
|
||
generating: '生成中', generation: '发电', generator: '发电机', geojson: 'GeoJSON', get: '获取', gnss: 'GNSS', good: '良好', gps: 'GPS', gr: '电网',
|
||
grid: '电网', group: '分组', handle: '处理', handled: '已处理', handler: '处理人', hangar: '机库', has: '有', header: '表头', heading: '航向',
|
||
health: '健康', heatmap: '热力图', height: '高度', high: '高', hint: '提示', history: '历史', home: '首页', home2: '首页', horizontal: '水平',
|
||
hotspot: '热斑', hour: '小时', id: 'ID', image: '图片', immediate: '立即', important: '重要', improvement: '提升', in: '内', incident: '事件',
|
||
indoor: '室内', inference: '推理', info: '提示', initialized: '已初始化', input: '输入', inspect: '巡检', inspection: '巡检', integrated: '集成',
|
||
intelligent: '智能', interactive: '交互', intercom: '对讲', interval: '间隔', intrusion: '入侵', invalid: '无效', inverter: '逆变器', ir: '红外',
|
||
irradiance: '辐照度', irreversible: '不可逆', issue: '问题', issued: '已下发', item: '项', items: '项', json: 'JSON', key: '键', keyword: '关键词',
|
||
knife: '刀', label: '标签', landing: '降落', language: '语言', last: '最后', layout: '布局', left: '左', legend: '图例', length: '长度', lens: '镜头',
|
||
level: '级别', levels: '级别', lift: '抬升', limit: '限制', link: '链接', list: '列表', live: '直播', load: '加载', loaded: '已加载', local: '本地',
|
||
location: '位置', log: '日志', login: '登录', logs: '日志', loitering: '徘徊', lost: '丢失', low: '低', machine: '机器', main: '主', manage: '管理',
|
||
management: '管理', manager: '管理员', manual: '手动', map: '地图', mark: '标记', marked: '已标记', marks: '标记', mask: '掩码', members: '成员',
|
||
menu: '菜单', meteorology: '气象', mid: '中间', mileage: '里程', min: '最小', mock: '模拟', mode: '模式', model: '模型', models: '模型',
|
||
modified: '已修改', modify: '修改', mon: '周一', monitor: '监控', month: '月', monthly: '每月', more: '更多', motion: '运动', motor: '电机', mount: '挂载',
|
||
mow: '除草', mowing: '除草', msg: '消息', name: '名称', near: '附近', needed: '需要', network: '网络', new: '新', nickname: '昵称', night: '夜间',
|
||
no: '无', none: '无', normal: '正常', normally: '正常', north: '北', not: '未', notification: '通知', notify: '通知', now: '现在', number: '编号',
|
||
object: '对象', obstacle: '障碍', obtained: '已获取', occur: '发生', of: '的', offline: '离线', ok: '确定', old: '旧', om: '运维', on: '开', one: '一',
|
||
online: '在线', only: '仅', open: '打开', operate: '操作', operation: '操作', ops: '运维', optimal: '最优', optimization: '优化', optimize: '优化',
|
||
optional: '可选', or: '或', orchestration: '编排', order: '工单', orders: '工单', org: '组织', original: '原始', other: '其他', out: '外', outdoor: '室外',
|
||
over: '超过', overlay: '叠加', overview: '概览', page: '页面', panel: '面板', panorama: '全景', param: '参数', params: '参数', password: '密码',
|
||
path: '路径', pause: '暂停', paused: '已暂停', pdf: 'PDF', pending: '待处理', per: '每', percent: '百分比', perimeter: '周长', perm: '权限',
|
||
permission: '权限', person: '人员', personnel: '人员', phase: '相', phone: '电话', picture: '图片', pitch: '俯仰', pixels: '像素', placeholder: '占位',
|
||
plan: '计划', plane: '飞机', planned: '已计划', planning: '规划', platform: '平台', play: '播放', please: '请', plot: '区域', point: '点', points: '点',
|
||
polarity: '极性', port: '端口', position: '位置', positioning: '定位', power: '功率', pr: '光伏', precip: '降水', precision: '精度', predicted: '预测',
|
||
preparing: '准备中', preset: '预设', preview: '预览', priority: '优先级', probe: '探测', processing: '处理中', product: '产品', progress: '进度',
|
||
property: '属性', proportion: '比例', protect: '保护', ptz: '云台', pump: '泵', push: '推送', quality: '质量', quantity: '数量', rain: '雨',
|
||
rainfall: '降雨', range: '范围', rate: '率', rated: '额定', ratio: '比例', rbt: '机器人', read: '读取', ready: '就绪', realtime: '实时', rear: '后',
|
||
recent: '近期', recharge: '充电', recheck: '复检', recognition: '识别', recommended: '建议', record: '记录', recording: '录制', records: '记录',
|
||
recurring: '重复', refresh: '刷新', registry: '注册', related: '关联', relay: '中继', remark: '备注', remote: '远程', repeat: '重复', repellent: '驱避',
|
||
replay: '回放', report: '报表', reports: '报表', request: '请求', requesting: '请求中', required: '必填', reset: '重置', restored: '已恢复', result: '结果',
|
||
resume: '恢复', resumed: '已恢复', retry: '重试', return: '返航', returned: '已返航', revenue: '收益', reverse: '反向', right: '右', risk: '风险',
|
||
robot: '机器人', role: '角色', roles: '角色', room: '房间', root: '根', route: '路线', routes: '路线', rt: '实时', rth: '返航', rtk: 'RTK', rule: '规则',
|
||
run: '运行', running: '运行中', safe: '安全', sat: '卫星', satellite: '卫星', satellites: '卫星', save: '保存', saved: '已保存', saving: '节省',
|
||
schedule: '计划', scheduled: '已计划', screen: '屏幕', search: '搜索', seg: '分割', segment: '段', segmentation: '分割', select: '选择', selected: '已选',
|
||
send: '发送', sensor: '传感器', sent: '已发送', server: '服务器', services: '服务', servo: '伺服', setting: '设置', settings: '设置', seven: '七',
|
||
short: '短', show: '显示', sign: '标识', signal: '信号', single: '单', site: '站点', situation: '态势', size: '大小', smart: '智能', smoke: '烟', sms: '短信',
|
||
sn: '序列号', snapshots: '快照', sort: '排序', source: '来源', south: '南', span: '跨度', speed: '速度', standby: '待机', start: '开始', started: '已开始',
|
||
station: '电站', statistics: '统计', status: '状态', statuses: '状态', stop: '停止', stopped: '已停止', storage: '存储', store: '存储', stream: '流',
|
||
streams: '流', string: '组串', sub: '订阅', submit: '提交', subscribers: '订阅者', subscription: '订阅', subtitle: '字幕', success: '成功', suffix: '后缀',
|
||
suggest: '建议', suggested: '建议', suggestion: '建议', suitability: '适宜性', suitable: '适宜', summary: '摘要', sun: '太阳', super: '超级',
|
||
supervisor: '主管', supply: '补给', supported: '支持', supports: '支持', suspect: '疑似', suspend: '暂停', suspended: '已暂停', swap: '切换',
|
||
switch: '切换', symbol: '符号', sync: '同步', system: '系统', tai: '台', talk: '通话', task: '任务', tasks: '任务', temp: '温度', temperature: '温度',
|
||
template: '模板', terminated: '已终止', theoretical: '理论', thermal: '热成像', three: '三', threshold: '阈值', throttle: '油门', thu: '周四',
|
||
tiao: '条', time: '时间', timed: '定时', timeline: '时间线', timeout: '超时', timestamp: '时间戳', title: '标题', tl: '时间线', to: '到', today: '今日',
|
||
top: '顶部', topology: '拓扑', total: '总', tracking: '跟踪', trend: '趋势', trigger: '触发', triggered: '已触发', tue: '周二', turn: '转向', two: '二',
|
||
type: '类型', types: '类型', tyre: '轮胎', uav: '无人机', uid: 'UID', unit: '单位', unknown: '未知', up: '上升', update: '更新', upgrading: '升级中',
|
||
upload: '上传', usage: '用量', use4g: '4G', user: '用户', users: '用户', uuid: 'UUID', value: '值', version: '版本', vertical: '垂直', video: '视频',
|
||
view: '查看', visual: '可视', voltage: '电压', vs: '较', wait: '等待', waiting: '等待中', walk: '行走', wall: '墙', wash: '清洗', way: '路径',
|
||
wayline: '航线', waypoint: '航点', waypoints: '航点', weather: '天气', web: '网页', wed: '周三', weed: '杂草', week: '周', weekday: '工作日',
|
||
weekly: '每周', west: '西', wheel: '轮', which: '哪个', wide: '广角', width: '宽度', wifi: 'WiFi', wind: '风', window: '窗口', wing: '机翼', with: '带',
|
||
work: '工作', working: '作业中', workspace: '工作区', yes: '是', yesterday: '昨日', zero: '零', zone: '区域', zoom: '缩放',
|
||
};
|
||
const NOUNS_WITH_NO = new Set(['alarm', 'device', 'order', 'task', 'route', 'serial', 'station', 'work', 'user', 'role', 'id', 'sn', 'uav', 'drone', 'robot']);
|
||
|
||
// Chinese phrase/char -> English (for translating hardcoded chinese strings)
|
||
const zhEn = {
|
||
'保存': 'Save', '保存修改': 'Save Changes', '取消': 'Cancel', '确认': 'Confirm', '确定': 'OK', '删除': 'Delete',
|
||
'编辑': 'Edit', '新增': 'Add', '查询': 'Search', '搜索': 'Search', '重置': 'Reset', '提交': 'Submit', '关闭': 'Close',
|
||
'返回': 'Back', '导出': 'Export', '导入': 'Import', '下载': 'Download', '上传': 'Upload', '刷新': 'Refresh',
|
||
'查看': 'View', '查看全部': 'View All', '查看详情': 'View Details', '操作': 'Action', '状态': 'Status', '类型': 'Type',
|
||
'名称': 'Name', '描述': 'Description', '备注': 'Remark', '时间': 'Time', '日期': 'Date', '创建时间': 'Created At',
|
||
'更新时间': 'Updated At', '启用': 'Enable', '停用': 'Disable', '正常': 'Normal', '加载中': 'Loading',
|
||
'加载中...': 'Loading...', '暂无数据': 'No Data', '成功': 'Success', '失败': 'Failed', '删除成功': 'Deleted',
|
||
'删除失败': 'Delete failed', '编辑成功': 'Updated', '编辑失败': 'Update failed', '新增成功': 'Added',
|
||
'新增失败': 'Add failed', '保存成功': 'Saved', '保存失败': 'Save failed', '确定删除?': 'Are you sure to delete?',
|
||
'请选择': 'Please select', '请输入': 'Please enter', '全部': 'All', '是': 'Yes', '否': 'No', '男': 'Male', '女': 'Female',
|
||
'未知': 'Unknown', '未设置': 'Not set', '共': 'Total', '条': 'Items', '全选': 'Select all', '批量删除': 'Batch delete',
|
||
'已选': 'Selected', '更多': 'More', '展开': 'Expand', '收起': 'Collapse', '已完成': 'Completed',
|
||
'星期一': 'Monday', '星期二': 'Tuesday', '星期三': 'Wednesday', '星期四': 'Thursday', '星期五': 'Friday',
|
||
'星期六': 'Saturday', '星期日': 'Sunday',
|
||
'光伏机器人环境感知服务平台': 'PV Plant Intelligent Monitoring & O&M System',
|
||
'请选择电站': 'Please select a station', '全屏': 'Full Screen', '退出全屏': 'Exit Full Screen', '退出登录': 'Logout',
|
||
'电站地址': 'Station Address', '电站类型': 'Station Type', '运行状态': 'Running Status', '正常运行': 'Normal Running',
|
||
'地面电站': 'Ground Station', '1MW 光伏电站': '1MW PV Plant', '河南省林州': 'Linzhou, Henan',
|
||
'模块开发中': 'Module Developing',
|
||
'请输入账号': 'Enter account', '请输入密码': 'Enter password', '账号': 'Account', '密码': 'Password',
|
||
'登录': 'Login', '登录成功': 'Login success', '登录失败': 'Login failed', '欢迎': 'Welcome',
|
||
'用户协议': 'User Agreement', '隐私政策': 'Privacy Policy', '我已阅读并同意': 'I have read and agree',
|
||
'请阅读并同意用户协议': 'Please read and agree to the user agreement',
|
||
'总览首页': 'Overview', '设备管理': 'Device Management', '设备总览': 'Device Overview', '设备状态': 'Device Status',
|
||
'航线任务': 'Wayline Task', '机器人任务': 'Robot Task', '在线视频': 'Online Video', '实时监控': 'Real-time Monitor',
|
||
'告警中心': 'Alert Center', 'AI诊断分析': 'AI Diagnosis', '清洗优化': 'Cleaning Optimization', '工单任务': 'Work Order',
|
||
'报表中心': 'Report Center', '系统设置': 'System Settings', '日志管理': 'Log Management', '视频管理': 'Video Management',
|
||
'视频下载': 'Video Download', '用户管理': 'User Management', '角色管理': 'Role Management', '菜单管理': 'Menu Management',
|
||
'组织管理': 'Organization Management', '场站管理': 'Station Management', '通知策略页面': 'Notice Policy',
|
||
'数据与安全页面': 'Data & Safety', '个人中心': 'Profile', '请选择菜单': 'Please select a menu',
|
||
'当前功率': 'Current Power', '系统可用率': 'System Availability', '告警数量': 'Alert Count',
|
||
'节省运维成本': 'O&M Cost Saving', '日目标': 'Daily Target', '装机容量': 'Installed Capacity', '昨日': 'Yesterday',
|
||
'未处理': 'Unhandled', '已关闭': 'Closed', '本月累计节省': 'Monthly Accumulated Saving', '发电趋势': 'Generation Trend',
|
||
'辐照度与温度趋势': 'Irradiance & Temperature Trend', '逆变器效率对比': 'Inverter Efficiency', '运维任务进度': 'O&M Progress',
|
||
'电站概览': 'Station Overview', '近期巡检记录': 'Recent Inspection', 'AI 分析摘要': 'AI Analysis Summary',
|
||
'实时告警': 'Real-time Alerts', '设备在线状态': 'Device Online Status', '天气信息': 'Weather Info',
|
||
'清洗建议': 'Cleaning Suggestion', '实际': 'Actual', '预测': 'Predicted', '辐照度': 'Irradiance', '温度': 'Temperature',
|
||
'汇流箱': 'Combiner Box', '逆变器': 'Inverter', '巡检机器人': 'Inspection Robot', '异常': 'Abnormal', '维护中': 'Under Maintenance',
|
||
'生成清洗工单': 'Generate Cleaning Order', '请先选择电站': 'Please select station first', '清洗工单生成成功': 'Cleaning order created',
|
||
'kWh': 'kWh', 'kWp': 'kWp',
|
||
'设备名称': 'Device Name', '设备类型': 'Device Type', '设备型号': 'Device Model', '在线状态': 'Online Status',
|
||
'最后心跳': 'Last Heartbeat', '电量': 'Battery', '信号强度': 'Signal Strength', '位置': 'Location', '控制': 'Control',
|
||
'上传航线': 'Upload Wayline', '下载航线': 'Download Wayline', '执行任务': 'Execute Task', '任务名称': 'Task Name',
|
||
'任务状态': 'Task Status', '飞行时间': 'Flight Time', '高度': 'Altitude', '速度': 'Speed', '距离': 'Distance',
|
||
'开始时间': 'Start Time', '结束时间': 'End Time', '无人机': 'UAV', '割草机': 'Mower', '机器人': 'Robot', '摄像头': 'Camera',
|
||
'在线': 'Online', '离线': 'Offline', '待机': 'Standby', '运行中': 'Running', '充电中': 'Charging', '空闲': 'Idle',
|
||
'忙碌': 'Busy', '故障': 'Fault', '设备控制': 'Device Control', '实时视频': 'Real-time Video', '起飞': 'Takeoff',
|
||
'降落': 'Land', '返航': 'Return', '暂停': 'Pause', '继续': 'Resume', '紧急停止': 'Emergency Stop', '前进': 'Forward',
|
||
'后退': 'Backward', '左转': 'Turn Left', '右转': 'Turn Right', '上升': 'Up', '下降': 'Down', '左旋': 'Rotate Left',
|
||
'右旋': 'Rotate Right', '云台俯仰': 'Gimbal Pitch', '云台偏航': 'Gimbal Yaw', '放大': 'Zoom In', '缩小': 'Zoom Out',
|
||
'创建者': 'Creator', '执行计划': 'Execution Plan', '周日': 'Sun', '周一': 'Mon', '周二': 'Tue', '周三': 'Wed',
|
||
'周四': 'Thu', '周五': 'Fri', '周六': 'Sat', '执行周期': 'Execution Cycle', '新建': 'New', '暂停中': 'Paused',
|
||
'执行成功': 'Finished', '执行失败': 'Failed', '确定要删除该任务吗?': 'Delete this task?', '确定要取消该任务吗?': 'Cancel this task?',
|
||
'确定要暂停该任务吗?': 'Pause this task?', '恢复': 'Resume', '今日机器人计划': 'Today Robot Plan',
|
||
'进行中': 'In Progress', '作业中机器人': 'Working Robots', '台': 'Units', '作业中': 'Working', '累计作业里程': 'Total Distance',
|
||
'较昨日': 'vs Yesterday', '任务完成率': 'Task Completion Rate', '异常告警': 'Abnormal Alerts', '次': 'Times',
|
||
'在线率': 'Online Rate', '良好': 'Good', '机器人路径规划与监控': 'Robot Path Planning & Monitor',
|
||
'清空实时轨迹': 'Clear Track', '清空规划航线': 'Clear Plan', '控制模式:': 'Control Mode:', '本地': 'Local', '远程': 'Remote',
|
||
'航向:': 'Heading:', '已初始化': 'Initialized', '未初始化': 'Uninitialized', '定位:': 'Location:', '视频:': 'Video:',
|
||
'任务池': 'Task Pool', '任务执行计划': 'Task Execution Plan', '历史任务': 'Task History', '创建任务': 'Create Task',
|
||
'开始日期': 'Start Date', '结束日期': 'End Date', '全部机器人': 'All Robots', '作业编排建议': 'Operation Suggestion',
|
||
'开始除草任务': 'Start Mowing', '预计耗时 2 小时,当前进度 45%': 'ETA 2h, progress 45%', '预定巡检任务': 'Scheduled Inspection',
|
||
'待审批,建议执行区域 C': 'Pending, suggest area C', '设备例行维护': 'Routine Maintenance', '所有割草机返回充电站': 'All mowers return',
|
||
'智能生成今日计划': 'Auto-generate Today Plan', '设备环境与状态': 'Device Environment & Status', '当前温度': 'Current Temp',
|
||
'环境湿度': 'Humidity', '定位精度': 'Position Accuracy', 'RTK 固定': 'RTK Fixed', '网络延迟': 'Network Latency',
|
||
'注意:区域 B 存在积水风险,建议避开': 'Caution: area B flooding risk, avoid', '预设路线': 'Preset Routes',
|
||
'搜索...': 'Search...', '未命名路线': 'Unnamed Route', '删除航线': 'Delete Route', '执行航线': 'Execute Route',
|
||
'任务看板': 'Task Board', '待执行': 'Pending', '正在执行...': 'Executing...', '已暂停': 'Paused', '执行路线任务': 'Execute Route Task',
|
||
'执行': 'Execute', '路线信息': 'Route Info', '路线名称:': 'Route Name:', '请选择执行设备': 'Select Device', '机器人全景视频 - ': 'Robot Panorama - ',
|
||
'设备编号': 'Device No', '路线': 'Route', '请填写:': 'Please fill:', '请选择执行时间': 'Select Exec Time',
|
||
'任务创建成功': 'Task Created', '创建失败': 'Create Failed', '创建任务异常': 'Create Task Error', '新建任务': 'New Task',
|
||
'请输入任务名称': 'Enter Task Name', '执行路线': 'Execute Route', '选择路线': 'Select Route', '重复计划': 'Repeat Plan',
|
||
'天': 'Day', '周': 'Week', '月': 'Month', '执行日期': 'Exec Date', '选择执行日期': 'Select Exec Date', '执行时间': 'Exec Time',
|
||
'保存任务': 'Save Task',
|
||
'视频监控': 'Video Monitor', '实时监控': 'Real-time Monitor', '视频墙': 'Video Wall', '视频下载': 'Video Download',
|
||
'截图': 'Snapshot', '录制': 'Record', '播放': 'Play', '停止': 'Stop', '静音': 'Mute', '取消静音': 'Unmute', '直播': 'Live',
|
||
'回放': 'Replay', '选择设备': 'Select Device', '选择摄像头': 'Select Camera', '暂无视频': 'No Video', '视频加载中...': 'Loading video...',
|
||
'画质': 'Quality', '流畅': 'Fluency', '标清': 'SD', '高清': 'HD', '超清': 'FHD', '下载时间': 'Download Time',
|
||
'文件大小': 'File Size', '文件名': 'File Name', '下载状态': 'Download Status', '下载中': 'Downloading', '已下载': 'Downloaded',
|
||
'下载失败': 'Download Failed', '监控模式': 'Monitor Mode', '单画面': 'Single', '四画面': 'Quad', '九画面': 'Nine', '十六画面': 'Sixteen',
|
||
'告警概览': 'Alert Overview', '实时告警': 'Real-time Alert', '历史告警': 'Alert History', '告警规则': 'Alert Rules',
|
||
'告警统计': 'Alert Statistics', '告警订阅': 'Alert Subscription', '告警级别': 'Alert Level', '告警类型': 'Alert Type',
|
||
'告警来源': 'Alert Source', '告警时间': 'Alert Time', '处理状态': 'Handle Status', '处理结果': 'Handle Result',
|
||
'处理时间': 'Handle Time', '处理人': 'Handler', '处理备注': 'Handle Remark', '处理': 'Handle', '关闭告警': 'Close Alert',
|
||
'确认告警': 'Confirm Alert', '导出告警': 'Export Alert', '严重': 'Critical', '重要': 'Important', '一般': 'General',
|
||
'提示': 'Info', '待处理': 'Pending', '已处理': 'Handled', '已恢复': 'Restored', '已忽略': 'Ignored', '无法处理': 'Unable',
|
||
'厂家处理中': 'Manufacturer', '误报': 'False Alarm', '告警总数': 'Total Alerts', '今日告警': 'Today Alerts',
|
||
'未处理告警': 'Unhandled Alerts', '处理率': 'Handle Rate', '无人机故障': 'UAV Fault', '割草机故障': 'Mower Fault',
|
||
'其他设备故障': 'Other Device Fault', '服务器故障': 'Server Failure', '系统错误': 'System Error', '告警趋势': 'Alert Trend',
|
||
'告警分布': 'Alert Distribution',
|
||
'AI诊断分析': 'AI Diagnosis', '热成像分析': 'Thermal Analysis', '缺陷检测': 'Defect Detection', '温度分析': 'Temp Analysis',
|
||
'热斑检测': 'Hotspot Detection', '组件分析': 'Component Analysis', '组串分析': 'String Analysis', '逆变器分析': 'Inverter Analysis',
|
||
'上传图片': 'Upload Image', '开始分析': 'Start Analysis', '分析结果': 'Analysis Result', '缺陷类型': 'Defect Type',
|
||
'缺陷等级': 'Defect Level', '置信度': 'Confidence', '位置': 'Location', '处理建议': 'Suggestion', '异常温度': 'Abnormal Temp',
|
||
'最高温度': 'Max Temp', '平均温度': 'Avg Temp', '最低温度': 'Min Temp', '正常温度': 'Normal Temp', '热斑区域': 'Hotspot Area',
|
||
'风险等级': 'Risk Level', '高风险': 'High Risk', '中风险': 'Medium Risk', '低风险': 'Low Risk', '无风险': 'No Risk',
|
||
'检测到缺陷': 'Defects Detected', '未检测到缺陷': 'No Defect', '分析历史': 'Analysis History', '重新分析': 'Re-analyze',
|
||
'清洗优化': 'Cleaning Optimization', '清洗任务': 'Cleaning Task', '清洗建议': 'Cleaning Suggestion', '清洗计划': 'Cleaning Plan',
|
||
'清洗记录': 'Cleaning Record', '清洗效果': 'Cleaning Effect', '清洗前效率': 'Eff Before', '清洗后效率': 'Eff After',
|
||
'效率提升': 'Eff Improvement', '预计收益': 'Est Revenue', '清洗成本': 'Clean Cost', '净收益': 'Net Revenue', '优先级': 'Priority',
|
||
'建议日期': 'Suggest Date', '清洗区域': 'Area', '清洗方式': 'Method', '人工清洗': 'Manual', '机器人清洗': 'Robot',
|
||
'水清洗': 'Water', '干清洗': 'Dry', '状态': 'Status', '待清洗': 'Pending', '清洗中': 'Cleaning', '已清洗': 'Cleaned',
|
||
'已取消': 'Cancelled', '生成工单': 'Generate Order', '污损率': 'Soiling Rate', '功率损失': 'Power Loss',
|
||
'上次清洗日期': 'Last Clean', '建议清洗日期': 'Next Clean',
|
||
'工单任务': 'Work Order', '工单标题': 'Order Title', '工单类型': 'Order Type', '工单状态': 'Order Status',
|
||
'执行开始时间': 'Exec Start Time', '关联设备': 'Related Device', '关联区域': 'Related Area', '当前状态': 'Current Status',
|
||
'任务描述': 'Task Description', '附件素材': 'Attachments', '执行工单': 'Execute Order', '修改': 'Modify', '挂起': 'Suspend',
|
||
'完成': 'Complete', '派单': 'Dispatch', '修改工单': 'Modify Order', '工单派单': 'Dispatch Order', '近7天全部关联告警': '7d Alerts',
|
||
'请输入工单标题': 'Enter Title', '请选择工单类型': 'Select Type', '请选择优先级': 'Select Priority', '确认修改': 'Confirm Modify',
|
||
'确认派单': 'Confirm Dispatch', '确认执行': 'Confirm Execute', '确认完成': 'Confirm Complete', '选择接收人员': 'Select Receiver',
|
||
'请选择派单人员': 'Select Dispatcher', '选择执行设备': 'Select Device', '确定挂起?': 'Suspend?', '已创建': 'Created',
|
||
'执行中': 'In Progress', '已挂起': 'Suspended', '已完成': 'Completed', '待处理': 'Pending', '高': 'High', '中': 'Medium', '低': 'Low',
|
||
'AI 建议与关联信息': 'AI Suggestion', '建议携带': 'Suggested Equipment', '红外热像设备': 'Thermal Camera',
|
||
'优先复检组件': 'Prioritize Recheck', '预计影响发电': 'Est Impact', '关联告警趋势': 'Alert Trend', '关联告警列表': 'Alert List',
|
||
'近7天无告警记录': 'No alerts in 7d', '近 7 天': '(7d)', '高告警': 'High', '中告警': 'Medium', '低告警': 'Low',
|
||
'巡检': 'Inspection', '检修': 'Maintenance', '清洗': 'Cleaning', '维修': 'Repair', '运维': 'O&M', 'AI': 'AI',
|
||
'割草机故障': 'Mower Fault', '无人机故障': 'UAV Fault', '光伏组件故障': 'PV Module Fault', '清洗': 'Clean', '维护': 'Maintain',
|
||
'维修': 'Repair', '其他': 'Other',
|
||
'报表中心': 'Report Center', '发电量报表': 'Generation Report', '设备报表': 'Device Report', '告警报表': 'Alert Report',
|
||
'工单报表': 'Work Order Report', '巡检报表': 'Inspection Report', '清洗报表': 'Cleaning Report', '效率报表': 'Efficiency Report',
|
||
'自定义报表': 'Custom Report', '日报': 'Daily', '周报': 'Weekly', '月报': 'Monthly', '季报': 'Quarterly', '年报': 'Yearly',
|
||
'日期范围': 'Date Range', '生成报表': 'Generate Report', '导出报表': 'Export Report', '总发电量': 'Total Generation',
|
||
'峰值功率': 'Peak Power', '平均功率': 'Avg Power', '告警总数': 'Total Alerts', '工单总数': 'Total Orders', '完成率': 'Completion',
|
||
'平均效率': 'Avg Efficiency',
|
||
'系统设置': 'System Settings', '基础设置': 'Basic Settings', '用户管理': 'User Management', '菜单管理': 'Menu Management',
|
||
'组织管理': 'Organization Management', '场站管理': 'Station Management', '通知策略': 'Notice Policy', '设备接入': 'Device Access',
|
||
'数据与安全': 'Data & Safety', '系统维护': 'System Maintenance', '在线用户': 'Online Users', '设备管理': 'Device Management',
|
||
'日志管理': 'Log Management', '视频管理': 'Video Management', '系统名称': 'System Name', '系统版本': 'System Version',
|
||
'系统描述': 'System Description', '默认语言': 'Default Language', '系统Logo': 'System Logo', '主题': 'Theme', '浅色': 'Light',
|
||
'深色': 'Dark', '跟随系统': 'Follow System', '用户账号': 'Username', '用户昵称': 'Nickname', '手机号': 'Phone', '邮箱': 'Email',
|
||
'角色': 'Role', '密码': 'Password', '不填则不修改': 'Leave blank to keep', '语言': 'Language', '分配角色': 'Assign Role',
|
||
'性别': 'Gender', '状态': 'Status', '新增用户': 'Add User', '编辑用户': 'Edit User', '重置密码': 'Reset Password',
|
||
'确定将密码重置为 123456 吗?': 'Reset password to 123456?', '密码已重置为:123456': 'Password reset to 123456',
|
||
'中文': 'Chinese', '英语': 'English', '菜单名称': 'Menu Name', '菜单类型': 'Menu Type', '路由地址': 'Route Path',
|
||
'菜单图标': 'Menu Icon', '排序': 'Sort', '权限标识': 'Permission', '上级菜单': 'Parent Menu', '目录': 'Directory',
|
||
'菜单': 'Menu', '按钮': 'Button', '组织名称': 'Org Name', '组织类型': 'Org Type', '上级组织': 'Parent Org', '负责人': 'Leader',
|
||
'联系电话': 'Contact', '场站名称': 'Station Name', '场站类型': 'Station Type', '场站地址': 'Station Address',
|
||
'装机容量': 'Capacity', '场站状态': 'Station Status', '经度': 'Longitude', '纬度': 'Latitude', '时区': 'Timezone',
|
||
'日志类型': 'Log Type', '登录日志': 'Login Log', '操作日志': 'Operation Log', '错误日志': 'Error Log', '系统日志': 'System Log',
|
||
'操作人': 'Operator', '操作内容': 'Content', '操作时间': 'Time', 'IP地址': 'IP', '视频名称': 'Video Name', '视频地址': 'Video URL',
|
||
'视频类型': 'Video Type', '视频状态': 'Video Status', '备份数据库': 'Backup DB', '清除缓存': 'Clear Cache',
|
||
'系统信息': 'System Info', '磁盘使用': 'Disk', '内存使用': 'Memory', 'CPU使用率': 'CPU', '服务器状态': 'Server Status',
|
||
'运行时长': 'Uptime', '接入协议': 'Protocol', '接入状态': 'Status', '接入时间': 'Time', 'SN码': 'SN', '验证码': 'Verify Code',
|
||
'绑定设备': 'Bind Device', '错误编码': 'Error Code', '错误名称': 'Error Name', '错误来源': 'Error Source', '错误等级': 'Error Level',
|
||
'错误描述': 'Error Desc', '校验字段': 'Check Field', '对比规则': 'Compare Rule', '对比数值': 'Compare Value',
|
||
'区间最小值': 'Min', '区间最大值': 'Max', '请输入错误编码': 'Enter Error Code', '请输入错误名称': 'Enter Error Name',
|
||
'请选择来源': 'Select Source', '请选择等级': 'Select Level', '请选择错误来源': 'Select Error Source',
|
||
'请选择错误等级': 'Select Error Level', '请填写校验字段名': 'Enter Field', '请选择对比规则': 'Select Rule',
|
||
'请填写最小值': 'Enter Min', '请填写最大值': 'Enter Max', '请填写对比值': 'Enter Value',
|
||
'例如:ERR-ROBOT-001': 'e.g. ERR-ROBOT-001', '如:battery、speed、temperature': 'e.g. battery, speed',
|
||
'最小值': 'Min', '最大值': 'Max', '数值/文本,多个用逗号分隔': 'comma separated', '详细描述触发该错误的场景': 'Describe scenario',
|
||
'出现该错误后的处理方案': 'Handling plan', '新增错误规则': 'Add Error Rule', '编辑错误规则': 'Edit Error Rule',
|
||
'查看错误规则详情': 'View Error Rule', '确定要删除错误 "': 'Delete error "', '获取错误列表失败': 'Get error list failed',
|
||
'操作失败': 'Operation failed',
|
||
'个人中心': 'Profile', '获取个人信息失败': 'Get profile failed', '修改成功': 'Modified', '修改失败': 'Modify failed',
|
||
'密码修改成功': 'Password changed', '头像上传成功': 'Avatar uploaded', '上传失败': 'Upload failed',
|
||
'两次输入的密码不一致': 'Passwords mismatch', '更换头像': 'Change Avatar', '用户名称': 'Username', '用户昵称': 'Nickname',
|
||
'手机号码': 'Phone', '用户邮箱': 'Email', '所属角色': 'Role', '旧密码': 'Old Password', '新密码': 'New Password',
|
||
'确认密码': 'Confirm Password', '请输入用户昵称': 'Enter Nickname', '请输入手机号码': 'Enter Phone', '保存修改': 'Save Changes',
|
||
'确认修改': 'Confirm Modify',
|
||
'用户管理': 'User Management', '用户账号': 'Username', '用户昵称': 'Nickname', '手机号': 'Phone', '邮箱': 'Email',
|
||
'角色': 'Role', '状态': 'Status', '操作': 'Actions', '编辑': 'Edit', '删除': 'Delete', '用户账号': 'Username',
|
||
'用户昵称': 'Nickname', '手机号码': 'Phone', '密码': 'Password', '语言': 'Language', '分配角色': 'Assign Role',
|
||
'状态': 'Status', '性别': 'Gender', '不填则不修改': 'Leave blank', '中文': 'Chinese', '英语': 'English', '正常': 'Normal',
|
||
'停用': 'Disabled', '男': 'Male', '女': 'Female', '未知': 'Unknown', '批量删除(已选 ': 'Batch delete (', '重置密码': 'Reset Password',
|
||
'密码已重置为:123456': 'Password reset to 123456', '确定将密码重置为 123456 吗?': 'Reset to 123456?',
|
||
'角色管理': 'Role Management', '新增角色': 'Add Role', '角色名称': 'Role Name', '权限字符': 'Role Key', '排序': 'Sort',
|
||
'状态': 'Status', '备注': 'Remark', '操作': 'Actions', '编辑': 'Edit', '删除': 'Delete', '分配权限': 'Assign Permissions',
|
||
'数据权限': 'Data Scope', '菜单权限': 'Menu Permissions', '角色描述': 'Role Description', '正常': 'Normal', '停用': 'Disabled',
|
||
'异常': 'Abnormal',
|
||
'登录已过期,请重新登录': 'Session expired, please login again', '网络异常,请稍后重试': 'Network error, retry later',
|
||
'晴': 'Sunny', '多云': 'Cloudy', '阴': 'Overcast', '雨': 'Rainy',
|
||
};
|
||
|
||
// ---- collect referenced keys ----
|
||
const refRegex = /(?:i18n\.t|[^a-zA-Z]t)\(\s*['"`]([a-zA-Z][a-zA-Z0-9_.]*?)['"`]/g;
|
||
const files = walk(root);
|
||
const refKeys = new Set();
|
||
for (const f of files) {
|
||
const c = fs.readFileSync(f, 'utf8');
|
||
let m;
|
||
while ((m = refRegex.exec(c))) refKeys.add(m[1]);
|
||
}
|
||
|
||
// ---- helpers ----
|
||
function camelToWords(s) {
|
||
return s.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').split(/[\s._]+/).filter(Boolean);
|
||
}
|
||
function inferZhFromKey(key) {
|
||
const leaf = key.split('.').pop();
|
||
const words = camelToWords(leaf).map(w => w.toLowerCase());
|
||
const out = [];
|
||
for (let i = 0; i < words.length; i++) {
|
||
const w = words[i];
|
||
let zh = lex[w] || tokZh[w] || (w.length <= 2 && w === w.toUpperCase() ? w : '');
|
||
if (w === 'no') zh = (i > 0 && NOUNS_WITH_NO.has(words[i - 1])) ? '编号' : '无';
|
||
if (!zh) continue;
|
||
if (out[out.length - 1] !== zh) out.push(zh);
|
||
}
|
||
return out.join('');
|
||
}
|
||
function inferEnFromKey(key) {
|
||
const leaf = key.split('.').pop();
|
||
const words = camelToWords(leaf);
|
||
const STOP = new Set(['of', 'and', 'the', 'to', 'in', 'on', 'with', 'a', 'an', 'or', 'for']);
|
||
const out = [];
|
||
for (let i = 0; i < words.length; i++) {
|
||
let w = words[i];
|
||
if (w.length <= 2 || w === w.toUpperCase()) { /* keep acronym */ }
|
||
else if (i > 0 && STOP.has(w.toLowerCase())) w = w.toLowerCase();
|
||
else w = w.charAt(0).toUpperCase() + w.slice(1);
|
||
if (out[out.length - 1] !== w) out.push(w);
|
||
}
|
||
return out.join(' ');
|
||
}
|
||
function translateZh(zh) {
|
||
if (zhEn[zh]) return zhEn[zh];
|
||
// greedy phrase substitution for multi-char matches
|
||
let s = zh;
|
||
// sort keys by length desc for greedy match
|
||
const keys = Object.keys(zhEn).sort((a, b) => b.length - a.length);
|
||
for (const k of keys) { if (k.length >= 2) s = s.split(k).join('\u0001' + zhEn[k] + '\u0001'); }
|
||
// now translate remaining single chars / unknown
|
||
const segs = s.split('\u0001');
|
||
const res = segs.map(seg => {
|
||
if (zhEn[seg]) return zhEn[seg];
|
||
// try per-char? skip unknown chars to avoid garbage
|
||
return seg;
|
||
});
|
||
return res.join(' ').replace(/\s+/g, ' ').trim();
|
||
}
|
||
|
||
// ---- determine additions ----
|
||
const zhAdd = {}; // ns -> {key: val}
|
||
const enAdd = {};
|
||
const zhCjk = {};
|
||
const enCjk = {};
|
||
function addKey(fullKey, zhVal, enVal, isCjk) {
|
||
const dot = fullKey.indexOf('.');
|
||
const ns = dot > -1 ? fullKey.slice(0, dot) : '';
|
||
const leaf = dot > -1 ? fullKey.slice(dot + 1) : fullKey;
|
||
const zmap = isCjk ? zhCjk : zhAdd;
|
||
const emap = isCjk ? enCjk : enAdd;
|
||
zmap[ns] = zmap[ns] || {};
|
||
emap[ns] = emap[ns] || {};
|
||
if (!(fullKey in zhMap)) zmap[ns][leaf] = zhVal;
|
||
if (!(fullKey in enMap)) emap[ns][leaf] = enVal;
|
||
}
|
||
|
||
// referenced keys missing
|
||
let missingCount = 0;
|
||
for (const k of refKeys) {
|
||
if (!(k in zhMap) && !(k in enMap)) {
|
||
missingCount++;
|
||
addKey(k, inferZhFromKey(k), inferEnFromKey(k));
|
||
}
|
||
}
|
||
|
||
// hardcoded chinese -> keys (reuse existing by value; else new key under a file-based ns)
|
||
// map file path to namespace
|
||
function nsForFile(f) {
|
||
const rel = f.replace(root + '\\', '').replace(/\\/g, '/');
|
||
const base = path.basename(f).replace(/\.(tsx|ts|jsx|js)$/, '');
|
||
// try to infer from existing namespaces by matching folder/file
|
||
const lower = rel.toLowerCase();
|
||
if (lower.includes('systemsetting')) return 'systemSetting';
|
||
if (lower.includes('devices/') || lower.includes('device')) return 'devices';
|
||
if (lower.includes('alerts')) return 'alerts';
|
||
if (lower.includes('aianalysis') || lower.includes('aidiagnos')) return 'aiAnalysis';
|
||
if (lower.includes('clean')) return 'clean';
|
||
if (lower.includes('report')) return 'report';
|
||
if (lower.includes('workorder')) return 'workOrder';
|
||
if (lower.includes('login')) return 'login';
|
||
if (lower.includes('profile')) return 'profile';
|
||
if (lower.includes('users')) return 'users';
|
||
if (lower.includes('roles')) return 'roles';
|
||
if (lower.includes('home')) return 'home';
|
||
if (lower.includes('video')) return 'video';
|
||
if (lower.includes('router') || lower.includes('layout')) return 'layout';
|
||
return 'page';
|
||
}
|
||
|
||
const CJK = /[一-鿿]/;
|
||
let cjkCount = 0;
|
||
const cjkSeen = new Set();
|
||
for (const f of files) {
|
||
const lines = fs.readFileSync(f, 'utf8').split('\n');
|
||
for (const line of lines) {
|
||
const trimmed = line.trim();
|
||
if (trimmed.startsWith('//') || trimmed.startsWith('*')) continue;
|
||
if (/console\./.test(line)) continue;
|
||
if (!CJK.test(line)) continue;
|
||
// extract CJK substrings that look like user-facing text (skip pure comment lines)
|
||
const matches = line.match(/[一-鿿][一-鿿,。、::()()\sA-Za-z0-9%·\-/]*[一-鿿]/g);
|
||
if (!matches) continue;
|
||
for (const m of matches) {
|
||
const txt = m.trim();
|
||
if (txt.length < 2) continue;
|
||
if (cjkSeen.has(txt)) continue;
|
||
cjkSeen.add(txt);
|
||
cjkCount++;
|
||
// reuse existing key if zh value equals this
|
||
let reuseKey = null;
|
||
for (const ek of Object.keys(zhMap)) { if (zhMap[ek] === txt) { reuseKey = ek; break; } }
|
||
if (reuseKey) continue; // already have it
|
||
const ns = nsForFile(f);
|
||
// build a key from file base + counter
|
||
const base = path.basename(f).replace(/\.(tsx|ts|jsx|js)$/, '').replace(/[^a-zA-Z0-9]/g, '');
|
||
const key = ns + '.' + base + '_' + (cjkSeen.size);
|
||
addKey(key, txt, translateZh(txt), true);
|
||
}
|
||
}
|
||
}
|
||
|
||
console.log('Referenced keys total:', refKeys.size);
|
||
console.log('Missing referenced keys (added):', missingCount);
|
||
console.log('Hardcoded CJK unique strings seen:', cjkCount);
|
||
console.log('New keys to add (zh):', Object.values(zhAdd).reduce((s, o) => s + Object.keys(o).length, 0));
|
||
|
||
// save additions for next step
|
||
fs.writeFileSync('tmp_missing.json', JSON.stringify({ zhAdd, enAdd }, null, 2));
|
||
fs.writeFileSync('tmp_cjk.json', JSON.stringify({ zhCjk, enCjk }, null, 2));
|
||
console.log('Wrote tmp_missing.json and tmp_cjk.json');
|