diff --git a/desktop/src/__tests__/generalSettings.test.tsx b/desktop/src/__tests__/generalSettings.test.tsx
index 1a1df9dd..b7c98afc 100644
--- a/desktop/src/__tests__/generalSettings.test.tsx
+++ b/desktop/src/__tests__/generalSettings.test.tsx
@@ -1651,6 +1651,34 @@ describe('Settings > Providers tab', () => {
expect(within(dialog).getByText('Requests will be translated via the local proxy')).toBeInTheDocument()
})
+ it('localizes the main model placeholder in the provider form', () => {
+ useSettingsStore.setState({ locale: 'zh' })
+ providerStoreState.presets = [
+ {
+ id: 'custom',
+ name: 'Custom',
+ baseUrl: 'https://api.example.com/anthropic',
+ apiFormat: 'anthropic',
+ defaultModels: {
+ main: '',
+ haiku: '',
+ sonnet: '',
+ opus: '',
+ },
+ needsApiKey: true,
+ websiteUrl: '',
+ },
+ ]
+
+ render()
+
+ fireEvent.click(screen.getByRole('button', { name: /添加服务商/i }))
+
+ const dialog = screen.getByRole('dialog')
+ expect(within(dialog).getByPlaceholderText('模型 ID')).toBeInTheDocument()
+ expect(within(dialog).queryByPlaceholderText('Model ID')).not.toBeInTheDocument()
+ })
+
it('normalizes blank model mappings to the main model when saving a provider', async () => {
providerStoreState.createProvider = vi.fn().mockResolvedValue({
id: 'provider-new',
diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts
index 747bb0bd..ee0b4e3f 100644
--- a/desktop/src/i18n/locales/en.ts
+++ b/desktop/src/i18n/locales/en.ts
@@ -416,6 +416,7 @@ export const en = {
'settings.providers.sonnetModel': 'Sonnet Model',
'settings.providers.opusModel': 'Opus Model',
'settings.providers.model1mSupportShort': '1M',
+ 'settings.providers.modelIdPlaceholder': 'Model ID',
'settings.providers.sameAsMain': 'Same as main',
'settings.providers.contextSettingsTitle': 'Context and auto-compact',
'settings.providers.contextSettingsDesc': 'Preset limits are applied automatically. Edit only when the provider changes limits or you use a custom model ID.',
@@ -969,6 +970,12 @@ export const en = {
'settings.general.responseLangDefault': 'Default (English)',
'settings.general.outputStyleTitle': 'Output Style',
'settings.general.outputStyleDescription': 'Choose how Claude communicates in new or restarted sessions.',
+ 'settings.general.outputStyleBuiltin.default.label': 'Default',
+ 'settings.general.outputStyleBuiltin.default.description': 'Claude completes coding tasks efficiently and provides concise responses',
+ 'settings.general.outputStyleBuiltin.explanatory.label': 'Explanatory',
+ 'settings.general.outputStyleBuiltin.explanatory.description': 'Claude explains its implementation choices and codebase patterns',
+ 'settings.general.outputStyleBuiltin.learning.label': 'Learning',
+ 'settings.general.outputStyleBuiltin.learning.description': 'Claude pauses and asks you to write small pieces of code for hands-on practice',
'settings.general.outputStyleSelectLabel': 'Select output style',
'settings.general.outputStyleLoading': 'Loading output styles...',
'settings.general.outputStyleSaved': 'Output style saved.',
diff --git a/desktop/src/i18n/locales/jp.ts b/desktop/src/i18n/locales/jp.ts
index 40524ada..5c2f0c36 100644
--- a/desktop/src/i18n/locales/jp.ts
+++ b/desktop/src/i18n/locales/jp.ts
@@ -418,6 +418,7 @@ export const jp: Record = {
'settings.providers.sonnetModel': 'Sonnet モデル',
'settings.providers.opusModel': 'Opus モデル',
'settings.providers.model1mSupportShort': '1M',
+ 'settings.providers.modelIdPlaceholder': 'モデル ID',
'settings.providers.sameAsMain': 'メインと同じ',
'settings.providers.contextSettingsTitle': 'コンテキストと自動コンパクト',
'settings.providers.contextSettingsDesc': 'プリセットの上限は自動的に適用されます。プロバイダーが上限を変更した場合やカスタムモデル ID を使用する場合のみ編集してください。',
@@ -971,6 +972,12 @@ export const jp: Record = {
'settings.general.responseLangDefault': 'デフォルト(英語)',
'settings.general.outputStyleTitle': '出力スタイル',
'settings.general.outputStyleDescription': '新しいセッションまたは再起動後のセッションで Claude がどのように応答するかを選択します。',
+ 'settings.general.outputStyleBuiltin.default.label': 'デフォルト',
+ 'settings.general.outputStyleBuiltin.default.description': 'Claude はコーディングタスクを効率よく完了し、簡潔に応答します',
+ 'settings.general.outputStyleBuiltin.explanatory.label': '解説型',
+ 'settings.general.outputStyleBuiltin.explanatory.description': 'Claude は実装上の判断とコードベースのパターンを説明します',
+ 'settings.general.outputStyleBuiltin.learning.label': '学習型',
+ 'settings.general.outputStyleBuiltin.learning.description': 'Claude は一時停止し、実践練習として短いコードの記述を依頼します',
'settings.general.outputStyleSelectLabel': '出力スタイルを選択',
'settings.general.outputStyleLoading': '出力スタイルを読み込み中...',
'settings.general.outputStyleSaved': '出力スタイルを保存しました。',
diff --git a/desktop/src/i18n/locales/kr.ts b/desktop/src/i18n/locales/kr.ts
index 2ea02d90..ac1f5411 100644
--- a/desktop/src/i18n/locales/kr.ts
+++ b/desktop/src/i18n/locales/kr.ts
@@ -418,6 +418,7 @@ export const kr: Record = {
'settings.providers.sonnetModel': 'Sonnet 모델',
'settings.providers.opusModel': 'Opus 모델',
'settings.providers.model1mSupportShort': '1M',
+ 'settings.providers.modelIdPlaceholder': '모델 ID',
'settings.providers.sameAsMain': '메인과 동일',
'settings.providers.contextSettingsTitle': '컨텍스트 및 자동 압축',
'settings.providers.contextSettingsDesc': '사전 설정 한도가 자동으로 적용됩니다. 공급자가 한도를 변경하거나 사용자 지정 모델 ID를 사용할 때만 편집하세요.',
@@ -971,6 +972,12 @@ export const kr: Record = {
'settings.general.responseLangDefault': '기본값(영어)',
'settings.general.outputStyleTitle': '출력 스타일',
'settings.general.outputStyleDescription': '새 세션 또는 다시 시작한 세션에서 Claude가 응답하는 방식을 선택합니다.',
+ 'settings.general.outputStyleBuiltin.default.label': '기본값',
+ 'settings.general.outputStyleBuiltin.default.description': 'Claude가 코딩 작업을 효율적으로 완료하고 간결하게 응답합니다',
+ 'settings.general.outputStyleBuiltin.explanatory.label': '설명형',
+ 'settings.general.outputStyleBuiltin.explanatory.description': 'Claude가 구현 선택과 코드베이스 패턴을 설명합니다',
+ 'settings.general.outputStyleBuiltin.learning.label': '학습형',
+ 'settings.general.outputStyleBuiltin.learning.description': 'Claude가 잠시 멈추고 실습을 위해 짧은 코드를 작성하도록 요청합니다',
'settings.general.outputStyleSelectLabel': '출력 스타일 선택',
'settings.general.outputStyleLoading': '출력 스타일 불러오는 중...',
'settings.general.outputStyleSaved': '출력 스타일이 저장되었습니다.',
diff --git a/desktop/src/i18n/locales/zh-TW.ts b/desktop/src/i18n/locales/zh-TW.ts
index 2503af48..9332b9d9 100644
--- a/desktop/src/i18n/locales/zh-TW.ts
+++ b/desktop/src/i18n/locales/zh-TW.ts
@@ -418,6 +418,7 @@ export const zh: Record = {
'settings.providers.sonnetModel': 'Sonnet 模型',
'settings.providers.opusModel': 'Opus 模型',
'settings.providers.model1mSupportShort': '1M',
+ 'settings.providers.modelIdPlaceholder': '模型 ID',
'settings.providers.sameAsMain': '與主模型相同',
'settings.providers.contextSettingsTitle': '上下文與自動壓縮',
'settings.providers.contextSettingsDesc': '預設會自動應用模型視窗。只有服務商調整限制,或使用自定義模型 ID 時才需要修改。',
@@ -971,6 +972,12 @@ export const zh: Record = {
'settings.general.responseLangDefault': '預設(英語)',
'settings.general.outputStyleTitle': '輸出風格',
'settings.general.outputStyleDescription': '選擇 Claude 在新會話或重啟後的會話中如何表達。',
+ 'settings.general.outputStyleBuiltin.default.label': '預設',
+ 'settings.general.outputStyleBuiltin.default.description': 'Claude 會高效完成編碼任務,並提供簡潔回覆',
+ 'settings.general.outputStyleBuiltin.explanatory.label': '解釋型',
+ 'settings.general.outputStyleBuiltin.explanatory.description': 'Claude 會解釋實作選擇和程式碼庫模式',
+ 'settings.general.outputStyleBuiltin.learning.label': '學習型',
+ 'settings.general.outputStyleBuiltin.learning.description': 'Claude 會暫停並請你編寫小段程式碼進行實戰練習',
'settings.general.outputStyleSelectLabel': '選擇輸出風格',
'settings.general.outputStyleLoading': '正在載入輸出風格...',
'settings.general.outputStyleSaved': '輸出風格已儲存。',
diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts
index 1b5b096a..13bd6d07 100644
--- a/desktop/src/i18n/locales/zh.ts
+++ b/desktop/src/i18n/locales/zh.ts
@@ -418,6 +418,7 @@ export const zh: Record = {
'settings.providers.sonnetModel': 'Sonnet 模型',
'settings.providers.opusModel': 'Opus 模型',
'settings.providers.model1mSupportShort': '1M',
+ 'settings.providers.modelIdPlaceholder': '模型 ID',
'settings.providers.sameAsMain': '与主模型相同',
'settings.providers.contextSettingsTitle': '上下文与自动压缩',
'settings.providers.contextSettingsDesc': '预设会自动应用模型窗口。只有服务商调整限制,或使用自定义模型 ID 时才需要修改。',
@@ -971,6 +972,12 @@ export const zh: Record = {
'settings.general.responseLangDefault': '默认(英语)',
'settings.general.outputStyleTitle': '输出风格',
'settings.general.outputStyleDescription': '选择 Claude 在新会话或重启后的会话中如何表达。',
+ 'settings.general.outputStyleBuiltin.default.label': '默认',
+ 'settings.general.outputStyleBuiltin.default.description': 'Claude 会高效完成编码任务,并提供简洁回复',
+ 'settings.general.outputStyleBuiltin.explanatory.label': '解释型',
+ 'settings.general.outputStyleBuiltin.explanatory.description': 'Claude 会解释实现选择和代码库模式',
+ 'settings.general.outputStyleBuiltin.learning.label': '学习型',
+ 'settings.general.outputStyleBuiltin.learning.description': 'Claude 会暂停并请你编写小段代码进行实战练习',
'settings.general.outputStyleSelectLabel': '选择输出风格',
'settings.general.outputStyleLoading': '正在加载输出风格...',
'settings.general.outputStyleSaved': '输出风格已保存。',
diff --git a/desktop/src/pages/Settings.tsx b/desktop/src/pages/Settings.tsx
index cd1660a7..1b2cea19 100644
--- a/desktop/src/pages/Settings.tsx
+++ b/desktop/src/pages/Settings.tsx
@@ -83,6 +83,20 @@ const NETWORK_TIMEOUT_MIN_SECONDS = 30
const NETWORK_TIMEOUT_MAX_SECONDS = 1800
const NETWORK_TIMEOUT_STEP_SECONDS = 30
const SETTINGS_CHECKBOX_INPUT_CLASS = 'settings-checkbox-input peer'
+const BUILT_IN_OUTPUT_STYLE_TRANSLATION_KEYS = {
+ default: {
+ label: 'settings.general.outputStyleBuiltin.default.label',
+ description: 'settings.general.outputStyleBuiltin.default.description',
+ },
+ Explanatory: {
+ label: 'settings.general.outputStyleBuiltin.explanatory.label',
+ description: 'settings.general.outputStyleBuiltin.explanatory.description',
+ },
+ Learning: {
+ label: 'settings.general.outputStyleBuiltin.learning.label',
+ description: 'settings.general.outputStyleBuiltin.learning.description',
+ },
+} satisfies Record
function buildH5LaunchUrl(baseUrl: string | null, token: string | null): string | null {
if (!baseUrl) return null
@@ -1763,7 +1777,7 @@ function ProviderFormModal({ open, onClose, mode, provider, presets }: ProviderF
required={slot === 'main'}
value={models[slot]}
onChange={(e) => handleModelChange(slot, e.target.value)}
- placeholder={slot === 'main' ? 'Model ID' : t('settings.providers.sameAsMain')}
+ placeholder={slot === 'main' ? t('settings.providers.modelIdPlaceholder') : t('settings.providers.sameAsMain')}
/>