use axum::extract::State; use export::rest::AppResponseData; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; use crate::errors::ApiError; use crate::service::GitService; #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] pub struct LanguageOptionDto { /// BCP-47 代码(小写、`-` 分隔),如 `zh-cn`、`en`、`ja`。 pub code: String, /// 本语名称,如「简体中文」。 pub native_name: String, /// 英文名称,如 "Simplified Chinese"。 pub english_name: String, /// 是否为「沿用内容语言」模式。 pub auto: bool, /// 是否为部署时的缺省语言。 pub default: bool, } #[utoipa::path( get, path = "/ai/languages", tag = "ai", description = "AI 输出语言清单;前端据此渲染语言选择器。`auto` 表示沿用代码注释的语言。", responses( (status = 200, description = "supported languages", body = AppResponseData>) ) )] pub async fn list_ai_languages( State(service): State, ) -> Result>, ApiError> { let configured = ci_protocol::ai_languages::normalize(&service.state.config.ai.output_language); let options = ci_protocol::ai_languages::supported_codes() .into_iter() .map(|code| { let auto = ci_protocol::ai_languages::is_auto(code); let (native, english) = if auto { ("沿用内容语言".to_string(), "Match content".to_string()) } else { let display = ci_protocol::ai_languages::display_name(code); // display_name 形如「简体中文 (Simplified Chinese)」;拆回两段。 match display.split_once(" (") { Some((native, english)) => ( native.to_string(), english.trim_end_matches(')').to_string(), ), None => (display.clone(), display), } }; LanguageOptionDto { code: code.to_string(), native_name: native, english_name: english, auto, default: code == configured, } }) .collect(); Ok(AppResponseData::ok(options)) }