Merge pull request #1317 from brownrw8/i18l-l10n

Adding react-i18next (preliminary support for en, de, zh, ja)
This commit is contained in:
akfoster 2025-01-24 10:06:29 -08:00 committed by GitHub
commit 67ac1fd339
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 3542 additions and 5505 deletions

380
package-lock.json generated
View file

@ -2183,74 +2183,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
@ -2268,312 +2200,6 @@
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@ -3537,9 +3163,9 @@
"license": "MIT"
},
"node_modules/@mistralai/mistralai": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.3.6.tgz",
"integrity": "sha512-2y7U5riZq+cIjKpxGO9y417XuZv9CpBXEAvbjRMzWPGhXY7U1ZXj4VO4H9riS2kFZqTR2yLEKSE6/pGWVVIqgQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.4.0.tgz",
"integrity": "sha512-xA3DAtIDh4Qgr1EoSuiGVE+2ABNrxpcTeC0kSXYbkDNUGdthalLAH7DgbG0fkKZ7TN8xdWXQq2WiIghp/O96Eg==",
"peerDependencies": {
"zod": ">= 3"
}

View file

@ -72,6 +72,7 @@ type GlobalStateKey =
| "browserSettings"
| "chatSettings"
| "vsCodeLmModelSelector"
| "localeLanguage"
| "userInfo"
export const GlobalFileNames = {
@ -1128,6 +1129,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
autoApprovalSettings,
browserSettings,
chatSettings,
localeLanguage: vscode.env.language,
isLoggedIn: !!authToken,
userInfo,
}
@ -1219,6 +1221,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
browserSettings,
chatSettings,
vsCodeLmModelSelector,
localeLanguage,
userInfo,
] = await Promise.all([
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
@ -1254,6 +1257,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.getGlobalState("browserSettings") as Promise<BrowserSettings | undefined>,
this.getGlobalState("chatSettings") as Promise<ChatSettings | undefined>,
this.getGlobalState("vsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
this.getGlobalState("localeLanguage") as Promise<string | undefined>,
this.getGlobalState("userInfo") as Promise<UserInfo | undefined>,
])

View file

@ -58,6 +58,7 @@ export interface ExtensionState {
autoApprovalSettings: AutoApprovalSettings
browserSettings: BrowserSettings
chatSettings: ChatSettings
localeLanguage: string
isLoggedIn: boolean
userInfo?: {
displayName: string | null

File diff suppressed because it is too large Load diff

View file

@ -17,17 +17,21 @@
"pretty-bytes": "^6.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^15.4.0",
"react-remark": "^2.1.0",
"react-scripts": "5.0.1",
"react-scripts": "^5.0.1",
"react-textarea-autosize": "^8.5.3",
"react-use": "^17.5.1",
"react-virtuoso": "^4.7.13",
"rehype-highlight": "^7.0.0",
"rewire": "^7.0.0",
"styled-components": "^6.1.13",
"typescript": "^4.9.5",
"typescript": "^5.7.3",
"web-vitals": "^2.1.4"
},
"overrides": {
"typescript": "^5.7.3"
},
"scripts": {
"start": "react-scripts start",
"build": "node ./scripts/build-react-no-split.js",

View file

@ -9,9 +9,11 @@ import AccountView from "./components/account/AccountView"
import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext"
import { vscode } from "./utils/vscode"
import McpView from "./components/mcp/McpView"
import { useTranslation } from "react-i18next"
const AppContent = () => {
const { didHydrateState, showWelcome, shouldShowAnnouncement } = useExtensionState()
const { didHydrateState, showWelcome, shouldShowAnnouncement, localeLanguage } = useExtensionState()
const { i18n } = useTranslation()
const [showSettings, setShowSettings] = useState(false)
const [showHistory, setShowHistory] = useState(false)
const [showMcp, setShowMcp] = useState(false)
@ -67,6 +69,12 @@ const AppContent = () => {
}
}, [shouldShowAnnouncement])
useEffect(() => {
if (localeLanguage) {
i18n.changeLanguage(localeLanguage)
}
}, [i18n, localeLanguage])
if (!didHydrateState) {
return null
}

View file

@ -1,17 +1,19 @@
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import { memo } from "react"
// import VSCodeButtonLink from "./VSCodeButtonLink"
// import { getOpenRouterAuthUrl } from "./ApiOptions"
// import { vscode } from "../utils/vscode"
import { useTranslation } from "react-i18next"
import { Trans } from "react-i18next"
interface AnnouncementProps {
version: string
hideAnnouncement: () => void
}
/*
You must update the latestAnnouncementId in ClineProvider for new announcements to show to users. This new id will be compared with whats in state for the 'last announcement shown', and if it's different then the announcement will render. As soon as an announcement is shown, the id will be updated in state. This ensures that announcements are not shown more than once, even if the user doesn't close it themselves.
*/
const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
const { t } = useTranslation("translation", { keyPrefix: "announcement" })
const minorVersion = version.split(".").slice(0, 2).join(".") // 2.0.0 -> 2.0
return (
<div
@ -26,9 +28,7 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
<VSCodeButton appearance="icon" onClick={hideAnnouncement} style={{ position: "absolute", top: "8px", right: "8px" }}>
<span className="codicon codicon-close"></span>
</VSCodeButton>
<h3 style={{ margin: "0 0 8px" }}>
🎉{" "}New in v{minorVersion}
</h3>
<h3 style={{ margin: "0 0 8px" }}>{t("newInVersion", { version: minorVersion })}</h3>
<ul style={{ margin: "0 0 8px", paddingLeft: "12px" }}>
<li>
<b>Plan/Act mode toggle:</b> Plan mode turns Cline into an architect that gathers information, asks clarifying
@ -86,7 +86,7 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
Switch to OpenRouter
</VSCodeButton>
)}
</li>
</li>
<li>
<b>Edit Cline's changes before accepting!</b> When he creates or edits a file, you can modify his
changes directly in the right side of the diff view (+ hover over the 'Revert Block' arrow button in
@ -110,15 +110,13 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
}}
/>
<p style={{ margin: "0" }}>
Join our{" "}
<VSCodeLink style={{ display: "inline" }} href="https://discord.gg/cline">
discord
</VSCodeLink>{" "}
or{" "}
<VSCodeLink style={{ display: "inline" }} href="https://www.reddit.com/r/cline/">
r/cline
</VSCodeLink>
for more updates!
<Trans
i18nKey="announcement.joinOurCommunities"
components={{
DiscordLink: <VSCodeLink href="https://discord.gg/cline" />,
RedditLink: <VSCodeLink href="https://www.reddit.com/r/cline/" />,
}}
/>
</p>
</div>
)

View file

