# 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 使用后端默认值,用户可在设置中修改