feat: full i18n support - all pages use Lang.t() for zh/en
This commit is contained in:
+336
-41
@@ -2,50 +2,332 @@ const Lang = {
|
||||
_current: 'zh',
|
||||
_strings: {
|
||||
zh: {
|
||||
home: '首页', dashboard: '仪表盘', scene: '场景', settings: '设置',
|
||||
debug: '数据测试', selectGame: '选择游戏', collapsed: '折叠侧边栏',
|
||||
connected: '已连接', disconnected: '未连接', speed: '实时速度', rpm: '实时转速',
|
||||
gear: '当前档位', server: '服务器状态', telemetry: '遥测监听',
|
||||
connections: 'WebSocket 连接', packets: '数据包接收', lastPacket: '最后数据包',
|
||||
currentGame: '当前游戏', systemOverview: '系统概览', running: '运行中',
|
||||
stopped: '已停止', notStarted: '未启动', noData: '暂无数据', client: '个客户端',
|
||||
notSelected: '未选择', packetsUnit: '包', secAgo: '秒前',
|
||||
importTsd: '导入 .tsd', importTss: '导入 .tss', importTsp: '导入 .tsp',
|
||||
export: '导出', delete: '删除', edit: '编辑', render: '渲染', save: '保存',
|
||||
cancel: '取消', create: '新建场景', sceneName: '场景名称',
|
||||
search: '搜索仪表盘...', sort: '排序', all: '全部', none: '暂无',
|
||||
forward: '数据转发', addTarget: '+ 添加目标', saveActive: '保存并生效',
|
||||
connectionSettings: '连接设置', telemetryPort: '遥测监听端口',
|
||||
unifiedPort: '统一端口', perGamePort: '各游戏独立端口',
|
||||
restart: '重启监听', pluginSettings: '游戏插件管理',
|
||||
plugins: '游戏插件', reload: '重新加载', backup: '数据备份',
|
||||
exportBackup: '下载 .tsb', importBackup: '导入 .tsb',
|
||||
// Nav
|
||||
home: '首页', dashboard: '仪表盘', scene: '场景', market: '市场',
|
||||
record: '录制回放', debug: '数据测试', settings: '设置',
|
||||
selectGame: '选择游戏', collapseSidebar: '折叠侧边栏',
|
||||
|
||||
// Connection
|
||||
connected: '已连接', disconnected: '未连接', connectionError: '连接错误',
|
||||
|
||||
// Status cards
|
||||
serverStatus: '服务器状态', telemetryStatus: '遥测监听',
|
||||
wsConnections: 'WebSocket 连接', packetCount: '数据包接收',
|
||||
lastPacket: '最后数据包', currentGame: '当前游戏',
|
||||
liveSpeed: '实时速度', liveRpm: '实时转速', liveGear: '当前档位',
|
||||
systemOverview: '系统概览', overviewDesc: '实时监控 TurboSu 运行状态与游戏遥测连接',
|
||||
running: '运行中', stopped: '已停止', notStarted: '未启动',
|
||||
noData: '暂无数据', notSelected: '未选择',
|
||||
listening: '监听中',
|
||||
|
||||
// Dashboard
|
||||
searchDashboards: '搜索仪表盘...', sortByName: '名称', sortByCategory: '分类',
|
||||
sortByAuthor: '作者', importTsd: '导入 .tsd', newDashboard: '+ 新建',
|
||||
noDashboards: '暂无仪表盘主题', createFirstDash: '创建或导入你的第一个仪表盘主题',
|
||||
noCompatibleDash: '当前游戏没有兼容的仪表盘',
|
||||
allCategory: '全部', builtin: '内置', custom: '自定义',
|
||||
fullCompatible: '全', limitedCompatible: '限',
|
||||
|
||||
// Scene
|
||||
sceneManagement: '场景管理', noGameSelected: '请先在侧边栏选择一个游戏',
|
||||
newScene: '+ 新建场景', importTss: '导入 .tss',
|
||||
noScenes: '暂无场景', createFirstScene: '点击"新建场景"创建你的第一个场景布局',
|
||||
render: '渲染', edit: '编辑', delete: '删除', export: '导出',
|
||||
sceneName: '场景名称', sceneDescription: '场景描述(可选)',
|
||||
sceneCanvasHint: '提示:保存后可在场景编辑器中添加仪表盘、调整布局和画布比例。',
|
||||
save: '保存', cancel: '取消', editScene: '编辑场景',
|
||||
canvasesCount: '个画布', backToList: '← 返回', saveScene: '保存场景',
|
||||
dashListDrag: '仪表盘列表 (拖到画布)', noCompatibleDashForScene: '无兼容仪表盘',
|
||||
|
||||
// Market
|
||||
marketPage: '仪表盘市场', marketDesc: '浏览并安装社区分享的仪表盘和场景',
|
||||
notLoggedIn: '未登录', loggedIn: '已登录',
|
||||
login: '登录', register: '注册', logout: '退出',
|
||||
publish: '发布你的作品', install: '安装', installed: '已安装',
|
||||
installScene: '安装场景', uninstall: '卸载',
|
||||
pending: '待审核', approved: '已通过',
|
||||
marketLogin: '市场账户',
|
||||
email: '邮箱', password: '密码', username: '用户名',
|
||||
loginSuccess: '登录成功', loginFailed: '登录失败',
|
||||
registerSuccess: '注册成功,请查收验证邮件(点击关闭)', registerFailed: '注册失败',
|
||||
publishTitle: '发布作品', publishDesc: '选择要发布的仪表盘或场景',
|
||||
chooseFile: '📁 选择文件 (.tsd / .tss)',
|
||||
orChooseLocal: '— 或从本地选择 —',
|
||||
localDashboards: '本地仪表盘', localScenes: '本地场景',
|
||||
noPublishable: '没有可发布的内容', publishFailed: '发布失败',
|
||||
publishSuccess: '发布成功',
|
||||
uploadPreview: '上传预览图', dropPreview: '点击或拖放图片到此处 (最大 6MB)',
|
||||
previewTooLarge: '预览图不能超过 6MB', imageOnly: '仅支持图片格式',
|
||||
updateItem: '更新', confirmDelete: '确定删除?',
|
||||
myItems: '我的', myDashboards: '我的仪表盘', myScenes: '我的场景',
|
||||
noUploads: '你还没有上传任何内容',
|
||||
refresh: '🔄', retry: '重试', loadFailed: '加载失败',
|
||||
dashboardsTab: '仪表盘', scenesTab: '场景', myTab: '我的',
|
||||
installedHint: '安装成功!请在仪表盘页面查看',
|
||||
installFailed: '安装失败',
|
||||
needLogin: '请先登录',
|
||||
confirmUninstall: '确定卸载 "$1"?',
|
||||
|
||||
// Record
|
||||
recordPage: '录制与回放', recordDesc: '录制原始 UDP 流到 .tsr 文件,回放调试仪表盘',
|
||||
recordControl: '录制控制', startRecord: '开始录制', stopRecord: '停止录制',
|
||||
ready: '就绪', recording: '录制中...', autoDetect: '自动检测',
|
||||
playbackActive: '正在回放: ', playbackHint: '打开仪表盘页面即可看到数据',
|
||||
stopPlayback: '停止', recordFiles: '录制文件', importTsr: '导入 .tsr',
|
||||
noRecordings: '暂无录制文件', play: '播放',
|
||||
|
||||
// Debug
|
||||
debugPage: '数据测试', debugToolbar: '',
|
||||
parsedFields: '解析后的数据字段', rawJsonStream: '原始 JSON 数据流',
|
||||
waitingData: '等待数据...', pause: '⏸ 暂停', resume: '▶ 继续',
|
||||
clear: '清空', autoScroll: '自动滚动', viewLog: '📄 日志',
|
||||
|
||||
// Settings
|
||||
connectionSettings: '连接设置',
|
||||
telemetryPort: '遥测监听端口', telemetryPortDesc: '全局统一端口',
|
||||
tcpPort: 'TCP 默认端口', tcpPortDesc: 'TCP 协议默认监听端口',
|
||||
unifiedPort: '统一端口', unifiedPortDesc: '关闭后切游戏自动切换到各游戏的默认端口',
|
||||
unifiedPortToggle: '使用游戏独立端口',
|
||||
perGamePort: '各游戏独立端口', savePorts: '保存端口',
|
||||
restartListener: '重启遥测监听', restartListenerDesc: '修改端口或切换游戏后',
|
||||
restartBtn: '重启监听',
|
||||
|
||||
dataForwarding: '数据转发', dataForwardingDesc: '将收到的游戏原始 UDP 数据包完整转发到下游物理外设',
|
||||
addTarget: '+ 添加目标', saveEffective: '保存并生效',
|
||||
noForwardTargets: '暂无转发目标,点击下方添加',
|
||||
forwardEnabled: '启用',
|
||||
|
||||
dashManagement: '仪表盘管理', rightClickExport: '右键卡片导出',
|
||||
|
||||
pluginManagement: '游戏插件管理', importTsp: '导入 .tsp',
|
||||
reloadPlugins: '重新加载', noPlugins: '暂无游戏插件',
|
||||
|
||||
dataBackup: '数据备份', exportBackup: '导出全量备份',
|
||||
backupDesc: '打包仪表盘+场景+配置为 .tsb', downloadTsb: '下载 .tsb',
|
||||
restoreBackup: '恢复备份', restoreBackupDesc: '从 .tsb 文件恢复',
|
||||
importTsb: '导入 .tsb',
|
||||
|
||||
devTools: '开发工具', testMode: 'UI 测试模式',
|
||||
system: '系统', restartServer: '重启服务',
|
||||
about: '关于', author: 'Yei.J. (AskaEth)',
|
||||
testModeDesc: '本地随机模拟遥测数据',
|
||||
testModeOn: '测试模式已开启', testModeOff: '测试模式已关闭',
|
||||
|
||||
systemSection: '系统', restartServer: '重启 TurboSu',
|
||||
restartServerDesc: '重新加载所有代码和配置', restartBtnSys: '重启服务',
|
||||
confirmRestart: '确定重启 TurboSu 服务?',
|
||||
restarting: '服务正在重启,3秒后自动刷新...',
|
||||
|
||||
about: '关于', aboutDesc: '赛车遥测仪表盘 · 极速中枢 · Yei.J. (AskaEth)',
|
||||
|
||||
// General
|
||||
loading: '加载中...', confirm: '确定', success: '成功', error: '错误',
|
||||
clickClose: '点击关闭', saved: '已保存', updated: '已更新',
|
||||
deleted: '已删除', portUpdated: '端口已更新,重启后生效',
|
||||
configSaved: '已保存', telemetryRestarted: '遥测监听已重启',
|
||||
pluginInstalled: '插件安装成功', pluginRemoved: '插件已移除',
|
||||
pluginReloaded: '插件已重新加载',
|
||||
|
||||
// Counters & formats
|
||||
connectionsCount: '%d 个客户端', packetsCount: '%d 包',
|
||||
secondsAgo: '%d秒前', gearLabel: '档位 %s',
|
||||
downloadCount: '%d 次下载', downloadCountShort: '%d 次',
|
||||
canvasesLabel: '%d 个画布', forwardsSaved: '已保存 %d 个转发目标',
|
||||
defaultPortLabel: '默认: ',
|
||||
|
||||
// More UI
|
||||
noGamePlugins: '暂无可用的游戏插件',
|
||||
noGame: '未关联游戏', currentGamePrefix: '当前游戏: ',
|
||||
community: '社区',
|
||||
noScenesMarket: '暂无场景', noDashboardsMarket: '暂无仪表盘',
|
||||
|
||||
// Prompts / modals
|
||||
dashboardNamePrompt: '仪表盘名称:',
|
||||
marketLoginPrompt: '请先登录市场账户',
|
||||
enterEmailPassword: '请输入邮箱和密码',
|
||||
selectFileOrPreview: '请选择文件或预览图',
|
||||
confirmRemove: '移除?',
|
||||
|
||||
// Toast: import / create / upload
|
||||
importSuccess: '导入成功', importFailed: '导入失败',
|
||||
createSuccess: '创建成功', createFailed: '创建失败',
|
||||
uploadSuccess: '上传成功', uploadFailed: '上传失败',
|
||||
uploadFailedMsg: '上传失败: ',
|
||||
installSuccess: '安装成功', installFailedMsg: '安装失败: ',
|
||||
remove: '移除',
|
||||
uninstallSuccess: '已卸载', uninstallFailed: '卸载失败',
|
||||
uninstallNotFound: '未找到本地安装',
|
||||
deleteFailed: '删除失败', loggedOut: '已退出',
|
||||
sceneSaveSuccess: '场景保存成功', saveFailed: '保存失败: ',
|
||||
sceneImportSuccess: '场景导入成功',
|
||||
playbackStarted: '回放已开始', playbackStartedHint: '回放已开始,打开仪表盘查看数据',
|
||||
restoreSuccess: '恢复成功', restoreFailed: '恢复失败: ',
|
||||
removeSuccess: '已移除',
|
||||
exportTsdHint: '正在下载 .tsd 文件...',
|
||||
linkCopied: '链接已复制,可在局域网设备访问',
|
||||
linkCopiedShort: '链接已复制',
|
||||
portsSaved: '端口已保存',
|
||||
marketEmpty: '市场暂无仪表盘', marketLoadFailed: '市场加载失败',
|
||||
installDataIncomplete: '安装失败:数据不完整',
|
||||
installNetworkError: '安装失败:网络错误',
|
||||
restartRequestSent: '重启请求已发送,请手动刷新',
|
||||
marketNoItems: '暂无',
|
||||
confirmUpdate: '确认更新',
|
||||
},
|
||||
en: {
|
||||
home: 'Home', dashboard: 'Dashboard', scene: 'Scene', settings: 'Settings',
|
||||
debug: 'Debug', selectGame: 'Select Game', collapsed: 'Collapse',
|
||||
connected: 'Connected', disconnected: 'Disconnected', speed: 'Speed', rpm: 'RPM',
|
||||
gear: 'Gear', server: 'Server', telemetry: 'Telemetry',
|
||||
connections: 'Connections', packets: 'Packets', lastPacket: 'Last Packet',
|
||||
currentGame: 'Game', systemOverview: 'Overview', running: 'Running',
|
||||
stopped: 'Stopped', notStarted: 'Off', noData: 'No Data', client: ' clients',
|
||||
notSelected: 'None', packetsUnit: 'pkt', secAgo: 's ago',
|
||||
importTsd: 'Import .tsd', importTss: 'Import .tss', importTsp: 'Import .tsp',
|
||||
export: 'Export', delete: 'Delete', edit: 'Edit', render: 'Render', save: 'Save',
|
||||
cancel: 'Cancel', create: 'New Scene', sceneName: 'Name',
|
||||
search: 'Search...', sort: 'Sort', all: 'All', none: 'None',
|
||||
forward: 'Forward', addTarget: '+ Add', saveActive: 'Save',
|
||||
connectionSettings: 'Connection', telemetryPort: 'Port',
|
||||
unifiedPort: 'Unified', perGamePort: 'Per Game',
|
||||
restart: 'Restart', pluginSettings: 'Plugins',
|
||||
plugins: 'Plugins', reload: 'Reload', backup: 'Backup',
|
||||
exportBackup: 'Download .tsb', importBackup: 'Import .tsb',
|
||||
devTools: 'Dev Tools', testMode: 'Test Mode',
|
||||
system: 'System', restartServer: 'Restart',
|
||||
about: 'About', author: 'Yei.J. (AskaEth)',
|
||||
home: 'Home', dashboard: 'Dashboard', scene: 'Scene', market: 'Market',
|
||||
record: 'Record', debug: 'Debug', settings: 'Settings',
|
||||
selectGame: 'Select Game', collapseSidebar: 'Collapse',
|
||||
|
||||
connected: 'Connected', disconnected: 'Disconnected', connectionError: 'Error',
|
||||
|
||||
serverStatus: 'Server', telemetryStatus: 'Telemetry',
|
||||
wsConnections: 'Connections', packetCount: 'Packets',
|
||||
lastPacket: 'Last Packet', currentGame: 'Game',
|
||||
liveSpeed: 'Speed', liveRpm: 'RPM', liveGear: 'Gear',
|
||||
systemOverview: 'System Overview', overviewDesc: 'Real-time monitoring',
|
||||
running: 'Running', stopped: 'Stopped', notStarted: 'Off',
|
||||
noData: 'No Data', notSelected: 'None',
|
||||
listening: 'Listening',
|
||||
|
||||
searchDashboards: 'Search...', sortByName: 'Name', sortByCategory: 'Category',
|
||||
sortByAuthor: 'Author', importTsd: 'Import .tsd', newDashboard: '+ New',
|
||||
noDashboards: 'No dashboards', createFirstDash: 'Create or import your first dashboard',
|
||||
noCompatibleDash: 'No compatible dashboards for current game',
|
||||
allCategory: 'All', builtin: 'Built-in', custom: 'Custom',
|
||||
fullCompatible: 'All', limitedCompatible: 'Lim',
|
||||
|
||||
sceneManagement: 'Scene Manager', noGameSelected: 'Select a game first',
|
||||
newScene: '+ New Scene', importTss: 'Import .tss',
|
||||
noScenes: 'No scenes', createFirstScene: 'Create your first scene',
|
||||
render: 'Render', edit: 'Edit', delete: 'Delete', export: 'Export',
|
||||
sceneName: 'Name', sceneDescription: 'Description (optional)',
|
||||
sceneCanvasHint: 'Tip: Save first, then edit layout in scene editor.',
|
||||
save: 'Save', cancel: 'Cancel', editScene: 'Edit Scene',
|
||||
canvasesCount: 'canvases', backToList: '← Back', saveScene: 'Save Scene',
|
||||
dashListDrag: 'Dashboards (drag to canvas)', noCompatibleDashForScene: 'No compatible dashboards',
|
||||
|
||||
marketPage: 'Marketplace', marketDesc: 'Browse and install community dashboards & scenes',
|
||||
notLoggedIn: 'Not logged in', loggedIn: 'Logged in',
|
||||
login: 'Login', register: 'Register', logout: 'Logout',
|
||||
publish: 'Publish', install: 'Install', installed: 'Installed',
|
||||
installScene: 'Install Scene', uninstall: 'Uninstall',
|
||||
pending: 'Pending', approved: 'Approved',
|
||||
marketLogin: 'Account',
|
||||
email: 'Email', password: 'Password', username: 'Username',
|
||||
loginSuccess: 'Login successful', loginFailed: 'Login failed',
|
||||
registerSuccess: 'Registered! Check email to verify (click to close)', registerFailed: 'Registration failed',
|
||||
publishTitle: 'Publish', publishDesc: 'Select a dashboard or scene',
|
||||
chooseFile: '📁 Choose file (.tsd / .tss)',
|
||||
orChooseLocal: '— or select from local —',
|
||||
localDashboards: 'Local Dashboards', localScenes: 'Local Scenes',
|
||||
noPublishable: 'Nothing to publish', publishFailed: 'Publish failed',
|
||||
publishSuccess: 'Published successfully',
|
||||
uploadPreview: 'Upload Preview', dropPreview: 'Click or drop image (max 6MB)',
|
||||
previewTooLarge: 'Preview too large (6MB max)', imageOnly: 'Images only',
|
||||
updateItem: 'Update', confirmDelete: 'Confirm delete?',
|
||||
myItems: 'Mine', myDashboards: 'My Dashboards', myScenes: 'My Scenes',
|
||||
noUploads: 'Nothing uploaded yet',
|
||||
refresh: '🔄', retry: 'Retry', loadFailed: 'Load failed',
|
||||
dashboardsTab: 'Dashboards', scenesTab: 'Scenes', myTab: 'Mine',
|
||||
installedHint: 'Installed! Check dashboard page',
|
||||
installFailed: 'Install failed',
|
||||
needLogin: 'Please login first',
|
||||
confirmUninstall: 'Uninstall "$1"?',
|
||||
|
||||
recordPage: 'Record & Playback', recordDesc: 'Record raw UDP to .tsr, replay for debugging',
|
||||
recordControl: 'Record Control', startRecord: 'Start', stopRecord: 'Stop',
|
||||
ready: 'Ready', recording: 'Recording...', autoDetect: 'Auto Detect',
|
||||
playbackActive: 'Playing: ', playbackHint: 'Open a dashboard to see data',
|
||||
stopPlayback: 'Stop', recordFiles: 'Recordings', importTsr: 'Import .tsr',
|
||||
noRecordings: 'No recordings', play: 'Play',
|
||||
|
||||
debugPage: 'Debug', debugToolbar: '',
|
||||
parsedFields: 'Parsed Fields', rawJsonStream: 'Raw JSON Stream',
|
||||
waitingData: 'Waiting...', pause: '⏸ Pause', resume: '▶ Resume',
|
||||
clear: 'Clear', autoScroll: 'Auto Scroll', viewLog: '📄 Log',
|
||||
|
||||
connectionSettings: 'Connection',
|
||||
telemetryPort: 'Telemetry Port', telemetryPortDesc: 'Global port',
|
||||
tcpPort: 'TCP Port', tcpPortDesc: 'Default TCP port',
|
||||
unifiedPort: 'Unified Port', unifiedPortDesc: 'Turn off for per-game ports',
|
||||
unifiedPortToggle: 'Use per-game ports',
|
||||
perGamePort: 'Per-Game Ports', savePorts: 'Save Ports',
|
||||
restartListener: 'Restart Listener', restartListenerDesc: 'After port/game change',
|
||||
restartBtn: 'Restart',
|
||||
|
||||
dataForwarding: 'Data Forwarding', dataForwardingDesc: 'Forward raw UDP to downstream devices',
|
||||
addTarget: '+ Add', saveEffective: 'Save',
|
||||
noForwardTargets: 'No targets, add below',
|
||||
forwardEnabled: 'Enabled',
|
||||
|
||||
dashManagement: 'Dashboard Management', rightClickExport: 'Right-click to export',
|
||||
|
||||
pluginManagement: 'Plugin Management', importTsp: 'Import .tsp',
|
||||
reloadPlugins: 'Reload', noPlugins: 'No plugins',
|
||||
|
||||
dataBackup: 'Backup', exportBackup: 'Export Backup',
|
||||
backupDesc: 'Pack dashboards+scenes+config as .tsb', downloadTsb: 'Download .tsb',
|
||||
restoreBackup: 'Restore Backup', restoreBackupDesc: 'Restore from .tsb',
|
||||
importTsb: 'Import .tsb',
|
||||
|
||||
devTools: 'Dev Tools', testMode: 'UI Test Mode',
|
||||
testModeDesc: 'Simulate telemetry locally',
|
||||
testModeOn: 'Test mode on', testModeOff: 'Test mode off',
|
||||
|
||||
systemSection: 'System', restartServer: 'Restart TurboSu',
|
||||
restartServerDesc: 'Reload all code and config', restartBtnSys: 'Restart',
|
||||
confirmRestart: 'Restart TurboSu?',
|
||||
restarting: 'Restarting, will refresh in 3s...',
|
||||
|
||||
about: 'About', aboutDesc: 'Racing Telemetry Dashboard · Yei.J. (AskaEth)',
|
||||
|
||||
loading: 'Loading...', confirm: 'Confirm', success: 'Success', error: 'Error',
|
||||
clickClose: 'Click to close', saved: 'Saved', updated: 'Updated',
|
||||
deleted: 'Deleted', portUpdated: 'Port updated, restart to apply',
|
||||
configSaved: 'Saved', telemetryRestarted: 'Listener restarted',
|
||||
pluginInstalled: 'Plugin installed', pluginRemoved: 'Plugin removed',
|
||||
pluginReloaded: 'Plugins reloaded',
|
||||
|
||||
connectionsCount: '%d clients', packetsCount: '%d packets',
|
||||
secondsAgo: '%ds ago', gearLabel: 'Gear %s',
|
||||
downloadCount: '%d downloads', downloadCountShort: '%d',
|
||||
canvasesLabel: '%d canvases', forwardsSaved: '%d targets saved',
|
||||
defaultPortLabel: 'Default: ',
|
||||
|
||||
noGamePlugins: 'No game plugins available',
|
||||
noGame: 'No game', currentGamePrefix: 'Current game: ',
|
||||
community: 'Community',
|
||||
noScenesMarket: 'No scenes', noDashboardsMarket: 'No dashboards',
|
||||
|
||||
dashboardNamePrompt: 'Dashboard name:',
|
||||
marketLoginPrompt: 'Please login first',
|
||||
enterEmailPassword: 'Enter email and password',
|
||||
selectFileOrPreview: 'Select file or preview',
|
||||
confirmRemove: 'Remove?',
|
||||
|
||||
importSuccess: 'Imported', importFailed: 'Import failed',
|
||||
createSuccess: 'Created', createFailed: 'Create failed',
|
||||
uploadSuccess: 'Uploaded', uploadFailed: 'Upload failed',
|
||||
uploadFailedMsg: 'Upload failed: ',
|
||||
installSuccess: 'Installed', installFailedMsg: 'Install failed: ',
|
||||
remove: 'Remove',
|
||||
uninstallSuccess: 'Uninstalled', uninstallFailed: 'Uninstall failed',
|
||||
uninstallNotFound: 'Not found locally',
|
||||
deleteFailed: 'Delete failed', loggedOut: 'Logged out',
|
||||
sceneSaveSuccess: 'Scene saved', saveFailed: 'Save failed: ',
|
||||
sceneImportSuccess: 'Scene imported',
|
||||
playbackStarted: 'Playback started', playbackStartedHint: 'Playback started, open dashboard to view',
|
||||
restoreSuccess: 'Restored', restoreFailed: 'Restore failed: ',
|
||||
removeSuccess: 'Removed',
|
||||
exportTsdHint: 'Downloading .tsd...',
|
||||
linkCopied: 'Link copied, accessible on LAN',
|
||||
linkCopiedShort: 'Link copied',
|
||||
portsSaved: 'Ports saved',
|
||||
marketEmpty: 'No dashboards on market', marketLoadFailed: 'Market load failed',
|
||||
installDataIncomplete: 'Incomplete data',
|
||||
installNetworkError: 'Network error',
|
||||
restartRequestSent: 'Restart sent, refresh manually',
|
||||
marketNoItems: 'None',
|
||||
confirmUpdate: 'Confirm Update',
|
||||
}
|
||||
},
|
||||
|
||||
@@ -53,12 +335,25 @@ const Lang = {
|
||||
this._current = localStorage.getItem('turbosu-lang') || 'zh';
|
||||
const btn = document.getElementById('lang-toggle');
|
||||
if (btn) btn.textContent = this._current === 'zh' ? 'EN' : '中';
|
||||
this._scan();
|
||||
},
|
||||
|
||||
t(key) {
|
||||
return (this._strings[this._current] || this._strings.zh)[key] || key;
|
||||
},
|
||||
|
||||
_scan() {
|
||||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||
const key = el.getAttribute('data-i18n');
|
||||
const text = this.t(key);
|
||||
if (el.tagName === 'INPUT' && (el.type === 'text' || el.type === 'search' || el.type === 'email' || el.type === 'password')) {
|
||||
el.placeholder = text;
|
||||
} else {
|
||||
el.textContent = text;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toggle() {
|
||||
this._current = this._current === 'zh' ? 'en' : 'zh';
|
||||
localStorage.setItem('turbosu-lang', this._current);
|
||||
|
||||
Reference in New Issue
Block a user