# IMPLEMENTATION_PLAN:统一语言设置 ## 前置条件 | 条件 | 状态 | |------|------| | 后端 Schema 定义清晰 | ✅ | | 前端 Model 定义清晰 | ✅ | | AI 运行时使用 `ai_language` | ✅ | | 协议文档存在 | ✅ | ## 实现步骤 ### Step 1: 更新协议文档 **文件**: `docs/protocols/profile/profile-protocol.md` - 将 `interface_language` 和 `ai_language` 合并为 `language` - 更新示例 JSON --- ### Step 2: 后端 Schema **文件**: `backend/src/schemas/shared/user.py` ```python class PreferenceSettings(BaseModel): language: str = "zh-CN" timezone: str = "Asia/Shanghai" country: str = "US" @field_validator("language") @classmethod def validate_language(cls, value: str) -> str: if not _BCP47_PATTERN.fullmatch(value): raise ValueError("language must be a valid BCP-47 tag") return value ``` --- ### Step 3: 后端 AI 运行时 **文件**: `backend/src/core/agentscope/runtime/runner.py` ```python # 第 268-276 行 language = "zh-CN" if user_context.settings is not None: prefs = getattr(user_context.settings, "preferences", None) if prefs is not None: language = getattr(prefs, "language", "zh-CN") or "zh-CN" system_prompt = build_system_prompt( agent_type=stage_config.agent_type, language=language, llm_config=stage_config.llm_config, tools=None, now_utc=datetime.now(timezone.utc), ) ``` --- ### Step 4: 后端 Prompt 构建 **文件**: `backend/src/core/agentscope/prompts/system_prompt.py` ```python def _build_output_rules(*, language: str) -> str: lang_label = _get_language_label(language) ... def build_system_prompt( *, agent_type: AgentType, language: str, llm_config: LlmConfig, tools: list[ToolSchema] | None, now_utc: datetime, ) -> str: ... _build_output_rules(language=language), ``` **文件**: `backend/src/core/agentscope/prompts/worker_rules.py` ```python def get_worker_role_playing(language: str) -> str: _ = language ... def get_worker_output_rules(language: str) -> str: if language.startswith("en"): ... ``` **文件**: `backend/src/core/agentscope/prompts/agent_prompt.py` ```python def build_agent_prompt( *, language: str = "zh-CN", ) -> str: role_playing = get_worker_role_playing(language) output_rules = get_worker_output_rules(language) ... ``` --- ### Step 5: 后端测试 **文件**: `backend/tests/unit/test_parse_profile_settings.py` - 字段名 `ai_language` → `language` - 字段名 `interface_language` → `language` **文件**: `backend/tests/unit/test_agentscope_prompts.py` - 参数名 `ai_language` → `language` --- ### Step 6: 数据库数据更新 直接用 Supabase MCP 执行 SQL(无需迁移脚本): ```sql UPDATE profiles SET settings = jsonb_set( settings - 'interface_language' - 'ai_language', '{preferences,language}', COALESCE( settings->'preferences'->>'interface_language', settings->'preferences'->>'ai_language', '"zh-CN"' )::jsonb ) WHERE settings->'preferences' ?| array['interface_language', 'ai_language']; ``` --- ### Step 7: 前端 Model **文件**: `apps/lib/features/settings/data/models/profile_settings.dart` ```dart class PreferenceSettings { const PreferenceSettings({ this.language = 'zh-CN', this.timezone = 'Asia/Shanghai', this.country = 'US', }); final String language; final String timezone; final String country; PreferenceSettings copyWith({ String? language, String? timezone, String? country, }) { return PreferenceSettings( language: language ?? this.language, timezone: timezone ?? this.timezone, country: country ?? this.country, ); } } // 更新 defaultsForLocale factory ProfileSettingsV1.defaultsForLocale(Locale locale) { final tag = languageTagFromLocale(locale); return ProfileSettingsV1( preferences: PreferenceSettings(language: tag), ); } ``` --- ### Step 8: 前端 API **文件**: `apps/lib/features/settings/data/apis/profile_api.dart` ```dart // 序列化 (第 45 行) 'language': settings.preferences.language, // 反序列化 (第 114 行) language: (preferencesRaw['language'] as String?) ?? 'zh-CN', ``` --- ### Step 9: 前端设置界面 **文件**: `apps/lib/features/settings/presentation/screens/general_settings_screen.dart` 移除第 75-95 行的 AI 语言 `SettingsMenuTile`,修改剩余的语言选项: ```dart SettingsMenuTile( icon: Icons.language_rounded, title: l10n.settingsLanguage, subtitle: displayLanguageLabel( l10n, _settings.preferences.language, ), tint: colors.primary, background: colors.surfaceContainerHighest, showDivider: false, onTap: () => _selectLanguage( _settings.preferences.language, (lang) => setState(() { _settings = _settings.copyWith( preferences: _settings.preferences.copyWith( language: lang, ), ); }), ), ), ``` --- ### Step 10: 前端 i18n **文件**: `apps/lib/l10n/app_zh.arb` ```diff - "settingsInterfaceLanguage": "界面语言", - "settingsAiLanguage": "AI回复语言", - "settingsAiLanguageHint": "该字段将对齐..." + "settingsLanguage": "语言", ``` **文件**: `apps/lib/l10n/app_en.arb` ```diff - "settingsInterfaceLanguage": "Interface Language", - "settingsAiLanguage": "AI Response Language", - "settingsAiLanguageHint": "This field will align..." + "settingsLanguage": "Language", ``` **文件**: `apps/lib/l10n/app_zh_hant.arb` ```diff - "settingsInterfaceLanguage": "介面語言", - "settingsAiLanguage": "AI 回覆語言", + "settingsLanguage": "語言", ``` --- ### Step 11: 重新生成 l10n ```bash cd apps && flutter gen-l10n ``` --- ### Step 12: 更新其他协议文档 **文件**: `docs/protocols/divination/divination-run-protocol.md` 第 240 行: ```diff - - Language rule: `conclusion`, `focus_points`, `advice`, `keywords`, `answer` should follow user `ai_language` preference unless user explicitly requests otherwise. + - Language rule: `conclusion`, `focus_points`, `advice`, `keywords`, `answer` should follow user `language` preference unless user explicitly requests otherwise. ``` --- ## 验证 ```bash # 后端 cd backend uv run pytest tests/unit/test_parse_profile_settings.py tests/unit/test_agentscope_prompts.py -v ./infra/scripts/dev-migrate.sh migrate # 前端 cd apps flutter gen-l10n flutter analyze ```