Explorar o código

feat(i18n): enhance localization support with new translations and updates

- Added new keys and translations for various UI elements in English and Chinese.
- Updated existing translations for improved clarity and consistency.
- Introduced new keys for features like machine management, playback options, and user interactions.
- Enhanced the overall localization structure to support better user experience across different languages.
yb hai 2 semanas
pai
achega
183e08b9d6
Modificáronse 6 ficheiros con 904 adicións e 196 borrados
  1. 67 0
      i18next-scanner.config.cjs
  2. 5 1
      package.json
  3. 467 0
      pnpm-lock.yaml
  4. 129 0
      scripts/sort-json.cjs
  5. 118 96
      src/locales/en.json
  6. 118 99
      src/locales/zh-cn.json

+ 67 - 0
i18next-scanner.config.cjs

@@ -0,0 +1,67 @@
+/**
+ * i18next-scanner 配置文件
+ * 用于扫描代码中的翻译 key 并自动更新 locale JSON 文件
+ *
+ * 使用方法: pnpm run i18n
+ */
+
+const typescriptTransform = require('i18next-scanner-typescript')
+
+module.exports = {
+  input: [
+    'src/**/*.{js,jsx,ts,tsx,vue}',
+    // 排除不需要扫描的目录
+    '!src/locales/**',
+    '!**/node_modules/**'
+  ],
+  output: './',
+  options: {
+    debug: false,
+    removeUnusedKeys: true,
+    sort: true,
+    func: {
+      // 扫描的函数名
+      list: ['t', '$t', 'i18n.t'],
+      extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue']
+    },
+    trans: {
+      // Trans 组件 (如果使用)
+      component: 'Trans',
+      i18nKey: 'i18nKey',
+      defaultsKey: 'defaults',
+      extensions: ['.js', '.jsx', '.tsx', '.vue'],
+      fallbackKey: false
+    },
+    // 支持的语言
+    lngs: ['en', 'zh-cn'],
+    ns: ['translation'],
+    defaultLng: 'zh-cn',
+    defaultNs: 'translation',
+    // 默认值策略:中文使用 key 本身,英文留空待翻译
+    defaultValue: (lng, ns, key) => {
+      if (lng === 'zh-cn') {
+        return key
+      }
+      return ''
+    },
+    resource: {
+      loadPath: 'src/locales/{{lng}}.json',
+      savePath: 'src/locales/{{lng}}.json',
+      jsonIndent: 2,
+      lineEnding: '\n'
+    },
+    nsSeparator: false, // 禁用 namespace 分隔符
+    keySeparator: false, // 禁用 key 分隔符,支持扁平化 key
+    interpolation: {
+      prefix: '{{',
+      suffix: '}}'
+    }
+  },
+  // TypeScript 和 Vue 文件解析支持
+  transform: typescriptTransform({
+    extensions: ['.ts', '.tsx', '.vue'],
+    tsOptions: {
+      target: 'esnext'
+    }
+  })
+}

+ 5 - 1
package.json

@@ -23,7 +23,9 @@
     "prepare": "husky install",
     "deploy": "wrangler pages deploy dist --project-name=tg-live-game-web --branch=main",
     "deploy:preview": "wrangler pages deploy dist --project-name=tg-live-game-web --branch=preview",
