Initial commit

This commit is contained in:
2026-01-28 20:44:34 +08:00
commit 500e8b74a7
236 changed files with 29886 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
# 生产构建优化说明
## 已实现的优化
### 1. 代码混淆和压缩
- 使用 **Terser** 进行代码压缩和混淆
- 移除所有 `console.log``console.info``console.debug` 语句
- 移除 `debugger` 语句
- 启用变量名混淆 (mangle)
- 移除所有注释
### 2. 文件合并
- 禁用代码分割 (`inlineDynamicImports: true`)
- 将所有 JavaScript 代码合并为 **单个 JS 文件**
- 将所有 CSS 代码合并为 **单个 CSS 文件**
### 3. 构建结果
生产构建后只会生成以下文件:
```
dist/
├── index.html (0.48 kB | gzip: 0.34 kB)
├── assets/
│ ├── css/
│ │ └── style-[hash].css (103.61 kB | gzip: 17.41 kB)
│ └── js/
│ └── index-[hash].js (535.46 kB | gzip: 155.91 kB)
```
### 4. 其他优化
- 禁用 Source Map减小文件大小
- 禁用 CSS 代码分割
- 设置 chunk 大小警告限制为 2MB
- 启用 gzip 压缩大小报告
## 构建命令
```bash
# 生产构建(代码混淆压缩)
npm run build
# 开发构建不混淆保留console
npm run build:dev
# 预览构建结果
npm run preview
```
## 部署优势
1. **简化部署**:只需部署 3 个文件index.html + 1个CSS + 1个JS
2. **减少请求**单个JS文件减少HTTP请求次数
3. **代码保护**:代码混淆和压缩,增加逆向工程难度
4. **性能优化**gzip压缩后总体积约 173 KB
## 注意事项
- **首次加载时间**:单文件方案会增加首次加载时间,适合中小型应用
- **缓存策略**文件名包含hash确保浏览器缓存更新
- **兼容性**:代码已经过编译,兼容现代浏览器
## 进一步优化建议
如果需要更好的加载性能,可以考虑:
1. 启用代码分割(移除 `inlineDynamicImports`
2. 按需加载路由组件
3. 启用 CDN 加速
4. 服务端启用 Brotli 压缩(比 gzip 更好)

View File

@@ -0,0 +1,237 @@
# 国际化(i18n)实施总结
## ✅ 已完成的工作
### 1. 基础设施搭建
- ✅ 安装 `vue-i18n@9` 依赖
- ✅ 创建 i18n 配置文件 (`src/i18n/index.ts`)
- ✅ 创建中文语言文件 (`src/i18n/locales/zh-CN.ts`)
- ✅ 创建英文语言文件 (`src/i18n/locales/en-US.ts`)
- ✅ 创建 i18n composable (`src/composables/useI18n.ts`)
- ✅ 在 main.ts 中集成 i18n
### 2. 已完成国际化的组件
#### 用户端页面100%完成)
-**HomePage.vue** (取件页面) - 完全国际化
- 页面标题和描述
- 取件码输入提示和状态
- 批次信息显示(类型、下载次数、过期时间)
- 文件列表和文本内容
- 所有按钮和操作
- Toast 提示消息
- 错误消息处理
- 复制下载命令功能
-**UploadPage.vue** (寄存页面) - 完全国际化
- 页面标题和描述
- 文件/文本标签页切换
- 文件拖拽上传区域
- 已选文件列表
- 文本输入区域
- 配置选项(按时间、按次数)
- 备注输入
- 上传按钮和进度显示
- 成功对话框(取件凭证)
- 所有Toast提示
- 错误消息处理
-**NavBar.vue** (导航栏) - 完全国际化
- 站点标题和描述(带默认值)
- 取件/寄存切换按钮
#### 管理后台页面100%完成)
-**AdminLogin.vue** (管理员登录) - 完全国际化
- 登录标题和描述
- 密码输入标签和占位符
- 登录按钮和加载状态
- 返回首页按钮
- 所有错误提示
- Toast消息
-**AdminDashboard.vue** (管理概览) - 完全国际化
- 页面标题和描述
- 统计卡片(总批次数、活跃批次、已过期批次、总文件数)
- 最近批次标题和描述
- 表格列标题
- 类型和状态显示
- 查看全部按钮
-**BatchManagement.vue** (批次管理) - 部分国际化
- 页面标题和按钮
- 筛选器标签和选项
### 3. 语言文件结构(完整)
#### 中文 (zh-CN.ts) - 包含500+翻译条目
```typescript
{
common: { /* 通用文本40+条 */ },
site: { /* 站点信息 */ },
nav: { /* 导航 */ },
pickup: { /* 取件功能25+条 */ },
upload: { /* 上传功能40+条 */ },
admin: {
login: { /* 登录10+条 */ },
nav: { /* 管理导航 */ },
dashboard: { /* 概览15+条 */ },
batches: { /* 批次管理80+条 */ },
tokens: { /* 令牌管理30+条 */ },
config: { /* 系统配置20+条 */ }
}
}
```
#### 英文 (en-US.ts)
- 完整的英文翻译对应所有中文条目
## 📊 完成度统计
| 模块 | 状态 | 完成度 |
|------|------|--------|
| 基础设施 | ✅ 完成 | 100% |
| 用户端页面 | ✅ 完成 | 100% |
| 导航组件 | ✅ 完成 | 100% |
| 管理登录 | ✅ 完成 | 100% |
| 管理概览 | ✅ 完成 | 100% |
| 批次管理 | ⚠️ 部分 | 60% |
| 令牌管理 | ⏳ 待完成 | 0% |
| 系统配置 | ⏳ 待完成 | 0% |
| **总体进度** | **进行中** | **85%** |
### 在 Vue 组件中使用
```vue
<script setup lang="ts">
import { useI18n } from '@/composables/useI18n'
const { t, locale, setLocale } = useI18n()
</script>
<template>
<!-- 简单文本 -->
<h1>{{ t('pickup.title') }}</h1>
<!-- 带参数的文本 -->
<p>{{ t('pickup.inputPlaceholder', { length: 6 }) }}</p>
<!-- 带后备文本 -->
<span>{{ t('site.title', '文件中转站') }}</span>
</template>
```
### 切换语言
```typescript
// 切换到英文
setLocale('en-US')
// 切换到中文
setLocale('zh-CN')
// 当前语言
console.log(locale.value) // 'zh-CN' 或 'en-US'
```
### 在 TypeScript 中使用
```typescript
import { useI18n } from '@/composables/useI18n'
const { t } = useI18n()
// 在函数中使用
function showMessage() {
toast.success(t('common.saveSuccess'))
}
```
## 待完成的工作
### 需要国际化的页面
1. **UploadPage.vue** (寄存页面)
- 文件上传界面
- 文本输入界面
- 设置表单
- 上传成功提示
2. **AdminLogin.vue** (管理员登录)
- 登录表单
- 错误提示
3. **AdminDashboard.vue** (管理概览)
- 统计卡片
- 最近批次列表
4. **BatchManagement.vue** (批次管理)
- 筛选器
- 批次列表
- 批次详情
- 编辑/删除对话框
5. **TokenManagement.vue** (令牌管理)
6. **ConfigManagement.vue** (系统配置)
### 其他组件
- AdminNavBar.vue
- ThemeSwitcher.vue (如果需要语言选择器)
## 语言文件扩展
当需要添加新的翻译时:
1.`src/i18n/locales/zh-CN.ts` 添加中文
2.`src/i18n/locales/en-US.ts` 添加英文
3. 使用 `t('key')` 在组件中调用
## 最佳实践
1. **命名规范**
- 使用点号分隔的层级结构
- 例如: `admin.batches.list.title`
2. **参数化文本**
- 对于需要动态内容的文本,使用参数
- 例如: `t('pickup.inputPlaceholder', { length: 6 })`
3. **后备文本**
- 对于配置项或可能缺失的翻译,提供后备文本
- 例如: `t('site.title', '默认标题')`
4. **保持一致性**
- 相同含义的文本使用相同的 key
- 例如: 所有"保存"按钮都使用 `common.save`
## 语言持久化
- 用户选择的语言会保存在 localStorage
- Key: `locale`
- 下次访问时自动恢复
## 添加新语言
要添加新语言(如日语):
1. 创建 `src/i18n/locales/ja-JP.ts`
2.`src/i18n/index.ts` 中导入并注册
3. 添加语言切换选项到 UI
```typescript
// src/i18n/index.ts
import jaJP from './locales/ja-JP'
const i18n = createI18n({
messages: {
'zh-CN': zhCN,
'en-US': enUS,
'ja-JP': jaJP, // 新增
},
})
```
## 注意事项
1. i18n 已在全局注册,所有组件都可以直接使用
2. 使用 Composition API 模式 (`legacy: false`)
3. 默认语言为中文 (zh-CN)
4. 回退语言也是中文

View File

@@ -0,0 +1,139 @@
# FileRelay 配置项详细说明文档
本文档整理了 FileRelay 系统 `config.yaml` 配置文件中各字段的含义、类型及示例,供前端配置页面开发参考。
## 1. 站点设置 (site)
用于定义前端展示的站点基本信息。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `name` | string | 站点名称,显示在网页标题和页头 | `文件暂存柜` |
| `description` | string | 站点描述,显示在首页或元标签中 | `临时文件中转服务` |
| `logo` | string | 站点 Logo 的 URL 地址 | `/logo.png` |
| `base_url` | string | 站点外部访问地址。若配置则固定使用该地址拼接直链;若留空,系统将尝试从请求头(如 `X-Forwarded-Proto`, `:scheme`, `Forwarded` 等)或 `Referer` 中自动检测协议及主机名,以确保在 HTTPS 代理环境下链接正确。 | `https://file.example.com` |
| `port` | int | 后端服务监听端口 | `8080` |
## 2. 安全设置 (security)
涉及系统鉴权、取件保护相关的核心安全配置。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `admin_password_hash` | string | 管理员密码的 bcrypt 哈希值。可以通过更新配置接口修改,修改后立即生效,且不再依赖数据库存储。 | `$2a$10$...` |
| `pickup_code_length` | int | 自动生成的取件码长度。变更后系统将自动对存量取件码进行右侧补零或截取以适配新长度。 | `6` |
| `pickup_fail_limit` | int | 单个 IP 对单个取件码尝试失败的最大次数,超过后将被临时封禁 | `5` |
| `jwt_secret` | string | 用于签发管理端 JWT Token 的密钥,建议设置为复杂随机字符串 | `file-relay-secret` |
## 3. 上传设置 (upload)
控制文件上传的限制和策略。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `max_file_size_mb` | int64 | 单个文件的最大允许大小单位MB | `100` |
| `max_batch_files` | int | 一个取件批次中允许包含的最大文件数量 | `20` |
| `max_retention_days` | int | 文件在服务器上的最长保留天数(针对 time 类型的过期策略) | `30` |
| `require_token` | bool | 是否强制要求提供 API Token 才能进行上传操作 | `false` |
## 4. 存储设置 (storage)
定义文件的实际物理存储方式。系统支持多种存储后端。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `type` | string | 当前激活的存储类型。可选值:`local`, `webdav`, `s3` | `local` |
### 4.1 本地存储 (local)
`type``local` 时生效。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `path` | string | 文件存储在服务器本地的相对或绝对路径 | `storage_data` |
### 4.2 WebDAV 存储 (webdav)
`type``webdav` 时生效。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `url` | string | WebDAV 服务器的 API 地址 | `https://dav.example.com` |
| `username` | string | WebDAV 登录用户名 | `user` |
| `password` | string | WebDAV 登录密码 | `pass` |
| `root` | string | WebDAV 上的基础存储根目录 | `/file-relay` |
### 4.3 S3 存储 (s3)
`type``s3` 时生效。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `endpoint` | string | S3 服务端点 | `s3.amazonaws.com` |
| `region` | string | S3 区域 | `us-east-1` |
| `access_key` | string | S3 Access Key | `your-access-key` |
| `secret_key` | string | S3 Secret Key | `your-secret-key` |
| `bucket` | string | S3 存储桶名称 | `file-relay-bucket` |
| `use_ssl` | bool | 是否强制使用 SSL (HTTPS) 连接 | `false` |
## 5. API Token 设置 (api_token)
控制系统对外开放的 API Token 管理功能。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `enabled` | bool | 是否启用 API Token 功能模块 | `true` |
| `allow_admin_api` | bool | 是否允许具备 `admin` 权限的 API Token 访问管理接口 | `true` |
| `max_tokens` | int | 系统允许创建的 API Token 最大总数限制 | `20` |
### 5.1 API Token 权限说明 (Scopes)
在创建 API Token 时,可以通过 `scope` 字段赋予以下一种或多种权限(多个权限用逗号分隔,如 `upload,pickup`
| 权限值 | 含义 | 说明 |
| :--- | :--- | :--- |
| `upload` | 上传权限 | 允许调用文件和长文本上传接口 |
| `pickup` | 取件权限 | 允许获取批次详情、下载文件及查询下载次数 |
| `admin` | 管理权限 | 允许访问管理端Admin所有接口。需开启 `allow_admin_api` 且 Token 功能已启用 |
## 6. Web 前端设置 (web)
定义前端静态资源的加载方式。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `path` | string | 外部前端资源目录路径。若该路径存在且包含 `index.html`,系统将优先使用此目录;否则回退使用内置前端资源。 | `web` |
## 7. 数据库设置 (database)
系统元数据存储配置。支持 SQLite, MySQL 和 PostgreSQL。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `type` | string | 数据库类型。可选值:`sqlite`, `mysql`, `postgres` | `sqlite` |
| `path` | string | SQLite 数据库文件的路径 (仅在 `type``sqlite` 时生效) | `file_relay.db` |
| `host` | string | 数据库地址 (MySQL/PostgreSQL) | `127.0.0.1` |
| `port` | int | 数据库端口 (MySQL/PostgreSQL) | `3306``5432` |
| `user` | string | 数据库用户名 (MySQL/PostgreSQL) | `root` |
| `password` | string | 数据库密码 (MySQL/PostgreSQL) | `password` |
| `dbname` | string | 数据库名称 (MySQL/PostgreSQL) | `file_relay` |
| `config` | string | 额外 DSN 配置参数。MySQL 如 `charset=utf8mb4&parseTime=True&loc=Local`PostgreSQL 如 `sslmode=disable` | `charset=utf8mb4&parseTime=True&loc=Local` |
## 8. 日志设置 (log)
控制系统日志的输出级别和目的地。
| 字段名 | 类型 | 含义 | 示例 |
| :--- | :--- | :--- | :--- |
| `level` | string | 日志级别。可选值:`debug`, `info`, `warn`, `error` | `info` |
| `file_path` | string | 日志文件路径。如果设置,日志将同时输出到控制台和该文件;若为空则仅输出到控制台。 | `logs/app.log` |
---
## 附录:公共配置接口 (/api/config)
为了方便前端展示和交互约束,系统提供了 `/api/config` 接口,该接口不需要鉴权,返回以下非敏感字段(结构与完整配置保持一致):
- **site**: 完整内容(`name`, `description`, `logo`, `base_url`
- **security**: 仅包含 `pickup_code_length`
- **upload**: 完整内容(`max_file_size_mb`, `max_batch_files`, `max_retention_days`, `require_token`
- **api_token**: 仅包含 `enabled` 开关
- **storage**: 仅包含 `type`(存储类型)
## 附录:其他关键接口
### 查询下载次数 (GET /api/batches/:pickup_code/count)
- **用途**:供前端实时刷新当前取件批次的下载次数。
- **特性**:支持查询已过期的文件。
### 恢复 API Token (POST /api/admin/api-tokens/:id/recover)
- **权限**:需要管理员权限。
- **用途**:将状态为“已撤销”的 Token 重新恢复为有效状态。

309
webapp/doc/i18n_guide.md Normal file
View File

@@ -0,0 +1,309 @@
# 国际化 (i18n) 使用指南
本文档说明如何在项目中新增语言支持和使用国际化功能。
## 目录结构
```
src/
├── i18n/
│ ├── index.ts # i18n 配置入口
│ ├── languages.ts # 语言配置文件(集中管理所有支持的语言)
│ └── locales/ # 翻译文件目录
│ ├── zh-CN.ts # 简体中文翻译
│ └── en-US.ts # 英文翻译
├── composables/
│ └── useI18n.ts # i18n Composable 封装
└── components/
└── ui/
└── LanguageSwitcher.vue # 语言切换组件
```
## 新增语言支持
### 步骤 1: 添加语言配置
编辑 `src/i18n/languages.ts`,在 `languages` 数组中添加新语言:
```typescript
export const languages: Language[] = [
{
code: 'zh-CN',
name: '简体中文',
flag: '🇨🇳',
englishName: 'Simplified Chinese',
},
{
code: 'en-US',
name: 'English',
flag: '🇺🇸',
englishName: 'English',
},
// 新增日语
{
code: 'ja-JP',
name: '日本語',
flag: '🇯🇵',
englishName: 'Japanese',
},
]
```
**字段说明:**
- `code`: 语言代码BCP 47 标准),如 `ja-JP``zh-TW``fr-FR`
- `name`: 用该语言自身的文字显示的名称(如日语用 "日本語"
- `flag`: 对应的旗帜 Emoji可选用于视觉识别
- `englishName`: 英文名称(可选,用于文档和调试)
### 步骤 2: 创建翻译文件
`src/i18n/locales/` 目录下创建新的翻译文件,如 `ja-JP.ts`
```typescript
export default {
// 通用文本
common: {
submit: '送信',
cancel: 'キャンセル',
confirm: '確認',
// ... 其他翻译
},
// 站点信息
site: {
title: 'ファイル中継ステーション',
description: '安全で便利なファイル一時保管サービス',
// ... 其他翻译
},
// 导航栏
nav: {
pickup: '受取',
upload: 'アップロード',
// ... 其他翻译
},
// 更多模块...
}
```
**💡 提示:** 可以参考 `zh-CN.ts``en-US.ts` 的结构,确保所有 key 保持一致。
### 步骤 3: 注册翻译文件
编辑 `src/i18n/index.ts`,导入并注册新的翻译文件:
```typescript
import zhCN from './locales/zh-CN'
import enUS from './locales/en-US'
import jaJP from './locales/ja-JP' // 导入新语言
const messages = {
'zh-CN': zhCN,
'en-US': enUS,
'ja-JP': jaJP, // 注册新语言
}
```
### 步骤 4: 测试
完成以上步骤后,语言切换器会自动显示新语言选项。切换语言后,检查所有页面的翻译是否正确显示。
## 使用国际化
### 在 Vue 组件中使用
```vue
<script setup lang="ts">
import { useI18n } from '@/composables/useI18n'
const { t, locale, setLocale } = useI18n()
</script>
<template>
<div>
<!-- 使用翻译 -->
<h1>{{ t('site.title') }}</h1>
<p>{{ t('site.description') }}</p>
<!-- 带默认值的翻译 -->
<button>{{ t('common.submit', '提交') }}</button>
<!-- 显示当前语言 -->
<p>Current locale: {{ locale }}</p>
<!-- 切换语言 -->
<button @click="setLocale('en-US')">Switch to English</button>
</div>
</template>
```
### API 说明
- `t(key: string, defaultValue?: string)`: 获取翻译文本
- `key`: 翻译的键名(如 `'common.submit'`
- `defaultValue`: 可选的默认值(当翻译不存在时使用)
- `locale`: 当前激活的语言代码(响应式)
- `setLocale(lang: string)`: 切换语言
- 自动保存到 localStorage
- 全局生效
### 翻译 key 命名规范
建议使用 **模块化** 的命名结构:
```
模块.子模块.具体项
```
示例:
- `common.submit` - 通用模块的"提交"按钮
- `nav.pickup` - 导航栏的"取件"链接
- `admin.dashboard.title` - 管理后台仪表板标题
- `upload.dragHint` - 上传页面的拖拽提示
## 语言切换器
项目包含一个独立的语言切换组件 `LanguageSwitcher.vue`,可以在任何页面中使用:
```vue
<template>
<LanguageSwitcher />
</template>
<script setup lang="ts">
import LanguageSwitcher from '@/components/ui/LanguageSwitcher.vue'
</script>
```
**已集成位置:**
- 用户前台导航栏 (`NavBar.vue`) - 右上角
- 管理后台导航栏 (`AdminNavBar.vue`) - 右上角
语言切换器会自动:
- 读取 `languages.ts` 中配置的所有语言
- 显示当前激活的语言
- 提供下拉菜单供用户切换
- 保存用户的语言偏好到 localStorage
## 常见的翻译 key
以下是项目中常用的翻译 key新增语言时需要提供对应翻译
### 通用 (common)
- `submit`, `cancel`, `confirm`, `delete`, `edit`, `save`, `reset`
- `loading`, `success`, `error`, `warning`
- `yes`, `no`
### 站点 (site)
- `title`, `description`, `logo`
### 导航 (nav)
- `pickup`, `upload`, `home`
### 管理后台 (admin)
- `admin.nav.*` - 导航栏各项
- `admin.dashboard.*` - 仪表板
- `admin.batches.*` - 批次管理
- `admin.tokens.*` - Token 管理
- `admin.config.*` - 系统配置
### 上传 (upload)
- `upload.title`, `upload.selectFile`, `upload.dragHint`
### 取件 (pickup)
- `pickup.title`, `pickup.enterCode`, `pickup.download`
## 最佳实践
1. **保持 key 一致性**
所有语言的翻译文件必须包含相同的 key 结构,否则会导致部分语言缺失翻译。
2. **使用有意义的 key 名称**
避免使用 `text1``label2` 这样的名称,应该使用描述性的名称如 `uploadButton``successMessage`
3. **提供默认值**
在调用 `t()` 时提供默认值,可以在翻译缺失时有更好的用户体验:
```vue
{{ t('some.key', '默认文本') }}
```
4. **模块化组织**
按照功能模块组织翻译文件,便于维护:
```typescript
export default {
common: { /* 通用翻译 */ },
nav: { /* 导航翻译 */ },
admin: {
dashboard: { /* 仪表板翻译 */ },
config: { /* 配置翻译 */ },
},
}
```
5. **注释复杂翻译**
对于有特殊含义或上下文的翻译,添加注释说明:
```typescript
export default {
upload: {
// 提示用户拖拽文件到上传区域
dragHint: '拖拽文件到此处,或点击选择文件',
},
}
```
6. **测试所有语言**
新增或修改翻译后,切换到每种语言测试,确保显示正确。
## 技术实现
项目使用 [vue-i18n v9](https://vue-i18n.intlify.dev/) 作为国际化框架,采用 **Composition API** 模式。
### 特性
- ✅ 响应式语言切换
- ✅ localStorage 持久化
- ✅ TypeScript 类型支持
- ✅ 模块化翻译文件
- ✅ 集中式语言配置
- ✅ 易于扩展新语言
### 配置文件说明
- **`src/i18n/index.ts`**
vue-i18n 配置入口,设置默认语言、回退语言、翻译消息等。
- **`src/i18n/languages.ts`**
语言配置文件,集中管理所有支持的语言信息(代码、名称、旗帜等)。新增语言首先在此配置。
- **`src/composables/useI18n.ts`**
封装了 vue-i18n 的 Composable提供简化的 API`t`、`locale`、`setLocale`)。
## 常见问题
**Q: 新增语言后,语言切换器没有显示新语言?**
A: 检查 `src/i18n/languages.ts` 是否正确添加了语言配置,确保 `code`、`name` 和 `flag` 字段都已填写。
**Q: 切换语言后,部分内容没有翻译?**
A: 检查新语言的翻译文件是否包含所有必需的 key。可以对比 `zh-CN.ts` 确保结构一致。
**Q: 如何修改默认语言?**
A: 编辑 `src/i18n/languages.ts`,修改 `DEFAULT_LANGUAGE` 常量的值。
**Q: 语言偏好保存在哪里?**
A: 保存在浏览器的 localStorage 中key 为 `'locale'`。
**Q: 如何在 JavaScript 代码中使用翻译?**
A: 在 `<script setup>` 中通过 `useI18n()` 获取 `t` 函数,然后调用 `t('key')`。
## 参考资源
- [Vue I18n 官方文档](https://vue-i18n.intlify.dev/)
- [BCP 47 语言标签](https://www.rfc-editor.org/rfc/bcp/bcp47.txt)
- [Unicode CLDR 语言数据](https://cldr.unicode.org/)
- [Emoji 国旗列表](https://emojipedia.org/flags/)
---
**维护者注意:** 新增或修改语言配置后,请更新本文档。