| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- ## 项目中英文转换逻辑说明
- ### 一、国际化(i18n)架构概述
- 本项目采用 **Vue I18n** 实现中英文双语切换,核心架构包含配置层、语言包层和组件调用层三个层次。
- ---
- ### 二、核心文件结构
- | 文件路径 | 功能说明 |
- |---------|---------|
- | `src/i18n.ts` | Vue I18n 核心配置,注册语言包 |
- | `src/i18n.d.ts` | TypeScript 类型定义文件 |
- | `src/locales/zh.json` | 中文语言包(键值对存储) |
- | `src/locales/en.json` | 英文语言包(与中文键结构一致) |
- | `src/locales/index.js` | 备用语言管理模块 |
- | `scripts/extract-i18n.js` | 自动提取国际化标记的脚本 |
- ---
- ### 三、中英文转换核心逻辑
- #### 3.1 配置初始化 (`src/i18n.ts`)
- ```typescript
- import { createI18n } from 'vue-i18n';
- import zh from './locales/zh.json';
- import en from './locales/en.json';
- const i18n = createI18n({
- legacy: false, // 使用 Composition API 模式
- locale: 'zh', // 默认语言:中文
- fallbackLocale: 'en', // 回退语言:英文
- messages: { zh, en }, // 语言包映射对象
- });
- export default i18n;
- ```
- **关键配置说明:**
- - `legacy: false` - 启用 Vue 3 Composition API 兼容模式
- - `locale` - 当前活跃语言标识
- - `fallbackLocale` - 当某个 key 在当前语言包不存在时,使用回退语言
- #### 3.2 语言包结构
- 语言包采用**嵌套 JSON 结构**,支持层级键路径:
- ```json
- // src/locales/zh.json
- {
- "Header": {
- "title": "土壤酸化智能预测专家系统",
- "welcome": "欢迎",
- "logout": "退出登录"
- },
- "login": {
- "userTitle": "用户登录",
- "loginButton": "登录",
- "loginFailed": "登录失败,请检查用户名或密码"
- },
- "validation": {
- "usernameRequired": "请输入账号",
- "passwordLength": "密码长度为 3 到 16 个字符"
- }
- }
- ```
- #### 3.3 组件调用方式
- **Vue 模板中的使用:**
- ```vue
- <template>
- <!-- 直接使用 t() 函数 -->
- <h2>{{ t('login.userTitle') }}</h2>
- <!-- 表单验证 -->
- <el-input :placeholder="t('validation.usernameRequired')" />
- <!-- 动态文本 -->
- <el-button>{{ t('login.loginButton') }}</el-button>
- </template>
- <script setup lang="ts">
- import { useI18n } from 'vue-i18n';
- const { t, locale } = useI18n();
- // 切换语言
- const toggleLanguage = () => {
- locale.value = locale.value === 'zh' ? 'en' : 'zh';
- localStorage.setItem('lang', locale.value);
- };
- </script>
- ```
- **TypeScript 文件中的使用:**
- ```typescript
- // 在组合式函数中使用
- import { useI18n } from 'vue-i18n';
- const { t } = useI18n();
- // 用于消息提示
- ElMessage.success(t('login.loginSuccess'));
- // 用于动态文本
- const errorMsg = t('login.loginFailed');
- ```
- ---
- ### 四、语言切换流程
- #### 4.1 完整切换流程(以登录页为例)
- ```typescript
- // src/views/login/loginView.vue
- const toggleLanguage = async () => {
- // 1. 计算新语言
- const newLocale = locale.value === "zh" ? "en" : "zh";
- // 2. 更新 Vue I18n locale(触发视图自动更新)
- locale.value = newLocale;
- // 3. 持久化到 localStorage(刷新页面保持语言设置)
- localStorage.setItem("lang", newLocale);
- // 4. 可选:同步到后端(保存用户语言偏好)
- try {
- await changeLanguageAPI({
- language: newLocale,
- userId: store.userInfo?.userId,
- timestamp: Date.now(),
- });
- } catch (error) {
- console.error("语言切换同步失败:", error);
- }
- };
- ```
- #### 4.2 初始化时的语言恢复
- 在应用启动时,从 localStorage 读取上次保存的语言:
- ```typescript
- // src/main.ts
- const savedLang = localStorage.getItem('lang') || 'zh';
- const i18n = createI18n({
- locale: savedLang,
- // ... 其他配置
- });
- ```
- ---
- ### 五、国际化标记提取脚本
- #### 5.1 脚本位置和功能
- **脚本文件:** `scripts/extract-i18n.js`
- **核心功能:**
- - 自动扫描 `.vue` 和 `.ts` 文件
- - 识别特定标记格式的中文文本
- - 自动生成/更新语言包文件
- #### 5.2 使用方法
- ```bash
- # 扫描整个 src 目录(默认)
- node scripts/extract-i18n.js
- # 扫描指定目录
- node scripts/extract-i18n.js src/views/User
- # 扫描单个文件
- node scripts/extract-i18n.js src/components/layout/AppLayout.vue
- ```
- #### 5.3 提取标记格式
- 在 Vue/TS 文件中使用以下格式标记需要国际化的文本:
- ```vue
- <!--i18n:模块名.键名-->中文文本内容
- ```
- **示例:**
- ```vue
- <!--i18n:Header.title-->土壤酸化智能预测专家系统
- <!--i18n:login.userTitle-->用户登录
- <!--i18n:Menu.dataManagement-->数据管理
- ```
- #### 5.4 脚本处理流程
- ```
- 1. 解析命令行参数 → 确定扫描路径
- 2. 读取已有语言包 → 保留历史翻译
- 3. 递归扫描文件 → 收集 .vue/.ts 文件
- 4. 正则匹配标记 → 提取键名和中文文本
- 5. 构建嵌套对象 → 处理键路径(如 Menu.subMenu.item)
- 6. 写入语言包 → 更新 zh.json 和 en.json
- ```
- #### 5.5 脚本核心代码解析
- **标记匹配正则:**
- ```javascript
- const regex = /<!--i18n:(\S+)-->([\u4e00-\u9fa5\w\s,.,。;;!!??::()()]+?)(?=\r?\n|['"<]|$)/g;
- ```
- **嵌套键设置函数:**
- ```javascript
- function setNestedValue(obj, keyPath, value) {
- const keys = keyPath.split('.');
- let current = obj;
- for (let i = 0; i < keys.length - 1; i++) {
- const key = keys[i];
- if (typeof current[key] === 'string') {
- console.warn(`键名冲突:"${key}" 已作为字符串存在`);
- return;
- }
- if (!current[key] || typeof current[key] !== 'object') {
- current[key] = {};
- }
- current = current[key];
- }
- const lastKey = keys[keys.length - 1];
- if (current[lastKey] === undefined) {
- current[lastKey] = value;
- }
- }
- ```
- ---
- ### 六、语言包维护规范
- | 规范项 | 说明 |
- |-------|------|
- | **键命名** | 使用 `模块名.子模块.键名` 格式,如 `Menu.dataManagement` |
- | **结构对齐** | 中英文语言包必须保持**完全相同的键结构** |
- | **值处理** | 中文包存储中文原文,英文包存储对应英文翻译 |
- | **新增翻译** | 同时在 `zh.json` 和 `en.json` 中添加键值对 |
- | **标记规范** | 使用 `<!--i18n:键名-->` 标记便于脚本提取 |
- | **避免硬编码** | 所有用户可见文本必须通过 `t()` 函数获取 |
- ---
- ### 七、现有翻译覆盖范围
- | 模块 | 说明 |
- |-----|------|
- | **Header** | 顶部导航栏文本 |
- | **login/register/logout** | 登录、注册、退出相关 |
- | **Menu** | 侧边栏菜单项 |
- | **validation** | 表单验证提示 |
- | **AcidModelMap** | 酸化模型地图相关 |
- | **PhPrediction** | pH 预测模型相关 |
- | **Calculation** | 计算模块相关 |
- | **DetectionStatistics** | 检测统计相关 |
- | **SoilCdStatistics** | 土壤镉统计相关 |
- | **LandCultivatedStatistics** | 耕地统计相关 |
- ---
- ### 八、Element Plus 组件国际化
- Element Plus 组件默认使用中文,如需支持英文需额外配置:
- ```typescript
- // src/main.ts
- import ElementPlus from 'element-plus';
- import zhCn from 'element-plus/es/locale/lang/zh-cn';
- import en from 'element-plus/es/locale/lang/en';
- // 根据当前语言动态切换 Element Plus 语言
- app.use(ElementPlus, {
- locale: locale.value === 'zh' ? zhCn : en,
- });
- ```
- ---
- ### 九、扩展说明
- #### 9.1 添加新翻译流程
- 1. **标记文本**:在 Vue/TS 文件中添加 `<!--i18n:键名-->` 标记
- 2. **运行脚本**:执行 `node scripts/extract-i18n.js` 提取标记
- 3. **翻译英文**:在 `en.json` 中填写对应英文翻译
- 4. **使用翻译**:在组件中使用 `t('键名')` 获取文本
- #### 9.2 语言切换事件通知
- 通过自定义事件通知其他组件语言变化:
- ```typescript
- // 触发语言切换事件
- window.dispatchEvent(new CustomEvent('languageChanged', {
- detail: { locale: locale.value }
- }));
- // 监听语言切换事件
- window.addEventListener('languageChanged', (e) => {
- console.log('语言已切换为:', e.detail.locale);
- });
- ```
|