📋 概述
本文档全面总结了芯图相册(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 - 语言持久化:语言设置存储在
ImageStorageService的app_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端英文界面:按内容、城市、颜色智能分类*
*移动端英文界面:首页自动显示按内容、按城市、按颜色分类的维度*
---
2.2 弹窗(Alert)国际化
#### 2.2.1 标准弹窗实现
基础用法:
#### 2.2.2 动态语言弹窗(重要)
问题场景:在异步回调(如 setInterval)中,t 函数可能使用的是闭包中的旧语言值。
解决方案:使用 i18n.t() 并显式指定语言参数:
实现位置:
src/screens/mobile/SettingsScreen.mobile.jssrc/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端英文界面:按内容、城市、颜色智能分类*
*移动端英文界面:按内容分类*
*移动端英文界面:按城市分类*
*移动端英文界面:按颜色分类*
---
🤖 智能检测信息的国际化
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端英文界面:照片预览以及信息查看*
*移动端英文界面:单照片预览*
*移动端英文界面:查看单照片的详细信息*
*移动端英文界面:照片相似组检测*
---
💻 原生代码和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端:
ImageStorageService→IndexedDB→settings.app_language - 移动端:
ImageStorageService→SQLite→settings.app_language
读取和保存:
---
7.2 组件实现一致性
#### 7.2.1 相同的翻译键
PC端和移动端使用相同的翻译键:
src/screens/desktop/HomeScreen.desktop.jssrc/screens/mobile/HomeScreen.mobile.js
两者都使用相同的翻译键,如:
home.readyhome.scanningcategory.noImagesimagePreview.detectionResult
#### 7.2.2 相同的实现模式
分类名称处理:
颜色名称翻译:
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端英文界面: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
维护者: 芯图相册开发团队