Skip to content

Commit 5d8172a

Browse files
brownrw8ellipsis-dev[bot]saoudrizwan
authored andcommitted
feat: Set preferred language in settings and have it update system prompt (RooCodeInc#1538)
* feat: set preferred language in settings and have it update system prompt * Update webview-ui/src/components/settings/PreferredLanguagePicker.tsx Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * remove unnecessary useEffect * tweak prompt * formatting from main * Update Cline.ts * Revert "Update Cline.ts" This reverts commit bee6f0fee0b0783293aa035e566978589fe837d6. * Fixes * Update Cline.ts * move preferredLanguage to Advanced Settings * remove unneccessary import * remove more imports * skip language prompt for default language `en` * Update package.json * lint --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Saoud Rizwan <[email protected]>
1 parent 916660a commit 5d8172a

File tree

7 files changed

+132
-2
lines changed

7 files changed

+132
-2
lines changed

.changeset/proud-camels-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": minor
3+
---
4+
5+
Add preferred language option to settings

package.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,31 @@
182182
"default": null,
183183
"description": "Path to Chrome executable for browser use functionality. If not set, the extension will attempt to find or download it automatically."
184184
},
185+
"cline.preferredLanguage": {
186+
"type": "string",
187+
"enum": [
188+
"English",
189+
"Arabic - العربية",
190+
"Portuguese - Português (Brasil)",
191+
"Czech - Čeština",
192+
"French - Français",
193+
"German - Deutsch",
194+
"Hindi - हिन्दी",
195+
"Hungarian - Magyar",
196+
"Italian - Italiano",
197+
"Japanese - 日本語",
198+
"Korean - 한국어",
199+
"Polish - Polski",
200+
"Portuguese - Português (Portugal)",
201+
"Russian - Русский",
202+
"Simplified Chinese - 简体中文",
203+
"Spanish - Español",
204+
"Traditional Chinese - 繁體中文",
205+
"Turkish - Türkçe"
206+
],
207+
"default": "English",
208+
"description": "The language that Cline should use for communication."
209+
},
185210
"cline.mcpMarketplace.enabled": {
186211
"type": "boolean",
187212
"default": true,

src/core/Cline.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import { formatResponse } from "./prompts/responses"
5959
import { addUserInstructions, SYSTEM_PROMPT } from "./prompts/system"
6060
import { getNextTruncationRange, getTruncatedMessages } from "./sliding-window"
6161
import { ClineProvider, GlobalFileNames } from "./webview/ClineProvider"
62+
import { DEFAULT_LANGUAGE_SETTINGS, getLanguageKey, LanguageDisplay, LanguageKey } from "../shared/Languages"
6263

6364
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) ?? path.join(os.homedir(), "Desktop") // may or may not exist but fs checking existence would immediately ask for permission which would be bad UX, need to come up with a better solution
6465

