diff --git a/static/js/app.js b/static/js/app.js
index 119a713..211e7f4 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -1,4 +1,5 @@
(function () {
+ Lang.init();
Theme.init();
WS.init();
Sidebar.init();
@@ -11,6 +12,7 @@
Router.init();
document.getElementById('theme-toggle').addEventListener('click', () => Theme.toggle());
+ document.getElementById('lang-toggle').addEventListener('click', () => Lang.toggle());
console.log('%cTurboSu %cReady',
'color:#667eea;font-size:16px;font-weight:bold;',
diff --git a/static/js/utils/lang.js b/static/js/utils/lang.js
new file mode 100644
index 0000000..99875f4
--- /dev/null
+++ b/static/js/utils/lang.js
@@ -0,0 +1,67 @@
+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',
+ devTools: '开发工具', testMode: 'UI 测试模式',
+ system: '系统', restartServer: '重启服务',
+ about: '关于', author: 'Yei.J. (AskaEth)',
+ },
+ 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)',
+ }
+ },
+
+ init() {
+ this._current = localStorage.getItem('turbosu-lang') || 'zh';
+ },
+
+ t(key) {
+ return (this._strings[this._current] || this._strings.zh)[key] || key;
+ },
+
+ toggle() {
+ this._current = this._current === 'zh' ? 'en' : 'zh';
+ localStorage.setItem('turbosu-lang', this._current);
+ location.reload();
+ }
+};
+
+window.Lang = Lang;
diff --git a/templates/index.html b/templates/index.html
index bd31ac1..197068a 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -84,6 +84,7 @@
+
@@ -104,6 +105,7 @@
+