@ -32,6 +32,8 @@ import {
vertexDefaultModelId,
vertexModels,
} from "../../../../src/shared/api"
import { useTranslation } from "react-i18next"
import { Trans } from "react-i18next"
import { ExtensionMessage } from "../../../../src/shared/ExtensionMessage"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { vscode } from "../../utils/vscode"
@ -72,6 +74,7 @@ declare module "vscode" {
}
const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, isPopup }: ApiOptionsProps) => {
const { t, ready } = useTranslation("translation", { keyPrefix: "apiOptions", useSuspense: false })
const { apiConfiguration, setApiConfiguration, uriScheme } = useExtensionState()
const [ollamaModels, setOllamaModels] = useState<string[]>([])
const [lmStudioModels, setLmStudioModels] = useState<string[]>([])
@ -144,7 +147,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
value={selectedModelId}
onChange={handleInputChange("apiModelId")}
style={{ width: "100%" }}>
<VSCodeOption value="">Select a model...</VSCodeOption>
<VSCodeOption value="">{t("selectModel")}</VSCodeOption>
{Object.keys(models).map((modelId) => (
<VSCodeOption
key={modelId}
@ -165,7 +168,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
<div style={{ display: "flex", flexDirection: "column", gap: 5, marginBottom: isPopup ? -10 : 0 }}>
<DropdownContainer className="dropdown-container">
<label htmlFor="api-provider">
<span style={{ fontWeight: 500 }}>API Provider</span>
<span style={{ fontWeight: 500 }}>{t("apiProvider")}</span>
</label>
<VSCodeDropdown
id="api-provider"
@ -183,7 +186,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
<VSCodeOption value="vertex">GCP Vertex AI</VSCodeOption>
<VSCodeOption value="bedrock">AWS Bedrock</VSCodeOption>
<VSCodeOption value="openai-native">OpenAI</VSCodeOption>
<VSCodeOption value="openai">OpenAI Compatible</VSCodeOption>
<VSCodeOption value="openai">{t("getCompatibleVendor", { vendor: "OpenAI" })}</VSCodeOption>
<VSCodeOption value="vscode-lm">VS Code LM API</VSCodeOption>
<VSCodeOption value="lmstudio">LM Studio</VSCodeOption>
<VSCodeOption value="ollama">Ollama</VSCodeOption>
@ -197,7 +200,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("apiKey")}
placeholder="Enter API Key...">
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>Anthropic API Key</span>
</VSCodeTextField>
@ -213,7 +216,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
})
}
}}>
Use custom base URL
{t("useCustomBaseUrl")}
</VSCodeCheckbox>
{anthropicBaseUrlSelected && (
@ -232,7 +235,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
This key is stored locally and only used to make API requests from this extension.
{t("apiKeyInfo")}
{!apiConfiguration?.apiKey && (
<VSCodeLink
href="https://console.anthropic.com/settings/keys"
@ -240,7 +243,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
display: "inline",
fontSize: "inherit",
}}>
You can get an Anthropic API key by signing up here.
{t("getApiKeyMessage", { vendor: "Anthropic" })}
</VSCodeLink>
)}
</p>
@ -254,8 +257,8 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("openAiNativeApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>OpenAI API Key</span>
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>{t("getApiVendorKey", { vendor: "OpenAI" })}</span>
</VSCodeTextField>
<p
style={{
@ -263,7 +266,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
This key is stored locally and only used to make API requests from this extension.
{t("apiKeyInfo")}
{!apiConfiguration?.openAiNativeApiKey && (
<VSCodeLink
href="https://platform.openai.com/api-keys"
@ -271,7 +274,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
display: "inline",
fontSize: "inherit",
}}>
You can get an OpenAI API key by signing up here.
{t("getApiKeyMessage", { vendor: "OpenAI" })}
</VSCodeLink>
)}
</p>
@ -285,8 +288,8 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("deepSeekApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>DeepSeek API Key</span>
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>{t("getApiVendorKey", { vendor: "DeepSeek" })}</span>
</VSCodeTextField>
<p
style={{
@ -294,7 +297,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
This key is stored locally and only used to make API requests from this extension.
{t("apiKeyInfo")}
{!apiConfiguration?.deepSeekApiKey && (
<VSCodeLink
href="https://www.deepseek.com/"
@ -302,7 +305,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
display: "inline",
fontSize: "inherit",
}}>
You can get a DeepSeek API key by signing up here.
{t("getApiKeyMessage", { vendor: "DeepSeek" })}
</VSCodeLink>
)}
</p>
@ -316,8 +319,8 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("mistralApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Mistral API Key</span>
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>{t("getApiVendorKey", { vendor: "Mistral" })}</span>
</VSCodeTextField>
<p
style={{
@ -325,7 +328,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
This key is stored locally and only used to make API requests from this extension.
{t("apiKeyInfo")}
{!apiConfiguration?.mistralApiKey && (
<VSCodeLink
href="https://console.mistral.ai/codestral"
@ -333,7 +336,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
display: "inline",
fontSize: "inherit",
}}>
You can get a Mistral API key by signing up here.
{t("getApiKeyMessage", { vendor: "Mistral" })}
</VSCodeLink>
)}
</p>
@ -347,15 +350,15 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("openRouterApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>OpenRouter API Key</span>
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>{t("getApiVendorKey", { vendor: "OpenRouter" })}</span>
</VSCodeTextField>
{!apiConfiguration?.openRouterApiKey && (
<VSCodeButtonLink
href={getOpenRouterAuthUrl(uriScheme)}
style={{ margin: "5px 0 0 0" }}
appearance="secondary">
Get OpenRouter API Key
{t("getApiKeyMessage", { vendor: "OpenRouter" })}
</VSCodeButtonLink>
)}
<p
@ -364,13 +367,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
This key is stored locally and only used to make API requests from this extension.{" "}
{/* {!apiConfiguration?.openRouterApiKey && (
<span style={{ color: "var(--vscode-charts-green)" }}>
(<span style={{ fontWeight: 500 }}>Note:</span> OpenRouter is recommended for high rate
limits, prompt caching, and wider selection of models.)
</span>
)} */}
{t("apiKeyInfo")}
</p>
</div>
)}
@ -387,35 +384,35 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("awsAccessKey")}
placeholder="Enter Access Key...">
<span style={{ fontWeight: 500 }}>AWS Access Key</span>
placeholder={t("enterAwsAccessKey")}>
<span style={{ fontWeight: 500 }}>{t("awsAccessKey")}</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.awsSecretKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("awsSecretKey")}
placeholder="Enter Secret Key...">
<span style={{ fontWeight: 500 }}>AWS Secret Key</span>
placeholder={t("enterAwsSecretKey")}>
<span style={{ fontWeight: 500 }}>{t("awsSecretKey")}</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.awsSessionToken || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("awsSessionToken")}
placeholder="Enter Session Token...">
<span style={{ fontWeight: 500 }}>AWS Session Token</span>
placeholder={t("enterAwsSessionToken")}>
<span style={{ fontWeight: 500 }}>{t("awsSessionToken")}</span>
</VSCodeTextField>
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 1} className="dropdown-container">
<label htmlFor="aws-region-dropdown">
<span style={{ fontWeight: 500 }}>AWS Region</span>
<span style={{ fontWeight: 500 }}>{t("getRegion", { vendor: "AWS" })}</span>
</label>
<VSCodeDropdown
id="aws-region-dropdown"
value={apiConfiguration?.awsRegion || ""}
style={{ width: "100%" }}
onChange={handleInputChange("awsRegion")}>
<VSCodeOption value="">Select a region...</VSCodeOption>
<VSCodeOption value="">{t("selectRegion")}</VSCodeOption>
{/* The user will have to choose a region that supports the model they use, but this shouldn't be a problem since they'd have to request access for it in that region in the first place. */}
<VSCodeOption value="us-east-1">us-east-1</VSCodeOption>
<VSCodeOption value="us-east-2">us-east-2</VSCodeOption>
@ -452,7 +449,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
awsUseCrossRegionInference: isChecked,
})
}}>
Use cross-region inference
{t("useCrossRegionInference")}
</VSCodeCheckbox>
<p
style={{
@ -460,9 +457,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
Authenticate by either providing the keys above or use the default AWS credential providers, i.e.
~/.aws/credentials or environment variables. These credentials are only used locally to make API requests
from this extension.
{t("awsInfo")}
</p>
</div>
)}
@ -478,19 +473,19 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
value={apiConfiguration?.vertexProjectId || ""}
style={{ width: "100%" }}
onInput={handleInputChange("vertexProjectId")}
placeholder="Enter Project ID...">
<span style={{ fontWeight: 500 }}>Google Cloud Project ID</span>
placeholder={t("enterGcpProjectId")}>
<span style={{ fontWeight: 500 }}>{t("gcpProjectId")}</span>
</VSCodeTextField>
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 2} className="dropdown-container">
<label htmlFor="vertex-region-dropdown">
<span style={{ fontWeight: 500 }}>Google Cloud Region</span>
<span style={{ fontWeight: 500 }}>{t("getRegion", { vendor: "Google Cloud" })}</span>
</label>
<VSCodeDropdown
id="vertex-region-dropdown"
value={apiConfiguration?.vertexRegion || ""}
style={{ width: "100%" }}
onChange={handleInputChange("vertexRegion")}>
<VSCodeOption value="">Select a region...</VSCodeOption>
<VSCodeOption value="">{t("selectRegion")}</VSCodeOption>
<VSCodeOption value="us-east5">us-east5</VSCodeOption>
<VSCodeOption value="us-central1">us-central1</VSCodeOption>
<VSCodeOption value="europe-west1">europe-west1</VSCodeOption>
@ -504,17 +499,12 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
To use Google Cloud Vertex AI, you need to
<VSCodeLink
href="https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#before_you_begin"
style={{ display: "inline", fontSize: "inherit" }}>
{"1) create a Google Cloud account enable the Vertex AI API enable the desired Claude models,"}
</VSCodeLink>{" "}
<VSCodeLink
href="https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp"
style={{ display: "inline", fontSize: "inherit" }}>
{"2) install the Google Cloud CLI configure Application Default Credentials."}
</VSCodeLink>
<Trans
i18nKey="apiOptions.gcpLinks"
components={{
Link: <VSCodeLink />,
}}
/>
</p>
</div>
)}
@ -526,8 +516,8 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("geminiApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Gemini API Key</span>
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>{t("getApiVendorKey", { vendor: "Gemini" })}</span>
</VSCodeTextField>
<p
style={{
@ -535,7 +525,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
This key is stored locally and only used to make API requests from this extension.
{t("apiKeyInfo")}
{!apiConfiguration?.geminiApiKey && (
<VSCodeLink
href="https://ai.google.dev/"
@ -543,7 +533,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
display: "inline",
fontSize: "inherit",
}}>
You can get a Gemini API key by signing up here.
{t("getApiKeyMessage", { vendor: "Gemini" })}
</VSCodeLink>
)}
</p>
@ -557,23 +547,23 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("openAiBaseUrl")}
placeholder={"Enter base URL..."}>
<span style={{ fontWeight: 500 }}>Base URL</span>
placeholder={t("enterBaseUrl")}>
<span style={{ fontWeight: 500 }}>{t("baseUrl")}</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.openAiApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("openAiApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>API Key</span>
placeholder={t("enterApiKey")}>
<span style={{ fontWeight: 500 }}>{t("apiKey")}</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.openAiModelId || ""}
style={{ width: "100%" }}
onInput={handleInputChange("openAiModelId")}
placeholder={"Enter Model ID..."}>
<span style={{ fontWeight: 500 }}>Model ID</span>
placeholder={t("enterModelId")}>
<span style={{ fontWeight: 500 }}>{t("modelId")}</span>
</VSCodeTextField>
<VSCodeCheckbox
checked={azureApiVersionSelected}
@ -587,14 +577,14 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
})
}
}}>
Set Azure API version
{t("useAzureApiVersion")}
</VSCodeCheckbox>
{azureApiVersionSelected && (
<VSCodeTextField
value={apiConfiguration?.azureApiVersion || ""}
style={{ width: "100%", marginTop: 3 }}
onInput={handleInputChange("azureApiVersion")}
placeholder={`Default: ${azureOpenAiDefaultApiVersion}`}
placeholder={t("getDefault", azureOpenAiDefaultApiVersion)}
/>
)}
<p
@ -603,10 +593,13 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: 3,
color: "var(--vscode-descriptionForeground)",
}}>
<span style={{ color: "var(--vscode-errorForeground)" }}>
(<span style={{ fontWeight: 500 }}>Note:</span> Cline uses complex prompts and works best with Claude
models. Less capable models may not work as expected.)
</span>
<Trans
i18nKey="apiOptions.azureInfo"
components={{
Link: <VSCodeLink />,
ErrSpan: <span style={{ color: "var(--vscode-errorForeground)" }} />,
}}
/>
</p>
</div>
)}
@ -615,7 +608,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
<div>
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 2} className="dropdown-container">
<label htmlFor="vscode-lm-model">
<span style={{ fontWeight: 500 }}>Language Model</span>
<span style={{ fontWeight: 500 }}>{t("languageModel")}</span>
</label>
{vsCodeLmModels.length > 0 ? (
<VSCodeDropdown
@ -638,7 +631,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
})
}}
style={{ width: "100%" }}>
<VSCodeOption value="">Select a model...</VSCodeOption>
<VSCodeOption value="">{t("selectModel")}</VSCodeOption>
{vsCodeLmModels.map((model) => (
<VSCodeOption
key={`${model.vendor}/${model.family}`}
@ -654,9 +647,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
The VS Code Language Model API allows you to run models provided by other VS Code extensions
(including but not limited to GitHub Copilot). The easiest way to get started is to install the
Copilot extension from the VS Marketplace and enabling Claude 3.5 Sonnet.
{t("vscodeLanguageModelsInfo")}
</p>
)}
@ -667,7 +658,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
color: "var(--vscode-errorForeground)",
fontWeight: 500,
}}>
Note: This is a very experimental integration and may not work as expected.
{t("experimentalFeature")}
</p>
</DropdownContainer>
</div>
@ -680,15 +671,15 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("lmStudioBaseUrl")}
placeholder={"Default: http://localhost:1234"}>
<span style={{ fontWeight: 500 }}>Base URL (optional)</span>
placeholder={t("getDefault", { defaultValue: "http://localhost/1234" })}>
<span style={{ fontWeight: 500 }}>{t("optionalBaseUrl")}</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.lmStudioModelId || ""}
style={{ width: "100%" }}
onInput={handleInputChange("lmStudioModelId")}
placeholder={"e.g. meta-llama-3.1-8b-instruct"}>
<span style={{ fontWeight: 500 }}>Model ID</span>
<span style={{ fontWeight: 500 }}>{t("modelId")}</span>
</VSCodeTextField>
{lmStudioModels.length > 0 && (
<VSCodeRadioGroup
@ -719,22 +710,13 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
LM Studio allows you to run models locally on your computer. For instructions on how to get started, see
their
<VSCodeLink href="https://lmstudio.ai/docs" style={{ display: "inline", fontSize: "inherit" }}>
quickstart guide.
</VSCodeLink>
You will also need to start LM Studio's{" "}
<VSCodeLink
href="https://lmstudio.ai/docs/basics/server"
style={{ display: "inline", fontSize: "inherit" }}>
local server
</VSCodeLink>{" "}
feature to use it with this extension.{" "}
<span style={{ color: "var(--vscode-errorForeground)" }}>
(<span style={{ fontWeight: 500 }}>Note:</span> Cline uses complex prompts and works best with Claude
models. Less capable models may not work as expected.)
</span>
<Trans
i18nKey="apiOptions.lmStudioInfo"
components={{
Link: <VSCodeLink style={{ display: "inline", fontSize: "inherit" }} />,
ErrSpan: <span style={{ color: "var(--vscode-errorForeground)" }} />,
}}
/>
</p>
</div>
)}
@ -746,8 +728,8 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("ollamaBaseUrl")}
placeholder={"Default: http://localhost:11434"}>
<span style={{ fontWeight: 500 }}>Base URL (optional)</span>
placeholder={t("getDefault", { defaultValue: "http://localhost:11434" })}>
<span style={{ fontWeight: 500 }}>{t("optionalBaseUrl")}</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.ollamaModelId || ""}
@ -785,17 +767,15 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
Ollama allows you to run models locally on your computer. For instructions on how to get started, see
their
<VSCodeLink
href="https://github.com/ollama/ollama/blob/main/README.md"
style={{ display: "inline", fontSize: "inherit" }}>
quickstart guide.
</VSCodeLink>
<span style={{ color: "var(--vscode-errorForeground)" }}>
(<span style={{ fontWeight: 500 }}>Note:</span> Cline uses complex prompts and works best with Claude
models. Less capable models may not work as expected.)
</span>
{
<Trans
i18nKey="apiOptions.ollamaInfo"
components={{
Link: <VSCodeLink style={{ display: "inline", fontSize: "inherit" }} />,
ErrorSpan: <span style={{ color: "var(--vscode-errorForeground)" }} />,
}}
/>
}
</p>
</div>
)}
@ -820,7 +800,7 @@ const ApiOptions = ({ showModelOptions, apiErrorMessage, modelIdErrorMessage, is
<>
<DropdownContainer zIndex={DROPDOWN_Z_INDEX - 2} className="dropdown-container">
<label htmlFor="model-id">
<span style={{ fontWeight: 500 }}>Model</span>
<span style={{ fontWeight: 500 }}>{t("model")}</span>
</label>
{selectedProvider === "anthropic" && createDropdown(anthropicModels)}
{selectedProvider === "bedrock" && createDropdown(bedrockModels)}
@ -883,6 +863,7 @@ export const ModelInfoView = ({
isPopup?: boolean
}) => {
const isGemini = Object.keys(geminiModels).includes(selectedModelId)
const { t, ready } = useTranslation("translation", { keyPrefix: "apiOptions", useSuspense: false })
const infoItems = [
modelInfo.description && (
@ -897,56 +878,57 @@ export const ModelInfoView = ({
<ModelInfoSupportsItem
key="supportsImages"
isSupported={modelInfo.supportsImages ?? false}
supportsLabel="Supports images"
doesNotSupportLabel="Does not support images"
supportsLabel={t("supportsImages")}
doesNotSupportLabel={t("doesNotSupportImages")}
/>,
<ModelInfoSupportsItem
key="supportsComputerUse"
isSupported={modelInfo.supportsComputerUse ?? false}
supportsLabel="Supports computer use"
doesNotSupportLabel="Does not support computer use"
supportsLabel={t("supportsComputerUse")}
doesNotSupportLabel={t("doesNotSupportComputerUse")}
/>,
!isGemini && (
<ModelInfoSupportsItem
key="supportsPromptCache"
isSupported={modelInfo.supportsPromptCache}
supportsLabel="Supports prompt caching"
doesNotSupportLabel="Does not support prompt caching"
supportsLabel={t("supportsPromptCache")}
doesNotSupportLabel={t("doesNotSupportPromptCache")}
/>
),
modelInfo.maxTokens !== undefined && modelInfo.maxTokens > 0 && (
<span key="maxTokens">
<span style={{ fontWeight: 500 }}>Max output:</span> {modelInfo.maxTokens?.toLocaleString()} tokens
<span style={{ fontWeight: 500 }}>{t("maxOutput")}:</span> {modelInfo.maxTokens?.toLocaleString()} {t("tokens")}
</span>
),
modelInfo.inputPrice !== undefined && modelInfo.inputPrice > 0 && (
<span key="inputPrice">
<span style={{ fontWeight: 500 }}>Input price:</span> {formatPrice(modelInfo.inputPrice)}/million tokens
<span style={{ fontWeight: 500 }}>{t("inputPrice")}:</span> {formatPrice(modelInfo.inputPrice)}/
{t("millionTokens")}
</span>
),
modelInfo.supportsPromptCache && modelInfo.cacheWritesPrice && (
<span key="cacheWritesPrice">
<span style={{ fontWeight: 500 }}>Cache writes price:</span> {formatPrice(modelInfo.cacheWritesPrice || 0)}
/million tokens
<span style={{ fontWeight: 500 }}>{t("cacheWritesPrice")}:</span> {formatPrice(modelInfo.cacheWritesPrice || 0)}/
{t("millionTokens")}
</span>
),
modelInfo.supportsPromptCache && modelInfo.cacheReadsPrice && (
<span key="cacheReadsPrice">
<span style={{ fontWeight: 500 }}>Cache reads price:</span> {formatPrice(modelInfo.cacheReadsPrice || 0)}/million
tokens
<span style={{ fontWeight: 500 }}>{t("cacheReadsPrice")}:</span> {formatPrice(modelInfo.cacheReadsPrice || 0)}/
{t("millionTokens")}
</span>
),
modelInfo.outputPrice !== undefined && modelInfo.outputPrice > 0 && (
<span key="outputPrice">
<span style={{ fontWeight: 500 }}>Output price:</span> {formatPrice(modelInfo.outputPrice)}/million tokens
<span style={{ fontWeight: 500 }}>{t("outputPrice")}:</span> {formatPrice(modelInfo.outputPrice)}/
{t("millionTokens")}
</span>
),
isGemini && (
<span key="geminiInfo" style={{ fontStyle: "italic" }}>
* Free up to {selectedModelId && selectedModelId.includes("flash") ? "15" : "2"} requests per minute. After that,
billing depends on prompt size.{" "}
{t("geminiInfo", { selectedModelId })}{" "}
<VSCodeLink href="https://ai.google.dev/pricing" style={{ display: "inline", fontSize: "inherit" }}>
For more info, see pricing details.
{t("pricingDetails")}
</VSCodeLink>
</span>
),

View file

@ -0,0 +1,35 @@
import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"
import { memo } from "react"
import { useTranslation } from "react-i18next"
const LanguageOptions = () => {
const { t, i18n } = useTranslation("translation", { keyPrefix: "settingsView", useSuspense: false })
const changeLanguage = (e: any) => {
const language = e.target.value
i18n.changeLanguage(language)
}
return (
<div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
<div className="dropdown-container">
<label htmlFor="language-dropdown">
<span style={{ fontWeight: 500 }}>{t("language")}</span>
</label>
<VSCodeDropdown
id="language-dropdown"
value={i18n.resolvedLanguage}
style={{ width: "100%" }}
onChange={changeLanguage}>
<VSCodeOption value="en">English</VSCodeOption>
<VSCodeOption value="de">Deutsch</VSCodeOption>
<VSCodeOption value="zh-CN">()</VSCodeOption>
<VSCodeOption value="zh-TW">()</VSCodeOption>
<VSCodeOption value="ja"></VSCodeOption>
</VSCodeDropdown>
</div>
</div>
)
}
export default memo(LanguageOptions)

View file

@ -1,9 +1,11 @@
import { VSCodeButton, VSCodeLink, VSCodeTextArea } from "@vscode/webview-ui-toolkit/react"
import { memo, useEffect, useState } from "react"
import { useTranslation } from "react-i18next"
import { useExtensionState } from "../../context/ExtensionStateContext"
import { validateApiConfiguration, validateModelId } from "../../utils/validate"
import { vscode } from "../../utils/vscode"
import ApiOptions from "./ApiOptions"
import LanguageOptions from "./LanguageOptions"
import SettingsButton from "../common/SettingsButton"
const IS_DEV = false // FIXME: use flags when packaging
@ -13,6 +15,7 @@ type SettingsViewProps = {
}
const SettingsView = ({ onDone }: SettingsViewProps) => {
const { t } = useTranslation("translation", { keyPrefix: "settingsView", useSuspense: false })
const { apiConfiguration, version, customInstructions, setCustomInstructions, openRouterModels } = useExtensionState()
const [apiErrorMessage, setApiErrorMessage] = useState<string | undefined>(undefined)
const [modelIdErrorMessage, setModelIdErrorMessage] = useState<string | undefined>(undefined)
@ -42,7 +45,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
// validate as soon as the component is mounted
/*
useEffect will use stale values of variables if they are not included in the dependency array. so trying to use useEffect with a dependency array of only one value for example will use any other variables' old values. In most cases you don't want this, and should opt to use react-use hooks.
useEffect(() => {
// uses someVar and anotherVar
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -76,8 +79,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
marginBottom: "17px",
paddingRight: 17,
}}>
<h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>Settings</h3>
<VSCodeButton onClick={handleSubmit}>Done</VSCodeButton>
<h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>{t("settings")}</h3>
<VSCodeButton onClick={handleSubmit}>{t("done")}</VSCodeButton>
</div>
<div
style={{
@ -101,9 +104,9 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
style={{ width: "100%" }}
resize="vertical"
rows={4}
placeholder={'e.g. "Run unit tests at the end", "Use TypeScript with async/await", "Speak in Spanish"'}
placeholder={t("customInstructionsPlaceholder")}
onInput={(e: any) => setCustomInstructions(e.target?.value ?? "")}>
<span style={{ fontWeight: "500" }}>Custom Instructions</span>
<span style={{ fontWeight: "500" }}>{t("customInstructions")}</span>
</VSCodeTextArea>
<p
style={{
@ -111,15 +114,18 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
These instructions are added to the end of the system prompt sent with every request.
{t("customInstructionsDescription")}
</p>
</div>
<div style={{ marginBottom: 5 }}>
<LanguageOptions />
</div>
{IS_DEV && (
<>
<div style={{ marginTop: "10px", marginBottom: "4px" }}>Debug</div>
<div style={{ marginTop: "10px", marginBottom: "4px" }}>{t("debug")}</div>
<VSCodeButton onClick={handleResetState} style={{ marginTop: "5px", width: "auto" }}>
Reset State
{t("resetState")}
</VSCodeButton>
<p
style={{
@ -127,7 +133,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
marginTop: "5px",
color: "var(--vscode-descriptionForeground)",
}}>
This will reset all global state and secret storage in the extension.
{t("resetStateDescription")}
</p>
</>
)}
@ -162,7 +168,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
margin: 0,
padding: 0,
}}>
If you have any questions or feedback, feel free to open an issue at{" "}
{t("feedback")}{" "}
<VSCodeLink href="https://github.com/cline/cline" style={{ display: "inline" }}>
https://github.com/cline/cline
</VSCodeLink>
@ -173,7 +179,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
margin: "10px 0 0 0",
padding: 0,
}}>
v{version}
{t("version")} {version}
</p>
</div>
</div>

View file

@ -34,6 +34,7 @@ export const ExtensionStateContextProvider: React.FC<{
shouldShowAnnouncement: false,
autoApprovalSettings: DEFAULT_AUTO_APPROVAL_SETTINGS,
browserSettings: DEFAULT_BROWSER_SETTINGS,
localeLanguage: "en",
chatSettings: DEFAULT_CHAT_SETTINGS,
isLoggedIn: false,
})

27
webview-ui/src/i18n.ts Normal file
View file

@ -0,0 +1,27 @@
import i18n from "i18next"
import { initReactI18next } from "react-i18next"
import translationEN from "./locales/en/translation.json"
import translationDE from "./locales/de/translation.json"
import translationZHCN from "./locales/zh-CN/translation.json"
import translationZHTW from "./locales/zh-TW/translation.json"
import translationJA from "./locales/ja/translation.json"
i18n.use(initReactI18next) // passes i18n down to react-i18next
.init({
fallbackLng: "en",
debug: true,
react: {
bindI18n: "languageChanged",
transSupportBasicHtmlNodes: true,
transKeepBasicHtmlNodesFor: ["b", "i", "strong", "em", "br"],
},
})
i18n.addResourceBundle("de", "translation", translationDE)
i18n.addResourceBundle("en", "translation", translationEN)
i18n.addResourceBundle("zh-CN", "translation", translationZHCN)
i18n.addResourceBundle("zh-TW", "translation", translationZHTW)
i18n.addResourceBundle("ja", "translation", translationJA)
export default i18n

View file

@ -4,6 +4,7 @@ import "./index.css"
import App from "./App"
import reportWebVitals from "./reportWebVitals"
import "../../node_modules/@vscode/codicons/dist/codicon.css"
import "./i18n"
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
root.render(

View file

@ -0,0 +1,67 @@
{
"announcement": {
"newInVersion": "Neu in Version {{version}}",
"joinOurCommunities": "Treten Sie unserem <DiscordLink>Discord</DiscordLink> oder <RedditLink>Reddit</RedditLink> für weitere Updates bei!"
},
"settingsView": {
"settings": "Einstellungen",
"done": "Fertig",
"language": "Sprache",
"customInstructions": "Benutzerdefinierte Anweisungen",
"customInstructionsPlaceholder": "z.B. \"Führen Sie am Ende Unit-Tests durch\", \"Verwenden Sie TypeScript mit async/await\", \"Sprechen Sie auf Japanisch\"",
"customInstructionsDescription": "Diese Anweisungen werden am Ende des Systemprompts hinzugefügt, der mit jeder Anfrage gesendet wird.",
"debug": "Debuggen",
"resetState": "Zustand zurücksetzen",
"resetStateDescription": "Dies setzt den gesamten globalen Zustand und die geheime Speicherung in der Erweiterung zurück.",
"feedback": "Wenn Sie Fragen oder Feedback haben, können Sie gerne ein Issue eröffnen unter",
"version": "v"
},
"apiOptions": {
"selectModel": "Modell auswählen...",
"model": "Modell",
"apiProvider": "API-Anbieter",
"enterApiKey": "API-Schlüssel eingeben...",
"apiKey": "API-Schlüssel",
"enterBaseUrl": "Basis-URL eingeben...",
"baseUrl": "Basis-URL",
"enterModelId": "Modell-ID eingeben...",
"modelId": "Modell-ID",
"useCustomBaseUrl": "Benutzerdefinierte Basis-URL verwenden",
"apiKeyInfo": "Dieser Schlüssel wird lokal gespeichert und nur verwendet, um API-Anfragen von dieser Erweiterung zu stellen.",
"getApiKeyMessage": "Sie können einen {{vendor}}-API-Schlüssel erhalten, indem Sie sich hier anmelden.",
"getApiVendorKey": "{{vendor}}-API-Schlüssel",
"getCompatibleVendor": "{{vendor}} kompatibel",
"enterGcpProjectId": "Projekt-ID eingeben...",
"gcpProjectId": "Google Cloud Projekt-ID",
"gcpLinks": "Um Google Cloud Vertex AI zu verwenden, müssen Sie <Link href=\"https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#before_you_begin\"> 1) ein Google Cloud-Konto erstellen die Vertex AI API aktivieren die gewünschten Claude-Modelle aktivieren, </Link><br /> <Link href=\"https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp\"> 2) die Google Cloud CLI installieren Anwendungsstandardanmeldeinformationen konfigurieren. </Link>",
"enterAwsAccessKey": "Zugriffsschlüssel eingeben...",
"awsAccessKey": "AWS-Zugriffsschlüssel",
"enterAwsSecretKey": "Geheimschlüssel eingeben...",
"awsSecretKey": "AWS-Geheimschlüssel",
"enterAwsSessionToken": "Sitzungstoken eingeben...",
"awsSessionToken": "AWS-Sitzungstoken",
"awsRegion": "AWS-Region",
"getRegion": "{{vendor}}-Region",
"selectRegion": "Region auswählen...",
"useCrossRegionInference": "Regionsübergreifende Inferenz verwenden",
"awsInfo": "Authentifizieren Sie sich entweder durch Eingabe der oben genannten Schlüssel oder verwenden Sie die Standard-AWS-Anmeldeinformationen, d.h. ~/.aws/credentials oder Umgebungsvariablen. Diese Anmeldeinformationen werden nur lokal verwendet, um API-Anfragen von dieser Erweiterung zu stellen.",
"vscodeLanguageModelsInfo": "Die VS Code Language Model API ermöglicht es Ihnen, Modelle zu verwenden, die von anderen VS Code-Erweiterungen bereitgestellt werden (einschließlich, aber nicht beschränkt auf GitHub Copilot). Der einfachste Weg, um loszulegen, ist die Installation der Copilot-Erweiterung aus dem VS Marketplace und die Aktivierung von Claude 3.5 Sonnet.",
"experimentalFeature": "Hinweis: Dies ist eine sehr experimentelle Integration und funktioniert möglicherweise nicht wie erwartet.",
"supportsImages": "Unterstützt Bilder",
"doesNotSupportImages": "Unterstützt keine Bilder",
"supportsComputerUse": "Unterstützt Computernutzung",
"doesNotSupportComputerUse": "Unterstützt keine Computernutzung",
"supportsPromptCache": "Unterstützt Prompt-Caching",
"doesNotSupportPromptCache": "Unterstützt kein Prompt-Caching",
"maxOutput": "Maximale Ausgabe",
"tokens": "Token",
"inputPrice": "Eingabepreis",
"millionTokens": "Millionen Token",
"cacheWritesPrice": "Preis für Cache-Schreibvorgänge",
"cacheReadsPrice": "Preis für Cache-Lesevorgänge",
"outputPrice": "Ausgabepreis",
"geminiInfo": "* Kostenlos bis zu {{selectedModelId}} Anfragen pro Minute. Danach hängt die Abrechnung von der Promptgröße ab.",
"pricingDetails": "Weitere Informationen finden Sie in den Preisdaten.",
"languageModel": "Sprachmodell"
}
}

View file

@ -0,0 +1,72 @@
{
"announcement": {
"newInVersion": "New in version {{version}}",
"joinOurCommunities": "Join our <DiscordLink>Discord</DiscordLink> or <RedditLink>Reddit</RedditLink> for more updates!"
},
"settingsView": {
"settings": "Settings",
"done": "Done",
"language": "Language",
"customInstructions": "Custom Instructions",
"customInstructionsPlaceholder": "e.g. \"Run unit tests at the end\", \"Use TypeScript with async/await\", \"Speak in Japanese\"",
"customInstructionsDescription": "These instructions are added to the end of the system prompt sent with every request.",
"debug": "Debug",
"resetState": "Reset State",
"resetStateDescription": "This will reset all global state and secret storage in the extension.",
"feedback": "If you have any questions or feedback, feel free to open an issue at",
"version": "v"
},
"apiOptions": {
"selectModel": "Select a Model...",
"model": "Model",
"apiProvider": "API Provider",
"enterApiKey": "Enter API Key...",
"apiKey": "API Key",
"enterBaseUrl": "Enter Base URL...",
"baseUrl": "Base URL",
"optionalBaseUrl": "Base URL (optional)",
"enterModelId": "Enter Model ID...",
"modelId": "Model ID",
"useCustomBaseUrl": "Use custom base URL",
"apiKeyInfo": "This key is stored locally and only used to make API requests from this extension.",
"getDefault": "Default: {{defaultValue}}",
"getApiKeyMessage": "You can get an {{vendor}} API key by signing up here.",
"getApiVendorKey": "{{vendor}} API Key",
"getCompatibleVendor": "{{vendor}} Compatible",
"lmStudioInfo": "LM Studio allows you to run models locally on your computer. For instructions on how to get started, see their <Link href=\"https://lmstudio.ai/docs\">quickstart guide.</Link> You will also need to start LM Studio's <Link href=\"https://lmstudio.ai/docs/basics/server\">local server</Link> feature to use it with this extension. <ErrSpan>(<b>Note:</b> Cline uses complex prompts and works best with Claude models. Less capable models may not work as expected.)</ErrSpan>",
"ollamaInfo": "Ollama allows you to run models locally on your computer. For instructions on how to get started, see their <Link href=\"https://github.com/ollama/ollama/blob/main/README.md\">quickstart guide.</Link> <ErrorSpan>(<b>Note:</b> Cline uses complex prompts and works best with Claude models. Less capable models may not work as expected.)</ErrorSpan>",
"azureInfo": "<ErrSpan>(<b>Note:</b> Cline uses complex prompts and works best with Claude models. Less capable models may not work as expected.)</ErrSpan>",
"setAzureApiVersion": "Set Azure API version",
"enterGcpProjectId": "Enter Project ID...",
"gcpProjectId": "Google Cloud Project ID",
"gcpLinks": "To use Google Cloud Vertex AI, you need to <Link href=\"https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#before_you_begin\"> 1) create a Google Cloud account enable the Vertex AI API enable the desired Claude models, </Link><br /> <Link href=\"https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp\"> 2) install the Google Cloud CLI configure Application Default Credentials. </Link>",
"enterAwsAccessKey": "Enter Access Key...",
"awsAccessKey": "AWS Access Key",
"enterAwsSecretKey": "Enter Secret Key...",
"awsSecretKey": "AWS Secret Key",
"enterAwsSessionToken": "Enter Session Token...",
"awsSessionToken": "AWS Session Token",
"getRegion": "{{vendor}} Region",
"selectRegion": "Select a Region...",
"useCrossRegionInference": "Use cross-region inference",
"awsInfo": "Authenticate by either providing the keys above or use the default AWS credential providers, i.e. ~/.aws/credentials or environment variables. These credentials are only used locally to make API requests from this extension.",
"vscodeLanguageModelsInfo": "The VS Code Language Model API allows you to run models provided by other VS Code extensions (including but not limited to GitHub Copilot). The easiest way to get started is to install the Copilot extension from the VS Marketplace and enabling Claude 3.5 Sonnet.",
"experimentalFeature": "Note: This is a very experimental integration and may not work as expected.",
"supportsImages": "Supports images",
"doesNotSupportImages": "Does not support images",
"supportsComputerUse": "Supports computer use",
"doesNotSupportComputerUse": "Does not support computer use",
"supportsPromptCache": "Supports prompt caching",
"doesNotSupportPromptCache": "Does not support prompt caching",
"maxOutput": "Max output",
"tokens": "tokens",
"inputPrice": "Input price",
"millionTokens": "million tokens",
"cacheWritesPrice": "Cache writes price",
"cacheReadsPrice": "Cache reads price",
"outputPrice": "Output price",
"geminiInfo": "* Free up to {{selectedModelId}} requests per minute. After that, billing depends on prompt size.",
"pricingDetails": "For more info, see pricing details.",
"languageModel": "Language Model"
}
}

View file

@ -0,0 +1,72 @@
{
"announcement": {
"newInVersion": "バージョン{{version}}の新機能",
"joinOurCommunities": "最新情報については、<DiscordLink>Discord</DiscordLink> または <RedditLink>Reddit</RedditLink> にぜひご参加ください!"
},
"settingsView": {
"settings": "設定",
"done": "完了",
"language": "言語",
"customInstructions": "カスタム指示",
"customInstructionsPlaceholder": "例: 「最後にユニットテストを実行する」、「async/awaitでTypeScriptを使用する」、「英語で話す」",
"customInstructionsDescription": "これらの指示は、各リクエストで送信されるシステムプロンプトの末尾に追加されます。",
"debug": "デバッグ",
"resetState": "状態をリセット",
"resetStateDescription": "拡張機能のすべてのグローバル状態とシークレットストレージがリセットされます。",
"feedback": "ご質問やフィードバックがある場合は、ご自由にイシューを作成してください。",
"version": "バージョン"
},
"apiOptions": {
"selectModel": "モデルを選択...",
"model": "モデル",
"apiProvider": "APIプロバイダー",
"enterApiKey": "APIキーを入力...",
"apiKey": "APIキー",
"enterBaseUrl": "ベースURLを入力...",
"baseUrl": "ベースURL",
"optionalBaseUrl": "ベースURL任意",
"enterModelId": "モデルIDを入力...",
"modelId": "モデルID",
"useCustomBaseUrl": "カスタムベースURLを使用",
"apiKeyInfo": "このキーはローカル環境にのみ保存され、拡張機能によるAPIリクエストでのみ使用されます。",
"getDefault": "デフォルト: {{defaultValue}}",
"getApiKeyMessage": "{{vendor}}のAPIキーは、こちらでサインアップして取得できます。",
"getApiVendorKey": "{{vendor}} APIキー",
"getCompatibleVendor": "{{vendor}}互換",
"lmStudioInfo": "LM Studioを使用すると、モデルをローカルコンピューターで実行できます。始め方については、<Link href=\"https://lmstudio.ai/docs\">クイックスタートガイド</Link>をご覧ください。また、この拡張機能で使用するには、LM Studioの<Link href=\"https://lmstudio.ai/docs/basics/server\">ローカルサーバー</Link>機能を起動する必要があります。<ErrSpan>(<b>注意:</b> Clineは複雑なプロンプトを使用するため、Claudeモデルで最適に動作します。処理能力の低いモデルでは、期待通りに動作しない可能性があります。)</ErrSpan>",
"ollamaInfo": "Ollamaを使用すると、モデルをローカルコンピューターで実行できます。始め方については、<Link href=\"https://github.com/ollama/ollama/blob/main/README.md\">クイックスタートガイド</Link>をご覧ください。<ErrorSpan>(<b>注意:</b> Clineは複雑なプロンプトを使用するため、Claudeモデルで最適に動作します。処理能力の低いモデルでは、期待通りに動作しない可能性があります。)</ErrorSpan>",
"azureInfo": "<ErrSpan>(<b>注意:</b> Clineは複雑なプロンプトを使用するため、Claudeモデルで最適に動作します。処理能力の低いモデルでは、期待通りに動作しない可能性があります。)</ErrSpan>",
"setAzureApiVersion": "Azure APIバージョンを設定",
"enterGcpProjectId": "プロジェクトIDを入力...",
"gcpProjectId": "Google CloudプロジェクトID",
"gcpLinks": "Google Cloud Vertex AIを使用するには、<Link href=\"https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#before_you_begin\"> 1) Google Cloudアカウントを作成 Vertex AI APIを有効化 Claudeモデルを有効化</Link><br /> <Link href=\"https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp\"> 2) Google Cloud CLIをインストール アプリケーションデフォルト認証情報を設定</Link>が必要です。",
"enterAwsAccessKey": "アクセスキーを入力...",
"awsAccessKey": "AWSアクセスキー",
"enterAwsSecretKey": "シークレットキーを入力...",
"awsSecretKey": "AWSシークレットキー",
"enterAwsSessionToken": "セッショントークンを入力...",
"awsSessionToken": "AWSセッショントークン",
"getRegion": "{{vendor}} リージョン",
"selectRegion": "リージョンを選択...",
"useCrossRegionInference": "クロスリージョン推論を使用",
"awsInfo": "上記のキーを入力するか、デフォルトのAWS認証プロバイダー (例: ~/.aws/credentials または環境変数) を使用して認証してください。これらの認証情報は、この拡張機能からのAPIリクエストにのみローカルで使用されます。",
"vscodeLanguageModelsInfo": "VS Code Language Model APIを使用すると、他のVS Code拡張機能 (GitHub Copilotなど) が提供するモデルを実行できます。始める最も簡単な方法は、VSマーケットプレイスからCopilot拡張機能をインストールし、Claude 3.5 Sonnetを有効化することです。",
"experimentalFeature": "注意: これは試験的な統合機能であり、意図した通りに動作しない場合があります。",
"supportsImages": "画像サポートあり",
"doesNotSupportImages": "画像サポートなし",
"supportsComputerUse": "コンピューター利用サポートあり",
"doesNotSupportComputerUse": "コンピューター利用サポートなし",
"supportsPromptCache": "プロンプトキャッシュサポートあり",
"doesNotSupportPromptCache": "プロンプトキャッシュサポートなし",
"maxOutput": "最大出力",
"tokens": "トークン",
"inputPrice": "入力価格",
"millionTokens": "百万トークン",
"cacheWritesPrice": "キャッシュ書き込み価格",
"cacheReadsPrice": "キャッシュ読み取り価格",
"outputPrice": "出力価格",
"geminiInfo": "* {{selectedModelId}} リクエスト毎分まで無料。その後、料金はプロンプトサイズに基づいて計算されます。",
"pricingDetails": "詳細については料金情報をご確認ください。",
"languageModel": "言語モデル"
}
}

View file

@ -0,0 +1,67 @@
{
"announcement": {
"newInVersion": "版本 {{version}} 中的新功能",
"joinOurCommunities": "加入我们的 <DiscordLink>Discord</DiscordLink> 或 <RedditLink>Reddit</RedditLink> 获取更多更新!"
},
"settingsView": {
"settings": "设置",
"done": "完成",
"language": "语言",
"customInstructions": "自定义指令",
"customInstructionsPlaceholder": "例如 \"在结束时运行单元测试\", \"使用 TypeScript 和 async/await\", \"用日语交流\"",
"customInstructionsDescription": "这些指令会添加到每个请求发送的系统提示的末尾。",
"debug": "调试",
"resetState": "重置状态",
"resetStateDescription": "这将重置扩展中的所有全局状态和秘密存储。",
"feedback": "如果您有任何问题或反馈,请随时在以下网址提交问题",
"version": "版本"
},
"apiOptions": {
"selectModel": "选择模型...",
"model": "模型",
"apiProvider": "API 提供商",
"enterApiKey": "请输入 API 密钥...",
"apiKey": "API 密钥",
"enterBaseUrl": "输入基本 URL...",
"baseUrl": "基本 URL",
"enterModelId": "输入模型 ID...",
"modelId": "模型 ID",
"useCustomBaseUrl": "使用自定义基本 URL",
"apiKeyInfo": "此密钥存储在本地,仅用于从此扩展进行 API 请求。",
"getApiKeyMessage": "您可以通过在此处注册来获取 {{vendor}} API 密钥。",
"getApiVendorKey": "{{vendor}} API 密钥",
"getCompatibleVendor": "{{vendor}} 兼容",
"enterGcpProjectId": "输入项目 ID...",
"gcpProjectId": "Google Cloud 项目 ID",
"gcpLinks": "要使用 Google Cloud Vertex AI您需要 <Link href=\"https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#before_you_begin\"> 1) 创建一个 Google Cloud 帐户 启用 Vertex AI API 启用所需的 Claude 模型,</Link><br /> <Link href=\"https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp\"> 2) 安装 Google Cloud CLI 配置应用程序默认凭据。</Link>",
"enterAwsAccessKey": "输入访问密钥...",
"awsAccessKey": "AWS 访问密钥",
"enterAwsSecretKey": "输入秘密密钥...",
"awsSecretKey": "AWS 密钥",
"enterAwsSessionToken": "输入会话令牌...",
"awsSessionToken": "AWS 会话令牌",
"awsRegion": "AWS 区域",
"getRegion": "{{vendor}} 区域",
"selectRegion": "选择区域...",
"useCrossRegionInference": "使用跨区域推理",
"awsInfo": "通过提供上述密钥或使用默认的 AWS 凭证提供程序进行身份验证,即 ~/.aws/credentials 或环境变量。这些凭证仅在本地用于从此扩展进行 API 请求。",
"vscodeLanguageModelsInfo": "VS Code 语言模型 API 允许您运行其他 VS Code 扩展提供的模型(包括但不限于 GitHub Copilot。最简单的方法是从 VS Marketplace 安装 Copilot 扩展并启用 Claude 3.5 Sonnet。",
"experimentalFeature": "注意:这是一个非常实验性功能,可能无法按预期工作。",
"supportsImages": "支持图像",
"doesNotSupportImages": "不支持图像",
"supportsComputerUse": "支持计算机使用",
"doesNotSupportComputerUse": "不支持计算机使用",
"supportsPromptCache": "支持提示缓存",
"doesNotSupportPromptCache": "不支持提示缓存",
"maxOutput": "最大输出",
"tokens": "令牌",
"inputPrice": "输入价格",
"millionTokens": "百万令牌",
"cacheWritesPrice": "缓存写入价格",
"cacheReadsPrice": "缓存读取价格",
"outputPrice": "输出价格",
"geminiInfo": "* 每分钟最多 {{selectedModelId}} 次请求免费。之后,费用取决于提示大小。",
"pricingDetails": "有关更多信息,请参阅定价详情。",
"languageModel": "语言模型"
}
}

View file

@ -0,0 +1,67 @@
{
"announcement": {
"newInVersion": "版本 {{version}} 中的新功能",
"joinOurCommunities": "加入我們的 <DiscordLink>Discord</DiscordLink> 或 <RedditLink>Reddit</RedditLink> 獲取更多更新!"
},
"settingsView": {
"settings": "設置",
"done": "完成",
"language": "語言",
"customInstructions": "自定義指令",
"customInstructionsPlaceholder": "例如 \"在結束時運行單元測試\", \"使用 TypeScript 和 async/await\", \"用日語交流\"",
"customInstructionsDescription": "這些指令會添加到每個請求發送的系統提示的末尾。",
"debug": "調試",
"resetState": "重置狀態",
"resetStateDescription": "這將重置擴展中的所有全局狀態和秘密存儲。",
"feedback": "如果您有任何問題或反饋,請隨時在以下網址提交問題",
"version": "版本"
},
"apiOptions": {
"selectModel": "選擇模型...",
"model": "模型",
"apiProvider": "API 提供者",
"enterApiKey": "請輸入 API 密鑰...",
"apiKey": "API 密鑰",
"enterBaseUrl": "輸入基本 URL...",
"baseUrl": "基本 URL",
"enterModelId": "輸入模型 ID...",
"modelId": "模型 ID",
"useCustomBaseUrl": "使用自定義基本 URL",
"apiKeyInfo": "此密鑰僅存儲在本地,僅用於從此擴展進行 API 請求。",
"getApiKeyMessage": "您可以通過在此處註冊來獲取 {{vendor}} API 金鑰。",
"getApiVendorKey": "{{vendor}} API 金鑰",
"getCompatibleVendor": "{{vendor}} 兼容",
"enterGcpProjectId": "輸入項目 ID...",
"gcpProjectId": "Google Cloud 項目 ID",
"gcpLinks": "要使用 Google Cloud Vertex AI您需要 <Link href=\"https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#before_you_begin\"> 1) 創建 Google Cloud 帳戶 啟用 Vertex AI API 啟用所需的 Claude 模型, </Link><br /> <Link href=\"https://cloud.google.com/docs/authentication/provide-credentials-adc#google-idp\"> 2) 安裝 Google Cloud CLI 配置應用程序默認憑據。 </Link>",
"enterAwsAccessKey": "輸入訪問金鑰...",
"awsAccessKey": "AWS 訪問金鑰",
"enterAwsSecretKey": "輸入秘密金鑰...",
"awsSecretKey": "AWS 秘密金鑰",
"enterAwsSessionToken": "輸入會話令牌...",
"awsSessionToken": "AWS 會話令牌",
"awsRegion": "AWS 區域",
"getRegion": "{{vendor}} 區域",
"selectRegion": "選擇區域...",
"useCrossRegionInference": "使用跨區域推理",
"awsInfo": "通過提供上述金鑰或使用默認的 AWS 憑據提供者進行身份驗證,即 ~/.aws/credentials 或環境變量。這些憑據僅在本地用於從此擴展進行 API 請求。",
"vscodeLanguageModelsInfo": "VS Code 語言模型 API 允許您運行其他 VS Code 擴展提供的模型(包括但不限於 GitHub Copilot。最簡單的入門方法是從 VS Marketplace 安裝 Copilot 擴展並啟用 Claude 3.5 Sonnet。",
"experimentalFeature": "注意:這是一個非常實驗性的集成,可能無法按預期工作。",
"supportsImages": "支持圖片",
"doesNotSupportImages": "不支持圖片",
"supportsComputerUse": "支持電腦使用",
"doesNotSupportComputerUse": "不支持電腦使用",
"supportsPromptCache": "支持提示緩存",
"doesNotSupportPromptCache": "不支持提示緩存",
"maxOutput": "最大輸出",
"tokens": "標記",
"inputPrice": "輸入價格",
"millionTokens": "百萬標記",
"cacheWritesPrice": "緩存寫入價格",
"cacheReadsPrice": "緩存讀取價格",
"outputPrice": "輸出價格",
"geminiInfo": "* 每分鐘最多免費 {{selectedModelId}} 次請求。之後,計費取決於提示大小。",
"pricingDetails": "更多信息,請參見定價詳情。",
"languageModel": "語言模型"
}
}