@@ -75,6 +76,7 @@ export class Cline {
7576
browserSession: BrowserSession
7677
private didEditFile: boolean = false
7778
customInstructions?: string
79+
preferredLanguage?: LanguageKey
7880
autoApprovalSettings: AutoApprovalSettings
7981
private browserSettings: BrowserSettings
8082
private chatSettings: ChatSettings
@@ -135,6 +137,9 @@ export class Cline {
135137
this.browserSession = new BrowserSession(provider.context, browserSettings)
136138
this.diffViewProvider = new DiffViewProvider(cwd)
137139
this.customInstructions = customInstructions
140+
this.preferredLanguage = getLanguageKey(
141+
vscode.workspace.getConfiguration("cline").get<LanguageDisplay>("preferredLanguage"),
142+
)
138143
this.autoApprovalSettings = autoApprovalSettings
139144
this.browserSettings = browserSettings
140145
this.chatSettings = chatSettings
@@ -1269,6 +1274,10 @@ export class Cline {
12691274
let systemPrompt = await SYSTEM_PROMPT(cwd, supportsComputerUse, mcpHub, this.browserSettings)
12701275

12711276
let settingsCustomInstructions = this.customInstructions?.trim()
1277+
const preferredLanguageInstructions =
1278+
this.preferredLanguage && this.preferredLanguage !== DEFAULT_LANGUAGE_SETTINGS
1279+
? `# Preferred Language\n\nSpeak in ${this.preferredLanguage}.`
1280+
: ""
12721281
const clineRulesFilePath = path.resolve(cwd, GlobalFileNames.clineRules)
12731282
let clineRulesFileInstructions: string | undefined
12741283
if (await fileExistsAtPath(clineRulesFilePath)) {
@@ -1288,9 +1297,19 @@ export class Cline {
12881297
clineIgnoreInstructions = `# .clineignore\n\n(The following is provided by a root-level .clineignore file where the user has specified files and directories that should not be accessed. When using list_files, you'll notice a ${LOCK_TEXT_SYMBOL} next to files that are blocked. Attempting to access the file's contents e.g. through read_file will result in an error.)\n\n${clineIgnoreContent}\n.clineignore`
12891298
}
12901299

1291-
if (settingsCustomInstructions || clineRulesFileInstructions) {
1300+
if (
1301+
settingsCustomInstructions ||
1302+
clineRulesFileInstructions ||
1303+
preferredLanguageInstructions ||
1304+
clineIgnoreInstructions
1305+
) {
12921306
// altering the system prompt mid-task will break the prompt cache, but in the grand scheme this will not change often so it's better to not pollute user messages with it the way we have to with <potentially relevant details>
1293-
systemPrompt += addUserInstructions(settingsCustomInstructions, clineRulesFileInstructions, clineIgnoreInstructions)
1307+
systemPrompt += addUserInstructions(
1308+
settingsCustomInstructions,
1309+
clineRulesFileInstructions,
1310+
clineIgnoreInstructions,
1311+
preferredLanguageInstructions,
1312+
)
12941313
}
12951314

12961315
// If the previous API request's total token usage is close to the context window, truncate the conversation history to free up space for the new request

src/core/prompts/system.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,8 +979,12 @@ export function addUserInstructions(
979979
settingsCustomInstructions?: string,
980980
clineRulesFileInstructions?: string,
981981
clineIgnoreInstructions?: string,
982+
preferredLanguageInstructions?: string,
982983
) {
983984
let customInstructions = ""
985+
if (preferredLanguageInstructions) {
986+
customInstructions += preferredLanguageInstructions + "\n\n"
987+
}
984988
if (settingsCustomInstructions) {
985989
customInstructions += settingsCustomInstructions + "\n\n"
986990
}

src/shared/Languages.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
export type LanguageKey =
2+
| "en"
3+
| "ar"
4+
| "pt-BR"
5+
| "cs"
6+
| "fr"
7+
| "de"
8+
| "hi"
9+
| "hu"
10+
| "it"
11+
| "ja"
12+
| "ko"
13+
| "pl"
14+
| "pt-PT"
15+
| "ru"
16+
| "zh-CN"
17+
| "es"
18+
| "zh-TW"
19+
| "tr"
20+
21+
export type LanguageDisplay =
22+
| "English"
23+
| "Arabic - العربية"
24+
| "Portuguese - Português (Brasil)"
25+
| "Czech - Čeština"
26+
| "French - Français"
27+
| "German - Deutsch"
28+
| "Hindi - हिन्दी"
29+
| "Hungarian - Magyar"
30+
| "Italian - Italiano"
31+
| "Japanese - 日本語"
32+
| "Korean - 한국어"
33+
| "Polish - Polski"
34+
| "Portuguese - Português (Portugal)"
35+
| "Russian - Русский"
36+
| "Simplified Chinese - 简体中文"
37+
| "Spanish - Español"
38+
| "Traditional Chinese - 繁體中文"
39+
| "Turkish - Türkçe"
40+
41+
export const DEFAULT_LANGUAGE_SETTINGS: LanguageKey = "en"
42+
43+
export const languageOptions: { key: LanguageKey; display: LanguageDisplay }[] = [
44+
{ key: "en", display: "English" },
45+
{ key: "ar", display: "Arabic - العربية" },
46+
{ key: "pt-BR", display: "Portuguese - Português (Brasil)" },
47+
{ key: "cs", display: "Czech - Čeština" },
48+
{ key: "fr", display: "French - Français" },
49+
{ key: "de", display: "German - Deutsch" },
50+
{ key: "hi", display: "Hindi - हिन्दी" },
51+
{ key: "hu", display: "Hungarian - Magyar" },
52+
{ key: "it", display: "Italian - Italiano" },
53+
{ key: "ja", display: "Japanese - 日本語" },
54+
{ key: "ko", display: "Korean - 한국어" },
55+
{ key: "pl", display: "Polish - Polski" },
56+
{ key: "pt-PT", display: "Portuguese - Português (Portugal)" },
57+
{ key: "ru", display: "Russian - Русский" },
58+
{ key: "zh-CN", display: "Simplified Chinese - 简体中文" },
59+
{ key: "es", display: "Spanish - Español" },
60+
{ key: "zh-TW", display: "Traditional Chinese - 繁體中文" },
61+
{ key: "tr", display: "Turkish - Türkçe" },
62+
]
63+
64+
export function getLanguageKey(display: LanguageDisplay | undefined): LanguageKey {
65+
if (!display) {
66+
return DEFAULT_LANGUAGE_SETTINGS
67+
}
68+
const languageOption = languageOptions.find((option) => option.display === display)
69+
if (languageOption) {
70+
return languageOption.key
71+
}
72+
return DEFAULT_LANGUAGE_SETTINGS
73+
}

webview-ui/src/components/settings/__tests__/APIOptions.spec.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ describe("OpenApiInfoOptions", () => {
126126
<ApiOptions showModelOptions={true} />
127127
</ExtensionStateContextProvider>,
128128
)
129+
fireEvent.click(screen.getByText("Model Configuration"))
129130
const apiKeyInput = screen.getByText("Supports Images")
130131
expect(apiKeyInput).toBeInTheDocument()
131132
})
@@ -136,6 +137,7 @@ describe("OpenApiInfoOptions", () => {
136137
<ApiOptions showModelOptions={true} />
137138
</ExtensionStateContextProvider>,
138139
)
140+
fireEvent.click(screen.getByText("Model Configuration"))
139141
const orgIdInput = screen.getByText("Context Window Size")
140142
expect(orgIdInput).toBeInTheDocument()
141143
})
@@ -146,6 +148,7 @@ describe("OpenApiInfoOptions", () => {
146148
<ApiOptions showModelOptions={true} />
147149
</ExtensionStateContextProvider>,
148150
)
151+
fireEvent.click(screen.getByText("Model Configuration"))
149152
const modelInput = screen.getByText("Max Output Tokens")
150153
expect(modelInput).toBeInTheDocument()
151154
})

webview-ui/src/utils/vscStyles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export const VSC_INPUT_BACKGROUND = "--vscode-input-background"
2+
export const VSC_INPUT_FOREGROUND = "--vscode-input-foreground"
23
export const VSC_SIDEBAR_BACKGROUND = "--vscode-sideBar-background"
34
export const VSC_FOREGROUND = "--vscode-foreground"
45
export const VSC_EDITOR_FOREGROUND = "--vscode-editor-foreground"

0 commit comments

Comments
 (0)