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
32 changes: 18 additions & 14 deletions components/ModelsConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ function ThinkingLevelMapEditor({
value: Record<string, string | null> | undefined;
onChange: (v: Record<string, string | null> | undefined) => void;
}) {
const { t } = useI18n();
const map = value ?? {};

const setLevel = (level: ThinkingLevel, entry: string | null | "omit") => {
Expand Down Expand Up @@ -646,13 +647,13 @@ function ThinkingLevelMapEditor({
onClick={() => setLevel(level, "omit")}
style={{ ...btnBase, ...(state === "omit" ? btnActive : {}) }}
>
Default
{t("i18n.default")}
</button>
<button
onClick={() => setLevel(level, null)}
style={{ ...btnBase, borderLeft: "1px solid var(--border)", ...(state === "null" ? btnActiveDisabled : {}) }}
>
Disabled
{t("i18n.disabled")}
</button>
</div>

Expand All @@ -661,7 +662,7 @@ function ThinkingLevelMapEditor({
onClick={() => setLevel(level, strVal || level)}
style={{ ...btnBase, ...(state === "string" ? btnActive : {}), borderRight: "1px solid var(--border)", flexShrink: 0 }}
>
Custom
{t("i18n.custom")}
</button>
<input
value={strVal}
Expand Down Expand Up @@ -725,6 +726,7 @@ function HeaderListEditor({ headers, onChange }: {
headers: Record<string, string> | undefined;
onChange: (h: Record<string, string> | undefined) => void;
}) {
const { t } = useI18n();
const [rows, setRows] = useState<HeaderRow[]>(() => Object.entries(headers ?? {}).map(
([name, value], id) => ({ id, name, value }),
));
Expand Down Expand Up @@ -766,7 +768,7 @@ function HeaderListEditor({ headers, onChange }: {
{ id: nextRowIdRef.current++, name: "", value: "" },
])}
style={{ padding: "5px 9px", background: "none", border: "1px solid var(--border)", borderRadius: 4, color: "var(--text-muted)", cursor: "pointer", fontSize: 11, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 5, alignSelf: "flex-start" }}>
+ Add header
+ {t("models.addHeader")}
</button>
</div>
);
Expand Down Expand Up @@ -1093,7 +1095,7 @@ function ModelDetail({

<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
<Field label="ID *"><TextInput value={model.id} onChange={(v) => set("id", v)} placeholder="model-id" mono /></Field>
<Field label="Name"><TextInput value={model.name ?? ""} onChange={(v) => set("name", v || undefined)} placeholder="Display name" /></Field>
<Field label="Name"><TextInput value={model.name ?? ""} onChange={(v) => set("name", v || undefined)} placeholder={t("models.displayNamePlaceholder")} /></Field>
</div>

<div style={{ padding: "2px 0" }}>
Expand Down Expand Up @@ -1499,7 +1501,7 @@ function OAuthDetail({ provider, onRefresh, enabledModels, contextSettings }: {
{loginState.phase === "idle" && (
!provider.loggedIn && (
<p style={{ margin: 0, fontSize: 12, color: "var(--text-muted)", lineHeight: 1.5 }}>
Connect your {provider.name} account.
{t("models.oauthConnect", { provider: provider.name })}
</p>
)
)}
Expand Down Expand Up @@ -1527,19 +1529,19 @@ function OAuthDetail({ provider, onRefresh, enabledModels, contextSettings }: {
{(loginState.phase === "auth" || loginState.phase === "prompt") && (
<OAuthPastePanel
message={loginState.phase === "auth"
? "Complete sign-in in the browser, then copy the redirect URL from the address bar and paste it below."
? t("models.oauthPasteRedirect")
: loginState.message}
hint={loginState.phase === "auth" ? (
<>
If the browser window did not open,{" "}
{t("models.oauthNoBrowser")}{" "}
<a href={loginState.url} target="_blank" rel="noopener noreferrer">
click here to open the login page
{t("models.oauthOpenLoginPage")}
</a>
.
{t("models.oauthOpenLoginPageEnd")}
</>
) : undefined}
value={inputValue}
placeholder={loginState.phase === "auth" ? "http://localhost:1455/auth/callback?code=…" : (loginState.placeholder ?? "Enter value…")}
placeholder={loginState.phase === "auth" ? "http://localhost:1455/auth/callback?code=…" : (loginState.placeholder ?? t("models.oauthValuePlaceholder"))}
submitLabel={t("i18n.submit")}
inputRef={inputRef}
onValueChange={setInputValue}
Expand All @@ -1549,7 +1551,7 @@ function OAuthDetail({ provider, onRefresh, enabledModels, contextSettings }: {
{loginState.phase === "device_code" && (
<div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
<p style={{ margin: 0, fontSize: 12, color: "var(--text-muted)", lineHeight: 1.5 }}>
Open the verification page and enter this code:
{t("models.oauthDeviceCode")}
</p>
<div style={{ padding: "8px 10px", background: "var(--bg)", border: "1px solid var(--border)", borderRadius: 5, color: "var(--text)", fontSize: 16, fontWeight: 700, fontFamily: "var(--font-mono)", letterSpacing: 0 }}>
{loginState.userCode}
Expand Down Expand Up @@ -1670,7 +1672,9 @@ function ApiKeyDetail({ provider, onRefresh, enabledModels, contextSettings }: {

{!provider.configured && (
<p style={{ margin: 0, fontSize: 12, color: "var(--text-muted)", lineHeight: 1.5 }}>
Enter your {provider.displayName} API key to enable {provider.modelCount} model{provider.modelCount !== 1 ? "s" : ""}.
{provider.modelCount === 1
? t("models.apiKeyEnableOne", { provider: provider.displayName })
: t("models.apiKeyEnable", { provider: provider.displayName, count: provider.modelCount })}
</p>
)}

Expand Down Expand Up @@ -1843,7 +1847,7 @@ function AddProviderPicker({
>
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ fontSize: 12, fontWeight: 600, color: "var(--text)", lineHeight: 1.3, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{p.displayName}</div>
<div style={{ fontSize: 10, color: "var(--text-dim)", marginTop: 2 }}>{p.modelCount} models</div>
<div style={{ fontSize: 10, color: "var(--text-dim)", marginTop: 2 }}>{p.modelCount === 1 ? t("models.modelCountOne") : t("models.modelCount", { count: p.modelCount })}</div>
</div>
<ProviderIcon id={p.id} size={28} />
</button>
Expand Down
13 changes: 13 additions & 0 deletions lib/i18n/messages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,19 @@ export const enLocale: LocalePlugin = {
"models.configUnreadable": "Could not read models.json, so saving is disabled to avoid overwriting it. Fix the file, then reopen this panel. {error}",
"models.providerNameTaken": "Another provider is already named \"{name}\". Choose a different name.",
"models.apiKeyPlaceholder": "ENV_VAR_NAME, !shell-command, or literal key",
"models.apiKeyEnable": "Enter your {provider} API key to enable {count} models.",
"models.apiKeyEnableOne": "Enter your {provider} API key to enable 1 model.",
"models.modelCount": "{count} models",
"models.modelCountOne": "1 model",
"models.oauthConnect": "Connect your {provider} account.",
"models.oauthPasteRedirect": "Complete sign-in in the browser, then copy the redirect URL from the address bar and paste it below.",
"models.oauthNoBrowser": "If the browser window did not open,",
"models.oauthOpenLoginPage": "click here to open the login page",
"models.oauthOpenLoginPageEnd": ".",
"models.oauthValuePlaceholder": "Enter value…",
"models.oauthDeviceCode": "Open the verification page and enter this code:",
"models.addHeader": "Add header",
"models.displayNamePlaceholder": "Display name",
"models.discoveryAdded": "added",
"models.discoveryShowing": "Showing first {shown} of {total}",
"models.discoveryFetched": "{count} models fetched",
Expand Down
13 changes: 13 additions & 0 deletions lib/i18n/messages/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,19 @@ export const zhCNLocale: LocalePlugin = {
"models.configUnreadable": "无法读取 models.json,为避免覆盖已禁用保存。请修复该文件后重新打开此面板。{error}",
"models.providerNameTaken": "已存在名为“{name}”的 Provider,请换一个名称。",
"models.apiKeyPlaceholder": "环境变量名、!shell 命令或密钥",
"models.apiKeyEnable": "输入 {provider} 的 API Key,即可启用 {count} 个模型。",
"models.apiKeyEnableOne": "输入 {provider} 的 API Key,即可启用 1 个模型。",
"models.modelCount": "{count} 个模型",
"models.modelCountOne": "1 个模型",
"models.oauthConnect": "连接你的 {provider} 账号。",
"models.oauthPasteRedirect": "在浏览器中完成登录,然后从地址栏复制跳转后的地址,粘贴到下面。",
"models.oauthNoBrowser": "如果浏览器窗口没有打开,",
"models.oauthOpenLoginPage": "点此打开登录页",
"models.oauthOpenLoginPageEnd": "。",
"models.oauthValuePlaceholder": "输入内容…",
"models.oauthDeviceCode": "打开验证页面,输入下面的代码:",
"models.addHeader": "添加 Header",
"models.displayNamePlaceholder": "显示名称",
"models.discoveryAdded": "已添加",
"models.discoveryShowing": "显示前 {shown} 个,共 {total} 个",
"models.discoveryFetched": "已获取 {count} 个模型",
Expand Down
13 changes: 13 additions & 0 deletions lib/i18n/messages/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,19 @@ export const zhTWLocale: LocalePlugin = {
"models.configUnreadable": "無法讀取 models.json,為避免覆寫已停用儲存。請修正該檔案後重新開啟此面板。{error}",
"models.providerNameTaken": "已存在名為「{name}」的 Provider,請換一個名稱。",
"models.apiKeyPlaceholder": "環境變數名稱、!shell 命令或金鑰",
"models.apiKeyEnable": "輸入 {provider} 的 API Key,即可啟用 {count} 個模型。",
"models.apiKeyEnableOne": "輸入 {provider} 的 API Key,即可啟用 1 個模型。",
"models.modelCount": "{count} 個模型",
"models.modelCountOne": "1 個模型",
"models.oauthConnect": "連接你的 {provider} 帳號。",
"models.oauthPasteRedirect": "在瀏覽器中完成登入,然後從網址列複製跳轉後的網址,貼到下方。",
"models.oauthNoBrowser": "如果瀏覽器視窗沒有開啟,",
"models.oauthOpenLoginPage": "點此開啟登入頁面",
"models.oauthOpenLoginPageEnd": "。",
"models.oauthValuePlaceholder": "輸入內容…",
"models.oauthDeviceCode": "開啟驗證頁面,輸入下方的代碼:",
"models.addHeader": "新增 Header",
"models.displayNamePlaceholder": "顯示名稱",
"models.discoveryAdded": "已新增",
"models.discoveryShowing": "顯示前 {shown} 個,共 {total} 個",
"models.discoveryFetched": "已取得 {count} 個模型",
Expand Down
Loading