Files
eryao/.trellis/tasks/04-28-feat-locale-timezone-bootstrap/prd.md
T

107 lines
3.6 KiB
Markdown

# PRD: App启动时语言和时区自动设置
## 背景
当前App启动时语言硬编码为 `zh`,不读取iOS系统语言;时区完全不处理。需要实现三种场景的自动设置逻辑。
## 需求
### 场景1:新用户首次打开App → 注册时写入后端
1. App无本地存储信息(首次打开)
2. 读取iOS系统语言和时区
3. 自动设置App界面语言和时区
4. 用户注册时,将语言和时区作为请求参数传给后端
5. 后端创建用户Profile时使用传入值
### 场景2:已有用户在新设备首次登录 → 从服务器同步
1. App无本地存储信息(新设备首次打开)
2. 读取iOS系统语言和时区作为临时值
3. 自动设置App界面语言和时区(临时)
4. 用户登录成功后,从服务器拉取Profile中的语言和时区
5. 用服务器值更新本地存储和App设置
### 场景3:有本地存储 → 使用本地值
1. App有本地存储的语言和时区信息
2. 直接使用本地值,不读取系统语言和时区
3. 登录后仍从服务器同步(确保一致性)
## 技术方案
### 前端
1. **读取系统语言**
- 使用 `PlatformDispatcher.instance.locale` 获取系统首选语言
- 通过 `resolveSystemLocale()` 映射到 App 支持的 Locale
2. **读取系统时区**
- 使用 `flutter_timezone` 包的 `getLocalTimezone()` 获取 IANA 时区 ID
- 直接使用返回值,后端会验证有效性
3. **本地存储扩展**
- `SessionStore` 新增 `saveTimezone()` / `getTimezone()`
- 现有 `saveLocaleTag()` / `getLocaleTag()` 已支持语言
4. **启动流程修改** (`app.dart:_bootstrap`)
```
if (本地有locale) {
使用本地locale
} else {
读取系统locale → 保存到本地
}
if (本地有时区) {
使用本地时区
} else {
读取系统时区 → 保存到本地
}
```
5. **注册请求扩展**
- `AuthApi.createEmailSession` 新增 `language` 和 `timezone` 参数
- `EmailSessionCreateRequest` schema 扩展
6. **登录后同步**
- 现有 `_refreshProfile()` 已同步语言
- 扩展同步时区
### 后端
1. **Schema扩展** (`v1/auth/schemas.py`)
```python
class EmailSessionCreateRequest(BaseModel):
email: str
token: str
language: str | None = None # BCP-47 tag
timezone: str | None = None # IANA timezone
```
2. **Service逻辑** (`v1/auth/service.py`)
- `create_email_session` 接收语言/时区
- 创建/更新Profile时使用传入值(如果提供)
3. **Profile默认值保持不变**
- `language: str = "zh-CN"`
- `timezone: str = "Asia/Shanghai"`
## 验收标准
1. 新设备首次打开App,界面语言与iOS系统语言一致
2. 新用户注册后,后端Profile的语言/时区与App一致
3. 已有用户登录后,App语言/时区与服务器Profile一致
4. 有本地存储时,App启动不请求系统语言/时区
5. 支持的语言映射:
- iOS `en` / `en-US` / `en-GB` → Flutter `Locale('en')` → 存储 `en-US`
- iOS `zh` / `zh-CN` / `zh-SG` / `zh-Hans-*` → Flutter `Locale('zh')` → 存储 `zh-CN`
- iOS `zh-Hant` / `zh-TW` / `zh-HK` / `zh-MO` → Flutter `Locale(zh, Hant)` → 存储 `zh-Hant`
6. 时区为有效IANA ID (如 `Asia/Shanghai`, `America/New_York`)
## 风险
1. iOS系统语言可能不在支持列表中 → 回退到 `zh-CN`
2. `flutter_timezone` 包可能返回无效时区 → 后端验证 + 前端回退默认值
3. 用户修改系统语言/时区后,App不会自动更新(符合场景3设计)
4. 新用户注册时网络请求失败 → Profile 使用后端默认值,用户可在设置中修改