























@@ -5,6 +5,7 @@ import { ensureApiKeyFromEnvOrPrompt } from "../plugins/provider-auth-input.js";
55import type { RuntimeEnv } from "../runtime.js";
66import { fetchWithTimeout } from "../utils/fetch-timeout.js";
77import { normalizeSecretInput } from "../utils/normalize-secret-input.js";
8+import { t } from "../wizard/i18n/index.js";
89import type { WizardPrompter } from "../wizard/prompts.js";
910import {
1011applyCustomApiConfig,
@@ -45,23 +46,23 @@ type CustomApiCompatibilityChoice = CustomApiCompatibility | "unknown";
45464647const COMPATIBILITY_OPTIONS: Array<{
4748value: CustomApiCompatibilityChoice;
48-label: string;
49-hint: string;
49+labelKey: string;
50+hintKey: string;
5051}> = [
5152{
5253value: "openai",
53-label: "OpenAI-compatible",
54-hint: "Uses /chat/completions",
54+labelKey: "wizard.customProvider.compatibilityOpenAi",
55+hintKey: "wizard.customProvider.compatibilityOpenAiHint",
5556},
5657{
5758value: "anthropic",
58-label: "Anthropic-compatible",
59-hint: "Uses /messages",
59+labelKey: "wizard.customProvider.compatibilityAnthropic",
60+hintKey: "wizard.customProvider.compatibilityAnthropicHint",
6061},
6162{
6263value: "unknown",
63-label: "Unknown (detect automatically)",
64-hint: "Probes OpenAI then Anthropic endpoints",
64+labelKey: "wizard.customProvider.compatibilityUnknown",
65+hintKey: "wizard.customProvider.compatibilityUnknownHint",
6566},
6667];
6768@@ -135,11 +136,11 @@ async function promptBaseUrlAndKey(params: {
135136initialBaseUrl?: string;
136137}): Promise<{ baseUrl: string; apiKey?: SecretInput; resolvedApiKey: string }> {
137138const baseUrlInput = await params.prompter.text({
138-message: "API Base URL",
139+message: t("wizard.customProvider.apiBaseUrl"),
139140initialValue: params.initialBaseUrl,
140141placeholder: "https://api.example.com/v1",
141142validate: (val) => {
142-return URL.canParse(val) ? undefined : "Please enter a valid URL (e.g. http://...)";
143+return URL.canParse(val) ? undefined : t("wizard.customProvider.validUrl");
143144},
144145});
145146const baseUrl = baseUrlInput.trim();
@@ -149,7 +150,7 @@ async function promptBaseUrlAndKey(params: {
149150config: params.config,
150151provider: providerHint,
151152envLabel: "CUSTOM_API_KEY",
152-promptMessage: "API Key (leave blank if not required)",
153+promptMessage: t("wizard.customProvider.apiKeyPrompt"),
153154normalize: normalizeSecretInput,
154155validate: () => undefined,
155156prompter: params.prompter,
@@ -169,21 +170,21 @@ type CustomApiRetryChoice = "baseUrl" | "model" | "both";
169170170171async function promptCustomApiRetryChoice(prompter: WizardPrompter): Promise<CustomApiRetryChoice> {
171172return await prompter.select({
172-message: "What would you like to change?",
173+message: t("wizard.customProvider.retryChoice"),
173174options: [
174-{ value: "baseUrl", label: "Change base URL" },
175-{ value: "model", label: "Change model" },
176-{ value: "both", label: "Change base URL and model" },
175+{ value: "baseUrl", label: t("wizard.customProvider.changeBaseUrl") },
176+{ value: "model", label: t("wizard.customProvider.changeModel") },
177+{ value: "both", label: t("wizard.customProvider.changeBaseUrlAndModel") },
177178],
178179});
179180}
180181181182async function promptCustomApiModelId(prompter: WizardPrompter): Promise<string> {
182183return (
183184await prompter.text({
184-message: "Model ID",
185-placeholder: "e.g. llama3, claude-3-7-sonnet",
186-validate: (val) => (val.trim() ? undefined : "Model ID is required"),
185+message: t("wizard.customProvider.modelId"),
186+placeholder: t("wizard.customProvider.modelIdPlaceholder"),
187+validate: (val) => (val.trim() ? undefined : t("wizard.customProvider.modelIdRequired")),
187188})
188189).trim();
189190}
@@ -231,11 +232,11 @@ export async function promptCustomApiConfig(params: {
231232let resolvedApiKey = baseInput.resolvedApiKey;
232233233234const compatibilityChoice = await prompter.select({
234-message: "Endpoint compatibility",
235+message: t("wizard.customProvider.compatibility"),
235236options: COMPATIBILITY_OPTIONS.map((option) => ({
236237value: option.value,
237-label: option.label,
238-hint: option.hint,
238+label: t(option.labelKey),
239+hint: t(option.hintKey),
239240})),
240241});
241242@@ -247,14 +248,14 @@ export async function promptCustomApiConfig(params: {
247248while (true) {
248249let verifiedFromProbe = false;
249250if (!compatibility) {
250-const probeSpinner = prompter.progress("Detecting endpoint type...");
251+const probeSpinner = prompter.progress(t("wizard.customProvider.detectionProgress"));
251252const openaiProbe = await requestOpenAiVerification({
252253 baseUrl,
253254apiKey: resolvedApiKey,
254255 modelId,
255256});
256257if (openaiProbe.ok) {
257-probeSpinner.stop("Detected OpenAI-compatible endpoint.");
258+probeSpinner.stop(t("wizard.customProvider.detectedOpenAi"));
258259compatibility = "openai";
259260verifiedFromProbe = true;
260261} else {
@@ -264,14 +265,14 @@ export async function promptCustomApiConfig(params: {
264265 modelId,
265266});
266267if (anthropicProbe.ok) {
267-probeSpinner.stop("Detected Anthropic-compatible endpoint.");
268+probeSpinner.stop(t("wizard.customProvider.detectedAnthropic"));
268269compatibility = "anthropic";
269270verifiedFromProbe = true;
270271} else {
271-probeSpinner.stop("Could not detect endpoint type.");
272+probeSpinner.stop(t("wizard.customProvider.detectionFailed"));
272273await prompter.note(
273-"This endpoint did not respond to OpenAI or Anthropic style requests.",
274-"Endpoint detection",
274+t("wizard.customProvider.detectionFailedNote"),
275+t("wizard.customProvider.detectionNoteTitle"),
275276);
276277const retryChoice = await promptCustomApiRetryChoice(prompter);
277278({ baseUrl, apiKey, resolvedApiKey, modelId } = await applyCustomApiRetryChoice({
@@ -290,19 +291,25 @@ export async function promptCustomApiConfig(params: {
290291break;
291292}
292293293-const verifySpinner = prompter.progress("Verifying...");
294+const verifySpinner = prompter.progress(t("wizard.customProvider.verifying"));
294295const result =
295296compatibility === "anthropic"
296297 ? await requestAnthropicVerification({ baseUrl, apiKey: resolvedApiKey, modelId })
297298 : await requestOpenAiVerification({ baseUrl, apiKey: resolvedApiKey, modelId });
298299if (result.ok) {
299-verifySpinner.stop("Verification successful.");
300+verifySpinner.stop(t("wizard.customProvider.verificationSuccessful"));
300301break;
301302}
302303if (result.status !== undefined) {
303-verifySpinner.stop(`Verification failed: status ${result.status}`);
304+verifySpinner.stop(
305+t("wizard.customProvider.verificationFailedStatus", { status: result.status }),
306+);
304307} else {
305-verifySpinner.stop(`Verification failed: ${formatVerificationError(result.error)}`);
308+verifySpinner.stop(
309+t("wizard.customProvider.verificationFailedError", {
310+error: formatVerificationError(result.error),
311+}),
312+);
306313}
307314const retryChoice = await promptCustomApiRetryChoice(prompter);
308315({ baseUrl, apiKey, resolvedApiKey, modelId } = await applyCustomApiRetryChoice({
@@ -319,20 +326,20 @@ export async function promptCustomApiConfig(params: {
319326320327const suggestedId = buildEndpointIdFromUrl(baseUrl);
321328const providerIdInput = await prompter.text({
322-message: "Endpoint ID",
329+message: t("wizard.customProvider.endpointId"),
323330initialValue: suggestedId,
324331placeholder: "custom",
325332validate: (value) => {
326333const normalized = normalizeEndpointId(value);
327334if (!normalized) {
328-return "Endpoint ID is required.";
335+return t("wizard.customProvider.endpointIdRequired");
329336}
330337return undefined;
331338},
332339});
333340const aliasInput = await prompter.text({
334-message: "Model alias (optional)",
335-placeholder: "e.g. local, ollama",
341+message: t("wizard.customProvider.modelAlias"),
342+placeholder: t("wizard.customProvider.modelAliasPlaceholder"),
336343initialValue: "",
337344validate: (value) => {
338345const resolvedProvider = resolveCustomProviderId({
@@ -349,7 +356,7 @@ export async function promptCustomApiConfig(params: {
349356imageInputInference.confidence === "known"
350357 ? imageInputInference.supportsImageInput
351358 : await prompter.confirm({
352-message: "Does this model support image input?",
359+message: t("wizard.customProvider.imageInput"),
353360initialValue: imageInputInference.supportsImageInput,
354361});
355362const resolvedCompatibility = compatibility ?? "openai";
@@ -366,8 +373,11 @@ export async function promptCustomApiConfig(params: {
366373367374if (result.providerIdRenamedFrom && result.providerId) {
368375await prompter.note(
369-`Endpoint ID "${result.providerIdRenamedFrom}" already exists for a different base URL. Using "${result.providerId}".`,
370-"Endpoint ID",
376+t("wizard.customProvider.endpointIdRenamed", {
377+from: result.providerIdRenamedFrom,
378+to: result.providerId,
379+}),
380+t("wizard.customProvider.endpointIdTitle"),
371381);
372382}
373383此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。