-    "build:deploy": "pnpm run build && pnpm run deploy"
+    "build:deploy": "pnpm run build && pnpm run deploy",
+    "i18n": "i18next-scanner --config i18next-scanner.config.cjs && node scripts/sort-json.cjs",
+    "i18n:scan": "i18next-scanner --config i18next-scanner.config.cjs"
   },
   "lint-staged": {
     "*.{vue,js,ts}": [
@@ -71,6 +73,8 @@
     "eslint-plugin-vue": "^9.11.0",
     "happy-dom": "^20.0.11",
     "husky": "^6.0.0",
+    "i18next-scanner": "^4.6.0",
+    "i18next-scanner-typescript": "^1.2.1",
     "lint-staged": "^10.5.4",
     "prettier": "^2.8.8",
     "typescript": "~5.6.3",

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 467 - 0
pnpm-lock.yaml


+ 129 - 0
scripts/sort-json.cjs

@@ -0,0 +1,129 @@
+/**
+ * JSON 排序脚本
+ * 对 locale JSON 文件按 key 字母顺序排序
+ *
+ * 使用方法:
+ *   node scripts/sort-json.cjs                    # 排序所有 locale 文件
+ *   node scripts/sort-json.cjs src/locales/en.json # 排序指定文件
+ *   node scripts/sort-json.cjs --check            # 检查是否已排序(不修改)
+ */
+
+const fs = require('fs')
+const path = require('path')
+
+// 配置
+const LOCALES_DIR = path.join(__dirname, '../src/locales')
+const LOCALE_FILES = ['en.json', 'zh-cn.json']
+
+/**
+ * 读取并解析 JSON 文件
+ */
+function readJSONFile(filePath) {
+  try {
+    const content = fs.readFileSync(filePath, 'utf-8')
+    return JSON.parse(content)
+  } catch (error) {
+    console.error(`❌ 读取文件失败: ${filePath}`)
+    console.error(error.message)
+    return null
+  }
+}
+
+/**
+ * 按 key 排序 JSON 对象
+ */
+function sortJSON(obj) {
+  const sorted = {}
+  const keys = Object.keys(obj).sort((a, b) => a.localeCompare(b, 'zh-CN'))
+  for (const key of keys) {
+    sorted[key] = obj[key]
+  }
+  return sorted
+}
+
+/**
+ * 检查 JSON 是否已排序
+ */
+function isJSONSorted(obj) {
+  const keys = Object.keys(obj)
+  const sortedKeys = [...keys].sort((a, b) => a.localeCompare(b, 'zh-CN'))
+  return keys.every((key, index) => key === sortedKeys[index])
+}
+
+/**
+ * 保存 JSON 文件
+ */
+function saveJSONFile(filePath, data) {
+  const content = JSON.stringify(data, null, 2) + '\n'
+  fs.writeFileSync(filePath, content, 'utf-8')
+}
+
+/**
+ * 处理单个文件
+ */
+function processFile(filePath, checkOnly = false) {
+  const fileName = path.basename(filePath)
+
+  if (!fs.existsSync(filePath)) {
+    console.log(`⚠️  文件不存在: ${fileName}`)
+    return false
+  }
+
+  const data = readJSONFile(filePath)
+  if (!data) return false
+
+  const keyCount = Object.keys(data).length
+
+  if (isJSONSorted(data)) {
+    console.log(`✅ ${fileName} (${keyCount} keys) - 已排序`)
+    return true
+  }
+
+  if (checkOnly) {
+    console.log(`❌ ${fileName} (${keyCount} keys) - 未排序`)
+    return false
+  }
+
+  const sorted = sortJSON(data)
+  saveJSONFile(filePath, sorted)
+  console.log(`✅ ${fileName} (${keyCount} keys) - 已排序并保存`)
+  return true
+}
+
+/**
+ * 处理所有 locale 文件
+ */
+function processAllFiles(checkOnly = false) {
+  console.log('\n📦 处理 locale 文件...\n')
+
+  let allSorted = true
+
+  for (const file of LOCALE_FILES) {
+    const filePath = path.join(LOCALES_DIR, file)
+    const result = processFile(filePath, checkOnly)
+    if (!result) allSorted = false
+  }
+
+  console.log('')
+
+  if (checkOnly && !allSorted) {
+    console.log('💡 运行 "pnpm run i18n" 来排序文件\n')
+    process.exit(1)
+  }
+
+  return allSorted
+}
+
+// 主逻辑
+const args = process.argv.slice(2)
+const checkOnly = args.includes('--check')
+const targetFile = args.find((arg) => arg.endsWith('.json'))
+
+if (targetFile) {
+  // 处理指定文件
+  const filePath = path.isAbsolute(targetFile) ? targetFile : path.join(process.cwd(), targetFile)
+  processFile(filePath, checkOnly)
+} else {
+  // 处理所有文件
+  processAllFiles(checkOnly)
+}

+ 118 - 96
src/locales/en.json

@@ -1,115 +1,137 @@
 {
-  "摄像头管理系统": "Camera Management",
-  "仪表盘": "Dashboard",
-  "机器管理": "Machine Management",
-  "摄像头管理": "Camera Management",
-  "用户管理": "User Management",
-  "视频测试": "Video Test",
-  "Stream 测试": "Stream Test",
-  "视频管理": "Video Management",
-  "直播管理": "Live Management",
-  "Stream 配置": "Stream Configuration",
-  "审计日志": "Audit Log",
-  "观看统计": "Watching Statistics",
-  "修改密码": "Change Password",
-  "退出登录": "Logout",
-  "原密码": "Old Password",
-  "新密码": "New Password",
-  "确认密码": "Confirm Password",
-  "请再次输入新密码": "Please enter the new password again",
-  "密码长度不能少于6位": "Password length must be at least 6 characters",
-  "请输入原密码": "Please enter the old password",
-  "请输入新密码": "Please enter the new password",
-  "两次输入的密码不一致": "The passwords entered twice do not match",
-  "取消": "Cancel",
-  "确定": "Confirm",
-  "欢迎回来": "Welcome Back",
-  "登录您的管理后台,开始管理您的业务": "Sign in to your admin console and start managing your business",
-  "用户": "Users",
-  "稳定性": "Uptime",
-  "技术支持": "Support",
+  "版本": "Version",
+  "保存配置": "Save Configuration",
+  "编辑": "",
+  "编辑机器": "",
+  "播放": "Play",
+  "播放测试视频": "Play Test Video",
+  "播放方式": "Playback Method",
+  "播放器类型": "Player Type",
+  "播放域名的子域名部分": "The subdomain part of the playback domain",
+  "操作": "",
+  "测试播放": "Test Playback",
+  "测试连接": "Test Connection",
+  "测试视频": "Test Video",
+  "查询": "",
+  "成功删除": "",
+  "创建时间": "",
+  "当前状态": "Current Status",
   "登录": "Sign In",
-  "用户名": "Username",
-  "密码": "Password",
-  "记住我": "Remember me",
-  "忘记密码?": "Forgot password?",
   "登录成功": "Login successful",
+  "登录您的管理后台,开始管理您的业务": "Sign in to your admin console and start managing your business",
   "登录失败": "Login failed",
   "登录失败,请检查网络": "Login failed, please check your network",
-  "请联系管理员重置密码": "Please contact the administrator to reset your password",
-  "请输入用户名": "Please enter username",
-  "请输入密码": "Please enter password",
+  "否": "No",
+  "复制": "Copy",
+  "观看统计": "Watching Statistics",
+  "欢迎回来": "Welcome Back",
   "欢迎回来,这是您的数据概览": "Welcome back, here is your data overview",
+  "获取统计数据失败": "Failed to get statistics",
+  "机器管理": "Machine Management",
   "机器总数": "Total Machines",
-  "摄像头总数": "Total Cameras",
-  "通道总数": "Total Channels",
-  "摄像头在线率": "Camera Online Rate",
-  "已启用": "Enabled",
-  "已禁用": "Disabled",
-  "在线": "Online",
-  "离线": "Offline",
+  "机器ID": "",
+  "记住我": "Remember me",
+  "技术支持": "Support",
+  "截图": "Screenshot",
+  "仅在前端直接调用 API 时需要(不推荐)": "Only needed when directly calling the API in the frontend (not recommended)",
+  "静音": "Muted",
   "可用通道数量": "Available channels",
-  "系统运行正常": "System running normally",
   "快捷操作": "Quick Actions",
-  "刷新数据": "Refresh",
-  "系统信息": "System Info",
-  "系统状态": "System Status",
-  "数据更新时间": "Last Updated",
-  "版本": "Version",
-  "正常": "Normal",
-  "获取统计数据失败": "Failed to get statistics",
-  "Cloudflare Stream 配置": "Cloudflare Stream Configuration",
-  "播放域名的子域名部分": "The subdomain part of the playback domain",
-  "仅在前端直接调用 API 时需要(不推荐)": "Only needed when directly calling the API in the frontend (not recommended)",
-  "推荐通过后端代理调用,避免暴露 Token": "Recommended to call through the backend proxy to avoid exposing the Token",
-  "保存配置": "Save Configuration",
-  "测试连接": "Test Connection",
+  "快速测试": "Quick Test",
+  "离线": "Offline",
+  "两次输入的密码不一致": "The passwords entered twice do not match",
+  "吗?": "",
+  "密码": "Password",
+  "密码长度不能少于6位": "Password length must be at least 6 characters",
+  "描述": "",
+  "名称": "",
   "配置说明": "Configuration Description",
-  "如何获取 Customer Subdomain": "How to get Customer Subdomain",
-  "测试播放": "Test Playback",
-  "复制": "Copy",
-  "WebRTC 流": "WebRTC Stream",
-  "多视频监控": "Multi-Video Monitoring",
-  "新建标签": "New Tab",
-  "Stream 管理": "Stream Management",
-  "Video Test": "Video Test",
-  "直接 URL": "Direct URL",
-  "RTSP 流": "RTSP Stream",
-  "测试视频": "Test Video",
-  "M3U8/HLS": "M3U8/HLS",
-  "Stream": "Stream",
-  "Management": "Management",
-  "直接 URL 播放": "Direct URL Playback",
-  "播放": "Play",
+  "批量删除": "",
+  "批量删除失败": "",
+  "启用": "",
+  "启用状态": "",
   "清空": "Clear",
+  "请联系管理员重置密码": "Please contact the administrator to reset your password",
+  "请输入机器ID": "",
+  "请输入密码": "Please enter password",
+  "请输入名称": "",
   "请输入视频地址并点击播放": "Please enter video URL and click play",
-  "暂停": "Pause",
-  "停止": "Stop",
-  "截图": "Screenshot",
+  "请输入新密码": "Please enter the new password",
+  "请输入用户名": "Please enter username",
+  "请输入原密码": "Please enter the old password",
+  "请选择视频源并点击播放": "Please select video source and click play",
+  "请再次输入新密码": "Please enter the new password again",
+  "取消": "Cancel",
+  "取消选择": "",
   "全屏": "Fullscreen",
-  "静音": "Muted",
-  "有声": "Sound",
-  "自动播放": "Autoplay",
-  "手动": "Manual",
+  "确定": "Confirm",
+  "确定要删除机器": "",
+  "确定要删除选中的": "",
+  "确认密码": "Confirm Password",
+  "如何获取 Customer Subdomain": "How to get Customer Subdomain",
+  "删除": "",
+  "删除成功": "",
+  "删除失败": "",
+  "摄像头管理": "Camera Management",
+  "摄像头管理系统": "Camera Management",
+  "摄像头数": "",
+  "摄像头在线率": "Camera Online Rate",
+  "摄像头总数": "Total Cameras",
+  "生成地址": "Generate URL",
+  "生成的地址": "Generated URL",
   "事件日志": "Event Log",
-  "暂无日志": "No logs",
   "视频播放测试": "Video Playback Test",
   "视频地址": "Video URL",
-  "播放器类型": "Player Type",
-  "Cloudflare Stream": "Cloudflare Stream",
-  "Video ID": "Video ID",
-  "自定义域名": "Custom Domain",
-  "播放方式": "Playback Method",
-  "生成地址": "Generate URL",
-  "生成的地址": "Generated URL",
-  "转换服务地址": "Proxy Service URL",
-  "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放": "RTSP streams need to be converted to HLS/WebRTC via server before playing in browser",
+  "是": "Yes",
+  "手动": "Manual",
+  "数据更新时间": "Last Updated",
+  "刷新数据": "Refresh",
+  "台机器": "",
+  "台机器吗?": "",
+  "提示": "",
+  "停止": "Stop",
+  "通道总数": "Total Channels",
+  "推荐通过后端代理调用,避免暴露 Token": "Recommended to call through the backend proxy to avoid exposing the Token",
+  "退出登录": "Logout",
+  "忘记密码?": "Forgot password?",
+  "位置": "",
+  "稳定性": "Uptime",
+  "系统信息": "System Info",
+  "系统运行正常": "System running normally",
+  "系统状态": "System Status",
+  "项": "",
+  "新建标签": "New Tab",
+  "新密码": "New Password",
+  "新增": "",
+  "新增成功": "",
+  "新增机器": "",
+  "修改成功": "",
+  "修改密码": "Change Password",
   "选择测试源": "Select Test Source",
-  "播放测试视频": "Play Test Video",
-  "请选择视频源并点击播放": "Please select video source and click play",
-  "当前状态": "Current Status",
+  "仪表盘": "Dashboard",
+  "已禁用": "Disabled",
+  "已启用": "Enabled",
+  "已选择": "",
+  "用户": "Users",
+  "用户名": "Username",
+  "有声": "Sound",
+  "原密码": "Old Password",
+  "在线": "Online",
+  "暂停": "Pause",
+  "暂无日志": "No logs",
+  "正常": "Normal",
+  "直接 URL": "Direct URL",
+  "直接 URL 播放": "Direct URL Playback",
+  "重置": "",
+  "转换服务地址": "Proxy Service URL",
+  "自定义域名": "Custom Domain",
+  "自动播放": "Autoplay",
+  "Cloudflare Stream": "Cloudflare Stream",
+  "Cloudflare Stream 配置": "Cloudflare Stream Configuration",
   "iframe 模式": "iframe Mode",
-  "是": "Yes",
-  "否": "No",
-  "快速测试": "Quick Test"
+  "RTSP 地址": "",
+  "RTSP 流": "RTSP Stream",
+  "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放": "RTSP streams need to be converted to HLS/WebRTC via server before playing in browser",
+  "Stream 测试": "Stream Test",
+  "Video ID": "Video ID"
 }

+ 118 - 99
src/locales/zh-cn.json

@@ -1,118 +1,137 @@
 {
-  "摄像头管理系统": "摄像头管理系统",
-  "仪表盘": "仪表盘",
-  "机器管理": "机器管理",
-  "摄像头管理": "摄像头管理",
-  "用户管理": "用户管理",
-  "视频测试": "视频测试",
-  "Stream 测试": "Stream 测试",
-  "视频管理": "视频管理",
-  "直播管理": "直播管理",
-  "Stream 配置": "Stream 配置",
-  "审计日志": "审计日志",
-  "观看统计": "观看统计",
-  "修改密码": "修改密码",
-  "退出登录": "退出登录",
-  "原密码": "原密码",
-  "新密码": "新密码",
-  "确认密码": "确认密码",
-  "请再次输入新密码": "请再次输入新密码",
-  "密码长度不能少于6位": "密码长度不能少于6位",
-  "请输入原密码": "请输入原密码",
-  "请输入新密码": "请输入新密码",
-  "两次输入的密码不一致": "两次输入的密码不一致",
-  "取消": "取消",
-  "确定": "确定",
-  "欢迎回来": "欢迎回来",
-  "登录您的管理后台,开始管理您的业务": "登录您的管理后台,开始管理您的业务",
-  "用户": "用户",
-  "稳定性": "稳定性",
-  "技术支持": "技术支持",
+  "版本": "版本",
+  "保存配置": "保存配置",
+  "编辑": "编辑",
+  "编辑机器": "编辑机器",
+  "播放": "播放",
+  "播放测试视频": "播放测试视频",
+  "播放方式": "播放方式",
+  "播放器类型": "播放器类型",
+  "播放域名的子域名部分": "播放域名的子域名部分",
+  "操作": "操作",
+  "测试播放": "测试播放",
+  "测试连接": "测试连接",
+  "测试视频": "测试视频",
+  "查询": "查询",
+  "成功删除": "成功删除",
+  "创建时间": "创建时间",
+  "当前状态": "当前状态",
   "登录": "登录",
-  "用户名": "用户名",
-  "密码": "密码",
-  "记住我": "记住我",
-  "忘记密码?": "忘记密码?",
   "登录成功": "登录成功",
+  "登录您的管理后台,开始管理您的业务": "登录您的管理后台,开始管理您的业务",
   "登录失败": "登录失败",
   "登录失败,请检查网络": "登录失败,请检查网络",
-  "请联系管理员重置密码": "请联系管理员重置密码",
-  "请输入用户名": "请输入用户名",
-  "请输入密码": "请输入密码",
+  "否": "否",
+  "复制": "复制",
+  "观看统计": "观看统计",
+  "欢迎回来": "欢迎回来",
   "欢迎回来,这是您的数据概览": "欢迎回来,这是您的数据概览",
+  "获取统计数据失败": "获取统计数据失败",
+  "机器管理": "机器管理",
   "机器总数": "机器总数",
-  "摄像头总数": "摄像头总数",
-  "通道总数": "通道总数",
-  "摄像头在线率": "摄像头在线率",
-  "已启用": "已启用",
-  "已禁用": "已禁用",
-  "在线": "在线",
-  "离线": "离线",
+  "机器ID": "机器ID",
+  "记住我": "记住我",
+  "技术支持": "技术支持",
+  "截图": "截图",
+  "仅在前端直接调用 API 时需要(不推荐)": "仅在前端直接调用 API 时需要(不推荐)",
+  "静音": "静音",
   "可用通道数量": "可用通道数量",
-  "系统运行正常": "系统运行正常",
   "快捷操作": "快捷操作",
-  "刷新数据": "刷新数据",
-  "系统信息": "系统信息",
-  "系统状态": "系统状态",
-  "数据更新时间": "数据更新时间",
-  "版本": "版本",
-  "正常": "正常",
-  "获取统计数据失败": "获取统计数据失败",
-  "Cloudflare Stream 配置": "Cloudflare Stream 配置",
-  "播放域名的子域名部分": "播放域名的子域名部分",
-  "仅在前端直接调用 API 时需要(不推荐)": "仅在前端直接调用 API 时需要(不推荐)",
-  "推荐通过后端代理调用,避免暴露 Token": "推荐通过后端代理调用,避免暴露 Token",
-  "保存配置": "保存配置",
-  "测试连接": "测试连接",
-  "配置说明": "配置说明",
-  "如何获取 Customer Subdomain": "如何获取 Customer Subdomain",
-  "测试播放": "测试播放",
-  "复制": "复制",
-  "WebRTC 流": "WebRTC 流",
-  "多视频监控": "多视频监控",
-  "新建标签": "新建标签",
-  "Stream 管理": "Stream 管理",
-  "直接 URL": "直接 URL",
-  "RTSP 流": "RTSP 流",
-  "测试视频": "测试视频",
-  "M3U8/HLS": "M3U8/HLS",
-  "Stream": "Stream",
-  "Management": "Management",
-  "Video Management": "视频管理",
-  "Live Management": "直播管理",
-  "Stream Configuration": "Stream 配置",
   "快速测试": "快速测试",
-  "直接 URL 播放": "直接 URL 播放",
-  "播放": "播放",
+  "离线": "离线",
+  "两次输入的密码不一致": "两次输入的密码不一致",
+  "吗?": "吗?",
+  "密码": "密码",
+  "密码长度不能少于6位": "密码长度不能少于6位",
+  "描述": "描述",
+  "名称": "名称",
+  "配置说明": "配置说明",
+  "批量删除": "批量删除",
+  "批量删除失败": "批量删除失败",
+  "启用": "启用",
+  "启用状态": "启用状态",
   "清空": "清空",
+  "请联系管理员重置密码": "请联系管理员重置密码",
+  "请输入机器ID": "请输入机器ID",
+  "请输入密码": "请输入密码",
+  "请输入名称": "请输入名称",
   "请输入视频地址并点击播放": "请输入视频地址并点击播放",
-  "暂停": "暂停",
-  "停止": "停止",
-  "截图": "截图",
+  "请输入新密码": "请输入新密码",
+  "请输入用户名": "请输入用户名",
+  "请输入原密码": "请输入原密码",
+  "请选择视频源并点击播放": "请选择视频源并点击播放",
+  "请再次输入新密码": "请再次输入新密码",
+  "取消": "取消",
+  "取消选择": "取消选择",
   "全屏": "全屏",
-  "静音": "静音",
-  "有声": "有声",
-  "自动播放": "自动播放",
-  "手动": "手动",
+  "确定": "确定",
+  "确定要删除机器": "确定要删除机器",
+  "确定要删除选中的": "确定要删除选中的",
+  "确认密码": "确认密码",
+  "如何获取 Customer Subdomain": "如何获取 Customer Subdomain",
+  "删除": "删除",
+  "删除成功": "删除成功",
+  "删除失败": "删除失败",
+  "摄像头管理": "摄像头管理",
+  "摄像头管理系统": "摄像头管理系统",
+  "摄像头数": "摄像头数",
+  "摄像头在线率": "摄像头在线率",
+  "摄像头总数": "摄像头总数",
+  "生成地址": "生成地址",
+  "生成的地址": "生成的地址",
   "事件日志": "事件日志",
-  "暂无日志": "暂无日志",
   "视频播放测试": "视频播放测试",
   "视频地址": "视频地址",
-  "播放器类型": "播放器类型",
-  "Cloudflare Stream": "Cloudflare Stream",
-  "Video ID": "Video ID",
-  "自定义域名": "自定义域名",
-  "播放方式": "播放方式",
-  "生成地址": "生成地址",
-  "生成的地址": "生成的地址",
-  "转换服务地址": "转换服务地址",
-  "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放": "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放",
+  "是": "是",
+  "手动": "手动",
+  "数据更新时间": "数据更新时间",
+  "刷新数据": "刷新数据",
+  "台机器": "台机器",
+  "台机器吗?": "台机器吗?",
+  "提示": "提示",
+  "停止": "停止",
+  "通道总数": "通道总数",
+  "推荐通过后端代理调用,避免暴露 Token": "推荐通过后端代理调用,避免暴露 Token",
+  "退出登录": "退出登录",
+  "忘记密码?": "忘记密码?",
+  "位置": "位置",
+  "稳定性": "稳定性",
+  "系统信息": "系统信息",
+  "系统运行正常": "系统运行正常",
+  "系统状态": "系统状态",
+  "项": "项",
+  "新建标签": "新建标签",
+  "新密码": "新密码",
+  "新增": "新增",
+  "新增成功": "新增成功",
+  "新增机器": "新增机器",
+  "修改成功": "修改成功",
+  "修改密码": "修改密码",
   "选择测试源": "选择测试源",
-  "播放测试视频": "播放测试视频",
-  "请选择视频源并点击播放": "请选择视频源并点击播放",
-  "当前状态": "当前状态",
+  "仪表盘": "仪表盘",
+  "已禁用": "已禁用",
+  "已启用": "已启用",
+  "已选择": "已选择",
+  "用户": "用户",
+  "用户名": "用户名",
+  "有声": "有声",
+  "原密码": "原密码",
+  "在线": "在线",
+  "暂停": "暂停",
+  "暂无日志": "暂无日志",
+  "正常": "正常",
+  "直接 URL": "直接 URL",
+  "直接 URL 播放": "直接 URL 播放",
+  "重置": "重置",
+  "转换服务地址": "转换服务地址",
+  "自定义域名": "自定义域名",
+  "自动播放": "自动播放",
+  "Cloudflare Stream": "Cloudflare Stream",
+  "Cloudflare Stream 配置": "Cloudflare Stream 配置",
   "iframe 模式": "iframe 模式",
-  "是": "是",
-  "否": "否",
-  "Video Test": "视频测试"
+  "RTSP 地址": "RTSP 地址",
+  "RTSP 流": "RTSP 流",
+  "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放": "RTSP 流需要通过服务端转换为 HLS/WebRTC 后才能在浏览器播放",
+  "Stream 测试": "Stream 测试",
+  "Video ID": "Video ID"
 }

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio