芯图相册国际化技术实现总结

芯图相册国际化技术实现总结

📋 概述

本文档全面总结了芯图相册(XinTu Album)的国际化(i18n)技术实现方案,涵盖用户界面、动态内容、原生代码和跨平台一致性等各个方面。

技术栈

  • i18n 库: i18next + react-i18next
  • 支持语言: 中文(zh)、英文(en)
  • 存储方案: 语言设置存储在 ImageStorageService 中,统一管理应用配置
  • 平台支持: PC端(Electron)和移动端(React Native Android)

---

🏗️ 基本实现方案

1.1 核心架构

#### 1.1.1 i18n 初始化配置

文件位置: src/i18n/index.js

关键特性

  • 同步初始化:使用 getSavedLanguageSync() 同步读取语言设置,确保应用启动时语言正确
  • 异步加载:应用启动后通过 loadSavedLanguage() 异步加载保存的语言设置,支持 react-native-localize
  • 语言持久化:语言设置存储在 ImageStorageServiceapp_language 字段中

#### 1.1.2 语言检测机制

系统语言检测

1. Web/Desktop 环境

2. React Native 环境

语言设置管理

  • 读取getCurrentLanguageAsync() - 从 ImageStorageService 读取保存的语言设置
  • 保存changeLanguage(lng) - 保存语言设置到 ImageStorageService 并切换 i18n 语言
  • 验证:切换语言后会验证保存是否成功,确保数据一致性

---

1.2 翻译资源组织

文件结构

命名空间

  • common: 通用翻译命名空间(默认)
  • 所有翻译键都使用 common 命名空间,通过 useTranslation('common') 使用

翻译键命名规范

  • app.*: 应用基础信息(如 app.name
  • home.*: 首页相关翻译(如 home.ready, home.scanning
  • category.*: 分类相关翻译(如 category.noImages
  • imagePreview.*: 图片预览相关翻译(如 imagePreview.detectionResult
  • settings.*: 设置页面相关翻译(如 settings.memberActivated
  • common.*: 通用翻译(如 common.success, common.cancel

---

🎨 用户可见界面信息的国际化

2.1 界面基础文本国际化

#### 2.1.1 React 组件中的使用

标准用法

关键 API

  • t(key, options): 翻译函数,根据当前语言返回对应的翻译文本
  • i18n.language: 获取当前语言代码('zh' 或 'en')
  • i18n.t(key, { lng: 'en' }): 指定语言进行翻译(用于动态切换)

#### 2.1.2 常见界面元素翻译

| 翻译键 | 中文 | 英文 | 使用位置 |

|--------|------|------|----------|

| app.name | 芯图相册 | Xintu Album | 应用标题 |

| home.ready | 图片分类应用已就绪 | Image classification app is ready | 首页状态 |

| home.scanning | 扫描中... | Scanning... | 扫描状态 |

| home.scanComplete | 扫描完成 | Scan complete | 扫描完成提示 |

| home.smartScan | 智能扫描 | Smart Scan | 扫描按钮 |

| category.noImages | 暂无图片 | No images | 空状态提示 |

| common.success | 成功 | Success | 通用成功提示 |

| common.cancel | 取消 | Cancel | 取消按钮 |

英文界面效果展示

PC端英文首页

*PC端英文界面:按内容、城市、颜色智能分类*

移动端英文首页

*移动端英文界面:首页自动显示按内容、按城市、按颜色分类的维度*

---

2.2 弹窗(Alert)国际化

#### 2.2.1 标准弹窗实现

基础用法

#### 2.2.2 动态语言弹窗(重要)

问题场景:在异步回调(如 setInterval)中,t 函数可能使用的是闭包中的旧语言值。

解决方案:使用 i18n.t() 并显式指定语言参数:

实现位置

  • src/screens/mobile/SettingsScreen.mobile.js
  • src/screens/desktop/SettingsScreen.desktop.js

关键代码

---

🌍 城市信息的国际化

3.1 实现策略

核心原则:在扫描时根据用户语言配置保存对应语言的城市名称,而不是在显示时翻译。

#### 3.1.1 数据来源

1. 远程API(优先):

  • 返回字段:name(英文)、name_zh(中文)、admin1(省份英文)、admin1_zh(省份中文)
  • API: https://api.bigdatacloud.net/data/reverse-geocode-client

2. 本地数据(降级):

  • 仅包含中文城市名称
  • 文件:src/data/cities.json

#### 3.1.2 JavaScript 实现

文件位置: src/services/CityLocationService.js

关键方法

远程API调用

使用位置: src/services/GalleryScannerService.js

#### 3.1.3 Android 原生实现

文件位置: android/app/src/main/java/com/imageclassifier/v2/GalleryScanService.java

关键代码(第839-866行):

语言参数来源

  • Android 原生代码从 ImageStorageService 读取 app_language 设置
  • 在扫描时传递语言参数给城市查询方法

---

3.2 显示逻辑

直接显示:城市名称在扫描时已根据用户语言配置保存,显示时直接使用数据库中存储的值,无需额外翻译。

注意事项

  • 已存储的数据不会自动更新:如果用户切换语言,已扫描的图片的城市名称不会自动更新,需要重新扫描
  • 降级处理:如果远程API失败,降级到本地查询时只能保存中文名称(本地数据只有中文)
  • 缓存机制:使用包含语言的缓存键,确保不同语言的结果分别缓存

---

📂 内容类别信息的国际化

4.1 实现策略

核心原则:从配置文件中读取中英文名称,动态选择显示,而不是存储在 i18n JSON 文件中。

#### 4.1.1 数据来源

配置文件: public/initialSettings.json

#### 4.1.2 JavaScript 实现

文件位置: src/services/ConfigService.js

关键方法

使用位置: src/screens/desktop/HomeScreen.desktop.js

图片预览页面: src/screens/desktop/ImagePreviewScreen.desktop.js

---

4.2 设计优势

1. 单一数据源:分类名称只在一个地方维护(initialSettings.json),避免重复

2. 自动回退:如果首选语言不存在,自动使用另一种语言

3. 灵活性:支持动态添加新分类,只需更新配置文件

4. 性能优化:不需要在 i18n JSON 中维护大量分类名称

分类信息国际化效果展示

PC端英文分类

*PC端英文界面:按内容、城市、颜色智能分类*

移动端英文分类-内容

*移动端英文界面:按内容分类*

移动端英文分类-城市

*移动端英文界面:按城市分类*

移动端英文分类-颜色

*移动端英文界面:按颜色分类*

---

🤖 智能检测信息的国际化

5.1 扫描进度消息

#### 5.1.1 实现位置

JavaScript 版本: src/services/GalleryScannerService.js

Android 原生版本: src/services/GalleryScannerService.android.js

#### 5.1.2 翻译键定义

| 翻译键 | 中文 | 英文 |

|--------|------|------|

| home.scanProgress.initScanning | 初始化扫描: 准备扫描环境 | Initializing scan: Preparing scan environment |

| home.scanProgress.scanningFiles | 扫描文件: {{processed}}/{{total}} | Scanning files: {{processed}}/{{total}} |

| home.scanProgress.categoryQuery | 查询分类: {{processed}}/{{total}} | Querying categories: {{processed}}/{{total}} |

| home.scanProgress.smartRecognitionStart | 开始智能识别 {{count}} 张图片 | Starting smart recognition for {{count}} images |

| home.scanProgress.smartRecognition | 智能识别: {{processed}}/{{total}} | Smart recognition: {{processed}}/{{total}} |

| home.scanProgress.localRecognitionStart | 开始本地识别 {{count}} 张图片 | Starting local recognition for {{count}} images |

| home.scanProgress.localRecognition | 本地识别: {{processed}}/{{total}} | Local recognition: {{processed}}/{{total}} |

| home.scanProgress.locationEnrichmentStart | 开始位置信息丰富 {{count}} 张图片 | Starting location enrichment for {{count}} images |

| home.scanProgress.locationEnrichment | 位置信息丰富: {{processed}}/{{total}} | Location enrichment: {{processed}}/{{total}} |

| home.scanProgress.similarityDetectionStart | 开始相似度检测 | Starting similarity detection |

| home.scanProgress.similarityDetectionProgress | 相似度检测: {{processed}}/{{total}} ({{groups}} 组) | Similarity detection: {{processed}}/{{total}} ({{groups}} groups) |

| home.scanProgress.removingFiles | 移除文件: {{count}} | Removing files: {{count}} |

| home.scanProgress.completed | 扫描完成 | Scan completed |

#### 5.1.3 实现示例

JavaScript 版本

Android 原生版本(类似实现,但支持更多阶段):

扫描进度消息国际化效果展示

移动端扫描进度

*移动端英文界面:照片扫描进展显示*

---

5.2 检测结果标签

#### 5.2.1 翻译键定义

| 翻译键 | 中文 | 英文 |

|--------|------|------|

| imagePreview.detectionResult | 检测结果 | Detection Result |

| imagePreview.classificationComplete | 分类完成 | Classification Complete |

| imagePreview.objects | 个对象 | objects |

| imagePreview.idCardDetection | 身份证检测 | ID Card Detection |

| imagePreview.idCardFront | 身份证正面 | ID Card Front |

| imagePreview.idCardBack | 身份证背面 | ID Card Back |

| imagePreview.generalDetection | 通用物体检测 | General Object Detection |

| imagePreview.uncategorizedCategory | 未分类 | Uncategorized |

| imagePreview.unknownCategoryName | 未知分类 | Unknown Category |

#### 5.2.2 使用示例

文件位置: src/screens/desktop/ImagePreviewScreen.desktop.js

检测结果国际化效果展示

PC端照片预览

*PC端英文界面:照片预览以及信息查看*

移动端照片预览

*移动端英文界面:单照片预览*

移动端照片详细信息

*移动端英文界面:查看单照片的详细信息*

移动端相似照片检测

*移动端英文界面:照片相似组检测*

---

💻 原生代码和JS代码的国际化

6.1 JavaScript 代码国际化

#### 6.1.1 标准实现

导入和使用

#### 6.1.2 异步语言获取

场景:在非 React 组件中(如 Service 类)需要获取当前语言。

实现

---

6.2 Android 原生代码国际化

#### 6.2.1 语言参数传递

实现位置: android/app/src/main/java/com/imageclassifier/v2/GalleryScanService.java

关键步骤

1. 读取语言设置

2. 传递语言参数

3. 根据语言返回对应文本

#### 6.2.2 原生代码限制

当前实现

  • 城市名称:原生代码根据语言设置返回对应语言的城市名称
  • 国家名称:根据语言返回 "China" 或 "中国"
  • 其他文本:原生代码中的其他文本(如错误消息)目前未国际化

未来改进建议

  • 考虑使用 Android 的 Resources 系统进行国际化
  • 或者将更多文本逻辑移到 JavaScript 层处理

---

🔄 PC端和移动端国际化的一致性

7.1 共享配置

#### 7.1.1 统一的 i18n 配置

文件位置: src/i18n/index.js

关键特性

  • 跨平台兼容:使用 compatibilityJSON: 'v3' 确保 React Native 兼容性
  • 统一语言资源:PC端和移动端使用相同的翻译文件
  • 统一语言设置:语言设置存储在 ImageStorageService 中,PC端使用 IndexedDB,移动端使用 SQLite

#### 7.1.2 统一的语言设置管理

存储方案

  • PC端: ImageStorageServiceIndexedDBsettings.app_language
  • 移动端: ImageStorageServiceSQLitesettings.app_language

读取和保存

---

7.2 组件实现一致性

#### 7.2.1 相同的翻译键

PC端和移动端使用相同的翻译键

  • src/screens/desktop/HomeScreen.desktop.js
  • src/screens/mobile/HomeScreen.mobile.js

两者都使用相同的翻译键,如:

  • home.ready
  • home.scanning
  • category.noImages
  • imagePreview.detectionResult

#### 7.2.2 相同的实现模式

分类名称处理

颜色名称翻译

PC端和移动端国际化一致性展示

PC端分类展示

*PC端英文界面:按内容、城市、颜色智能分类*

移动端分类展示

*移动端英文界面:首页自动显示按内容、按城市、按颜色分类的维度*

PC端格式分类

*PC端英文界面:照片自动按存储、格式、分辨率分类*

移动端格式分类

*移动端英文界面:照片按格式、分辨率和拍摄方向分类*

---

7.3 数据一致性

#### 7.3.1 城市信息

PC端和移动端

  • ✅ 使用相同的 CityLocationService
  • ✅ 使用相同的远程API和本地数据
  • ✅ 根据相同的语言设置保存城市名称

城市信息国际化效果展示

移动端城市分类

*移动端英文界面:照片按城市分类*

#### 7.3.2 分类信息

PC端和移动端

  • ✅ 使用相同的 ConfigService
  • ✅ 读取相同的 initialSettings.json
  • ✅ 使用相同的分类名称映射逻辑

分类信息一致性展示

移动端社交活动分类

*移动端英文界面:照片社交活动类别浏览*

---

🔧 动态内容的处理方案

8.1 服务器返回内容的国际化

#### 8.1.1 颜色名称翻译

问题:服务器API返回的颜色名称可能是中文或英文,需要根据用户语言设置翻译。

解决方案:使用颜色名称映射表。

实现位置: src/i18n/index.js

使用位置: src/screens/desktop/HomeScreen.desktop.js

#### 8.1.2 方向名称翻译

类似实现:使用方向名称映射表。

实现位置: src/i18n/index.js

---

8.2 动态消息的国际化

#### 8.2.1 带参数的翻译

实现:使用 i18n 的插值功能。

#### 8.2.2 AI 描述消息

问题:AI 返回的描述消息可能是中文或英文,需要根据用户语言设置处理。

当前实现

  • AI 描述消息直接显示,不做翻译(因为 AI 本身会根据上下文生成对应语言的描述)
  • 如果 AI 返回的消息不符合用户语言设置,可能需要改进 AI 提示词

未来改进建议

  • 在 AI 请求时传递语言参数,确保返回对应语言的描述
  • 或者在后端进行翻译

---

📝 最佳实践总结

9.1 翻译键命名规范

1. 使用有意义的命名空间home.*, category.*, imagePreview.*

2. 使用描述性的键名home.scanComplete 而不是 home.msg1

3. 保持一致性:PC端和移动端使用相同的翻译键

9.2 动态内容处理

1. 服务器返回内容:使用映射表进行翻译(如颜色名称、方向名称)

2. 配置数据:从配置文件读取中英文名称,动态选择(如分类名称)

3. 扫描时保存:根据用户语言设置保存对应语言的数据(如城市名称)

9.3 语言设置管理

1. 统一存储:使用 ImageStorageService 统一管理语言设置

2. 异步读取:在 Service 类中使用 getCurrentLanguageAsync() 异步读取

3. 验证保存:切换语言后验证保存是否成功

9.4 弹窗和异步回调

1. 使用当前语言:在异步回调中使用 i18n.t(key, { lng: currentLang }) 而不是闭包中的 t 函数

2. 显式指定语言:确保使用最新的语言值

功能操作国际化效果展示

PC端批量操作

*PC端英文界面:照片批量选择*

移动端批量操作

*移动端英文界面:照片批量选中*

PC端AI修图

*PC端英文界面:AI修图-色彩优化(一键操作)*

移动端AI修图

*移动端英文界面:单照片AI修图-处理中*

---

🚀 未来改进建议

10.1 已实现功能

  • ✅ 基础界面文本国际化
  • ✅ 弹窗国际化(包括动态语言切换)
  • ✅ 城市信息国际化(扫描时保存)
  • ✅ 分类信息国际化(配置文件读取)
  • ✅ 智能检测信息国际化(扫描进度、检测结果)
  • ✅ 颜色名称翻译(映射表)
  • ✅ 方向名称翻译(映射表)
  • ✅ PC端和移动端一致性

10.2 待改进功能

1. 城市名称映射表

  • 考虑创建城市名称映射表,支持已存储数据的国际化显示
  • 避免重新扫描才能看到对应语言的城市名称

2. Android 原生代码国际化

  • 使用 Android Resources 系统进行更全面的国际化
  • 或者将更多文本逻辑移到 JavaScript 层

3. AI 描述消息

  • 在 AI 请求时传递语言参数
  • 确保返回对应语言的描述

4. 日期格式化

  • 使用 i18n 的日期格式化功能
  • 统一日期显示格式

5. 数字格式化

  • 根据语言设置格式化数字(如千位分隔符)

---

📚 相关文件清单

核心文件

  • src/i18n/index.js - i18n 配置和工具函数
  • src/i18n/locales/zh/common.json - 中文翻译资源
  • src/i18n/locales/en/common.json - 英文翻译资源

服务文件

  • src/services/ImageStorageService.js - 语言设置存储
  • src/services/CityLocationService.js - 城市信息国际化
  • src/services/ConfigService.js - 分类信息国际化
  • src/services/GalleryScannerService.js - 扫描进度消息国际化

原生代码

  • android/app/src/main/java/com/imageclassifier/v2/GalleryScanService.java - Android 原生城市信息国际化

配置文件

  • public/initialSettings.json - 分类名称配置

---

📖 参考资料

---

文档版本: 1.0.0

最后更新: 2025-01-20

维护者: 芯图相册开发团队

← 返回日记列表