Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/prompts/__tests__/sections.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe("addCustomInstructions", () => {
)

expect(result).toContain("Language Preference:")
expect(result).toContain('You should always speak and think in the "fr" language')
expect(result).toContain('You should always speak and think in the "Français" (fr) language')
})

test("works without vscode language", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ describe("addCustomInstructions", () => {
)

expect(result).toContain("Language Preference:")
expect(result).toContain("es")
expect(result).toContain("Español") // Check for language name
expect(result).toContain("(es)") // Check for language code in parentheses
expect(result).toContain("Global Instructions:\nglobal instructions")
expect(result).toContain("Mode-specific Instructions:\nmode instructions")
expect(result).toContain("Rules from .clinerules-test-mode:\nmode specific rules")
Expand Down Expand Up @@ -145,6 +146,22 @@ describe("addCustomInstructions", () => {
expect(result).not.toContain("Rules from .clinerules-test-mode")
})

it("should handle unknown language codes properly", async () => {
mockedFs.readFile.mockRejectedValue({ code: "ENOENT" })

const result = await addCustomInstructions(
"mode instructions",
"global instructions",
"/fake/path",
"test-mode",
{ language: "xyz" }, // Unknown language code
)

expect(result).toContain("Language Preference:")
expect(result).toContain('"xyz" (xyz) language') // For unknown codes, the code is used as the name too
expect(result).toContain("Global Instructions:\nglobal instructions")
})

it("should throw on unexpected errors", async () => {
const error = new Error("Permission denied") as NodeJS.ErrnoException
error.code = "EPERM"
Expand Down
4 changes: 3 additions & 1 deletion src/core/prompts/sections/custom-instructions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from "fs/promises"
import path from "path"
import * as vscode from "vscode"
import { LANGUAGES } from "../../../shared/language"

async function safeReadFile(filePath: string): Promise<string> {
try {
Expand Down Expand Up @@ -47,8 +48,9 @@ export async function addCustomInstructions(

// Add language preference if provided
if (options.language) {
const languageName = LANGUAGES[options.language] || options.language
sections.push(
`Language Preference:\nYou should always speak and think in the "${options.language}" language unless the user gives you instructions below to do otherwise.`,
`Language Preference:\nYou should always speak and think in the "${languageName}" (${options.language}) language unless the user gives you instructions below to do otherwise.`,
)
}

Expand Down
21 changes: 21 additions & 0 deletions src/shared/language.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
/**
* Language name mapping from ISO codes to full language names
*/
export const LANGUAGES: Record<string, string> = {
ca: "Català",
de: "Deutsch",
en: "English",
es: "Español",
fr: "Français",
hi: "हिन्दी",
it: "Italiano",
ja: "日本語",
ko: "한국어",
pl: "Polski",
"pt-BR": "Português",
tr: "Türkçe",
vi: "Tiếng Việt",
"zh-CN": "简体中文",
"zh-TW": "繁體中文",
}

/**
* Formats a VSCode locale string to ensure the region code is uppercase.
* For example, transforms "en-us" to "en-US" or "fr-ca" to "fr-CA".
Expand Down
19 changes: 1 addition & 18 deletions webview-ui/src/components/settings/LanguageSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,12 @@ import { Globe } from "lucide-react"

import { cn } from "@/lib/utils"
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui"
import { LANGUAGES } from "../../../../src/shared/language"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using alias imports (via tsconfig paths) to simplify the relative path if possible.

Suggested change
import { LANGUAGES } from "../../../../src/shared/language"
import { LANGUAGES } from "@src/shared/language"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using a module alias (e.g., @/shared/language) for the language import instead of a deep relative path to improve maintainability.

Suggested change
import { LANGUAGES } from "../../../../src/shared/language"
import { LANGUAGES } from "@/shared/language"


import { SetCachedStateField } from "./types"
import { SectionHeader } from "./SectionHeader"
import { Section } from "./Section"

const LANGUAGES: Record<string, string> = {
ca: "Català",
de: "Deutsch",
en: "English",
es: "Español",
fr: "Français",
hi: "हिन्दी",
it: "Italiano",
ja: "日本語",
ko: "한국어",
pl: "Polski",
"pt-BR": "Português",
tr: "Türkçe",
vi: "Tiếng Việt",
"zh-CN": "简体中文",
"zh-TW": "繁體中文",
}

type LanguageSettingsProps = HTMLAttributes<HTMLDivElement> & {
language: string
setCachedStateField: SetCachedStateField<"language">
Expand Down