mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
feat(i18n): extract en translations — context/lib/misc (#1251)
* feat(i18n): extract en translations for context/lib/misc Extract hardcoded English strings to i18n keys for: - automations context, providers store, shared-bundles - mcp-auth-modal, onboarding-workspace-selector, question-modal Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(i18n): second pass — extract remaining hardcoded strings Fix missed strings not covered by reference diff: - automations: schedule_required, prompt_required, prompt_empty, server_unavailable in deleteScheduledJob, failed_to_load in local block, provider_id_required (2 missed instances in store.ts) - mcp-auth-modal: request_timed_out - question-modal: Submit/Next button labels (common.submit, common.next) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(i18n): drop stale rebase artifacts --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: src-opn <src-opn@users.noreply.github.com>
This commit is contained in:
@@ -168,7 +168,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
statusPoll = window.setInterval(async () => {
|
||||
if (Date.now() - startedAt >= MCP_AUTH_TIMEOUT_MS) {
|
||||
stopStatusPolling();
|
||||
setError("Request timed out.");
|
||||
setError(translate("mcp.auth.request_timed_out"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -694,7 +694,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
<CheckCircle2 size={24} class="text-green-11" />
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-12">Already Connected</p>
|
||||
<p class="text-sm font-medium text-gray-12">{translate("mcp.auth.already_connected")}</p>
|
||||
<p class="text-xs text-gray-11">
|
||||
{translate("mcp.auth.already_connected_description", { server: serverName() })}
|
||||
</p>
|
||||
@@ -804,7 +804,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
</div>
|
||||
<div class="rounded-xl border border-gray-6/70 bg-gray-2/40 px-3 py-2 flex items-center gap-3">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="text-[10px] uppercase tracking-wide text-gray-8">Authorization link</div>
|
||||
<div class="text-[10px] uppercase tracking-wide text-gray-8">{translate("mcp.auth.authorization_link")}</div>
|
||||
<div class="text-[11px] text-gray-11 font-mono truncate">
|
||||
{authorizationUrl()}
|
||||
</div>
|
||||
@@ -814,7 +814,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
class="text-xs"
|
||||
onClick={handleCopyAuthorizationUrl}
|
||||
>
|
||||
{authUrlCopied() ? "Copied" : "Copy link"}
|
||||
{authUrlCopied() ? translate("mcp.auth.copied") : translate("mcp.auth.copy_link")}
|
||||
</Button>
|
||||
</div>
|
||||
<TextInput
|
||||
@@ -851,7 +851,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
1
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-12">Opening your browser</p>
|
||||
<p class="text-sm font-medium text-gray-12">{translate("mcp.auth.step1_title")}</p>
|
||||
<p class="text-xs text-gray-10 mt-1">
|
||||
{translate("mcp.auth.step1_description", { server: serverName() })}
|
||||
</p>
|
||||
@@ -863,7 +863,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
2
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-12">Authorize OpenWork</p>
|
||||
<p class="text-sm font-medium text-gray-12">{translate("mcp.auth.step2_title")}</p>
|
||||
<p class="text-xs text-gray-10 mt-1">
|
||||
{translate("mcp.auth.step2_description")}
|
||||
</p>
|
||||
@@ -875,7 +875,7 @@ export default function McpAuthModal(props: McpAuthModalProps) {
|
||||
3
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-12">Return here when you're done</p>
|
||||
<p class="text-sm font-medium text-gray-12">{translate("mcp.auth.step3_title")}</p>
|
||||
<p class="text-xs text-gray-10 mt-1">
|
||||
{translate("mcp.auth.step3_description")}
|
||||
</p>
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { QuestionInfo } from "@opencode-ai/sdk/v2/client";
|
||||
import { Check, ChevronRight, HelpCircle } from "lucide-solid";
|
||||
|
||||
import Button from "./button";
|
||||
import { t } from "../../i18n";
|
||||
|
||||
export type QuestionModalProps = {
|
||||
open: boolean;
|
||||
@@ -138,10 +139,10 @@ export default function QuestionModal(props: QuestionModalProps) {
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-gray-12">
|
||||
{currentQuestion()!.header || "Question"}
|
||||
{currentQuestion()!.header || t("common.question")}
|
||||
</h3>
|
||||
<div class="text-xs text-gray-11 font-medium">
|
||||
Question {currentIndex() + 1} of {props.questions.length}
|
||||
{t("question_modal.question_counter", undefined, { current: currentIndex() + 1, total: props.questions.length })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -186,14 +187,14 @@ export default function QuestionModal(props: QuestionModalProps) {
|
||||
<Show when={currentQuestion()!.custom}>
|
||||
<div class="mt-4 pt-4 border-t border-dls-border">
|
||||
<label class="block text-xs font-semibold text-dls-secondary mb-2 uppercase tracking-wide">
|
||||
Or type a custom answer
|
||||
{t("question_modal.custom_answer_label")}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={customInput()}
|
||||
onInput={(e) => setCustomInput(e.currentTarget.value)}
|
||||
class="w-full px-4 py-3 rounded-xl bg-dls-surface border border-dls-border focus:border-dls-accent focus:ring-4 focus:ring-[rgba(var(--dls-accent-rgb),0.2)] focus:outline-none text-sm text-dls-text placeholder:text-dls-secondary transition-shadow"
|
||||
placeholder="Type your answer here..."
|
||||
placeholder={t("question_modal.custom_answer_placeholder")}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (e.isComposing || e.keyCode === 229) return;
|
||||
@@ -209,15 +210,15 @@ export default function QuestionModal(props: QuestionModalProps) {
|
||||
<div class="p-6 border-t border-dls-border bg-dls-hover flex justify-between items-center">
|
||||
<div class="text-xs text-dls-secondary flex items-center gap-2">
|
||||
<span class="px-1.5 py-0.5 rounded border border-dls-border bg-dls-active font-mono">↑↓</span>
|
||||
<span>navigate</span>
|
||||
<span>{t("common.navigate")}</span>
|
||||
<span class="px-1.5 py-0.5 rounded border border-gray-6 bg-gray-3 font-mono ml-2">↵</span>
|
||||
<span>select</span>
|
||||
<span>{t("common.select")}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<Show when={currentQuestion()?.multiple || currentQuestion()?.custom}>
|
||||
<Button onClick={handleNext} disabled={!canProceed() || props.busy} class="!px-6">
|
||||
{isLastQuestion() ? "Submit" : "Next"}
|
||||
{isLastQuestion() ? t("common.submit") : t("common.next")}
|
||||
<Show when={!isLastQuestion()}>
|
||||
<ChevronRight size={16} class="ml-1 -mr-1 opacity-60" />
|
||||
</Show>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { schedulerDeleteJob, schedulerListJobs } from "../lib/tauri";
|
||||
import { isTauriRuntime } from "../utils";
|
||||
import { createWorkspaceContextKey } from "./workspace-context";
|
||||
import type { OpenworkServerStore } from "../connections/openwork-server-store";
|
||||
import { t } from "../../i18n";
|
||||
|
||||
export type AutomationsStore = ReturnType<typeof createAutomationsStore>;
|
||||
|
||||
@@ -33,10 +34,10 @@ const buildCreateAutomationPrompt = (
|
||||
const schedule = input.schedule.trim();
|
||||
const prompt = normalizeSentence(input.prompt);
|
||||
if (!schedule) {
|
||||
return { ok: false, error: "Schedule is required." };
|
||||
return { ok: false, error: t("automations.schedule_required") };
|
||||
}
|
||||
if (!prompt) {
|
||||
return { ok: false, error: "Prompt is required." };
|
||||
return { ok: false, error: t("automations.prompt_required") };
|
||||
}
|
||||
const workdir = (input.workdir ?? "").trim();
|
||||
const nameSegment = name ? ` named \"${name}\"` : "";
|
||||
@@ -58,7 +59,7 @@ const buildRunAutomationPrompt = (
|
||||
if (job.run?.prompt || job.prompt) {
|
||||
const promptBody = (job.run?.prompt ?? job.prompt ?? "").trim();
|
||||
if (!promptBody) {
|
||||
return { ok: false, error: "Automation prompt is empty." };
|
||||
return { ok: false, error: t("automations.prompt_empty") };
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
@@ -136,10 +137,10 @@ export function createAutomationsStore(options: {
|
||||
if (scheduledJobsContextKey() !== requestContextKey) return "skipped";
|
||||
const status =
|
||||
options.openworkServer.openworkServerStatus() === "disconnected"
|
||||
? "OpenWork server unavailable. Connect to sync scheduled tasks."
|
||||
? t("automations.server_unavailable")
|
||||
: options.openworkServer.openworkServerStatus() === "limited"
|
||||
? "OpenWork server needs a token to load scheduled tasks."
|
||||
: "OpenWork server not ready.";
|
||||
? t("automations.server_needs_token")
|
||||
: t("automations.server_not_ready");
|
||||
setScheduledJobsStatus(status);
|
||||
return "unavailable";
|
||||
}
|
||||
@@ -155,7 +156,7 @@ export function createAutomationsStore(options: {
|
||||
} catch (error) {
|
||||
if (scheduledJobsContextKey() !== requestContextKey) return "skipped";
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
setScheduledJobsStatus(message || "Failed to load scheduled tasks.");
|
||||
setScheduledJobsStatus(message || t("automations.failed_to_load"));
|
||||
return "error";
|
||||
} finally {
|
||||
setScheduledJobsBusy(false);
|
||||
@@ -180,7 +181,7 @@ export function createAutomationsStore(options: {
|
||||
} catch (error) {
|
||||
if (scheduledJobsContextKey() !== requestContextKey) return "skipped";
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
setScheduledJobsStatus(message || "Failed to load scheduled tasks.");
|
||||
setScheduledJobsStatus(message || t("automations.failed_to_load"));
|
||||
return "error";
|
||||
} finally {
|
||||
setScheduledJobsBusy(false);
|
||||
@@ -192,7 +193,7 @@ export function createAutomationsStore(options: {
|
||||
const client = options.openworkServer.openworkServerClient();
|
||||
const workspaceId = (options.runtimeWorkspaceId() ?? "").trim();
|
||||
if (!client || !workspaceId) {
|
||||
throw new Error("OpenWork server unavailable. Connect to sync scheduled tasks.");
|
||||
throw new Error(t("automations.server_unavailable"));
|
||||
}
|
||||
const response = await client.deleteScheduledJob(workspaceId, name);
|
||||
setScheduledJobs((current) => current.filter((entry) => entry.slug !== response.job.slug));
|
||||
@@ -200,7 +201,7 @@ export function createAutomationsStore(options: {
|
||||
}
|
||||
|
||||
if (!isTauriRuntime()) {
|
||||
throw new Error("Scheduled tasks require the desktop app.");
|
||||
throw new Error(t("automations.desktop_required"));
|
||||
}
|
||||
const root = options.selectedWorkspaceRoot().trim();
|
||||
const job = await schedulerDeleteJob(name, root || undefined);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createMemo, createSignal, type Accessor } from "solid-js";
|
||||
|
||||
import type { ProviderAuthAuthorization, ProviderListResponse } from "@opencode-ai/sdk/v2/client";
|
||||
|
||||
import { t, currentLocale } from "../../../i18n";
|
||||
import { t } from "../../../i18n";
|
||||
import { unwrap, waitForHealthy } from "../../lib/opencode";
|
||||
import type { Client, ProviderListItem, WorkspaceDisplay } from "../../types";
|
||||
import { safeStringify } from "../../utils";
|
||||
@@ -70,7 +70,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
const assertNoClientError = (result: unknown) => {
|
||||
const maybe = result as { error?: unknown } | null | undefined;
|
||||
if (!maybe || maybe.error === undefined) return;
|
||||
throw new Error(describeProviderError(maybe.error, t("app.error_request_failed", currentLocale())));
|
||||
throw new Error(describeProviderError(maybe.error, t("providers.request_failed")));
|
||||
};
|
||||
|
||||
const describeProviderError = (error: unknown, fallback: string) => {
|
||||
@@ -125,9 +125,9 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
|
||||
const generic = raw && /^unknown\s+error$/i.test(raw);
|
||||
const heading = (() => {
|
||||
if (status === 401 || status === 403) return t("app.error_auth_failed", currentLocale());
|
||||
if (status === 429) return t("app.error_rate_limit", currentLocale());
|
||||
if (provider) return `Provider error (${provider})`;
|
||||
if (status === 401 || status === 403) return t("providers.auth_failed");
|
||||
if (status === 429) return t("providers.rate_limit_exceeded");
|
||||
if (provider) return t("providers.provider_error", undefined, { provider });
|
||||
return fallback;
|
||||
})();
|
||||
|
||||
@@ -167,7 +167,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
if (!Array.isArray(provider.env) || provider.env.length === 0) continue;
|
||||
const existing = merged[id] ?? [];
|
||||
if (existing.some((method) => method.type === "api")) continue;
|
||||
merged[id] = [...existing, { type: "api", label: "API key" }];
|
||||
merged[id] = [...existing, { type: "api", label: t("providers.api_key_label") }];
|
||||
}
|
||||
for (const [id, providerMethods] of Object.entries(merged)) {
|
||||
const provider = availableProviders.find((item) => item.id === id);
|
||||
@@ -188,7 +188,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
const loadProviderAuthMethods = async (workerType: "local" | "remote") => {
|
||||
const c = options.client();
|
||||
if (!c) {
|
||||
throw new Error(t("app.error_not_connected", currentLocale()));
|
||||
throw new Error(t("providers.not_connected"));
|
||||
}
|
||||
const methods = unwrap(await c.provider.auth());
|
||||
return buildProviderAuthMethods(
|
||||
@@ -205,7 +205,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
setProviderAuthError(null);
|
||||
const c = options.client();
|
||||
if (!c) {
|
||||
throw new Error(t("app.error_not_connected", currentLocale()));
|
||||
throw new Error(t("providers.not_connected"));
|
||||
}
|
||||
try {
|
||||
const cachedMethods = providerAuthMethods();
|
||||
@@ -214,17 +214,17 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
: await loadProviderAuthMethods(providerAuthWorkerType());
|
||||
const providerIds = Object.keys(authMethods).sort();
|
||||
if (!providerIds.length) {
|
||||
throw new Error("No providers available");
|
||||
throw new Error(t("providers.no_providers_available"));
|
||||
}
|
||||
|
||||
const resolved = providerId?.trim() ?? "";
|
||||
if (!resolved) {
|
||||
throw new Error("Provider ID is required");
|
||||
throw new Error(t("providers.provider_id_required"));
|
||||
}
|
||||
|
||||
const methods = authMethods[resolved];
|
||||
if (!methods || !methods.length) {
|
||||
throw new Error(`Unknown provider: ${resolved}`);
|
||||
throw new Error(`${t("providers.unknown_provider")}: ${resolved}`);
|
||||
}
|
||||
|
||||
const oauthIndex =
|
||||
@@ -232,12 +232,12 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
? methodIndex
|
||||
: methods.find((method) => method.type === "oauth")?.methodIndex ?? -1;
|
||||
if (oauthIndex === -1) {
|
||||
throw new Error(`No OAuth flow available for ${resolved}. Use an API key instead.`);
|
||||
throw new Error(`${t("providers.no_oauth_prefix")} ${resolved}. ${t("providers.use_api_key_suffix")}`);
|
||||
}
|
||||
|
||||
const selectedMethod = methods.find((method) => method.methodIndex === oauthIndex);
|
||||
if (!selectedMethod || selectedMethod.type !== "oauth") {
|
||||
throw new Error(`Selected auth method is not an OAuth flow for ${resolved}.`);
|
||||
throw new Error(`${t("providers.not_oauth_flow_prefix")} ${resolved}.`);
|
||||
}
|
||||
|
||||
const auth = unwrap(await c.provider.oauth.authorize({ providerID: resolved, method: oauthIndex }));
|
||||
@@ -246,7 +246,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
authorization: auth,
|
||||
};
|
||||
} catch (error) {
|
||||
const message = describeProviderError(error, "Failed to connect provider");
|
||||
const message = describeProviderError(error, t("providers.connect_failed"));
|
||||
setProviderAuthError(message);
|
||||
throw error instanceof Error ? error : new Error(message);
|
||||
}
|
||||
@@ -310,16 +310,16 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
setProviderAuthError(null);
|
||||
const c = options.client();
|
||||
if (!c) {
|
||||
throw new Error(t("app.error_not_connected", currentLocale()));
|
||||
throw new Error(t("providers.not_connected"));
|
||||
}
|
||||
|
||||
const resolved = providerId?.trim();
|
||||
if (!resolved) {
|
||||
throw new Error("Provider ID is required");
|
||||
throw new Error(t("providers.provider_id_required"));
|
||||
}
|
||||
|
||||
if (!Number.isInteger(methodIndex) || methodIndex < 0) {
|
||||
throw new Error("OAuth method is required");
|
||||
throw new Error(t("providers.oauth_method_required"));
|
||||
}
|
||||
|
||||
const waitForProviderConnection = async (timeoutMs = 15_000, pollMs = 2_000) => {
|
||||
@@ -354,26 +354,26 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
const updated = await refreshProviders({ dispose: true });
|
||||
const connectedNow = Array.isArray(updated?.connected) && updated.connected.includes(resolved);
|
||||
if (connectedNow) {
|
||||
return { connected: true, message: `Connected ${resolved}` };
|
||||
return { connected: true, message: `${t("status.connected")} ${resolved}` };
|
||||
}
|
||||
const connected = await waitForProviderConnection();
|
||||
if (connected) {
|
||||
return { connected: true, message: `Connected ${resolved}` };
|
||||
return { connected: true, message: `${t("status.connected")} ${resolved}` };
|
||||
}
|
||||
return { connected: false, pending: true };
|
||||
} catch (error) {
|
||||
if (isPendingOauthError(error)) {
|
||||
const updated = await refreshProviders({ dispose: true });
|
||||
if (Array.isArray(updated?.connected) && updated.connected.includes(resolved)) {
|
||||
return { connected: true, message: `Connected ${resolved}` };
|
||||
return { connected: true, message: `${t("status.connected")} ${resolved}` };
|
||||
}
|
||||
const connected = await waitForProviderConnection();
|
||||
if (connected) {
|
||||
return { connected: true, message: `Connected ${resolved}` };
|
||||
return { connected: true, message: `${t("status.connected")} ${resolved}` };
|
||||
}
|
||||
return { connected: false, pending: true };
|
||||
}
|
||||
const message = describeProviderError(error, "Failed to complete OAuth");
|
||||
const message = describeProviderError(error, t("providers.oauth_failed"));
|
||||
setProviderAuthError(message);
|
||||
throw error instanceof Error ? error : new Error(message);
|
||||
}
|
||||
@@ -383,12 +383,12 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
setProviderAuthError(null);
|
||||
const c = options.client();
|
||||
if (!c) {
|
||||
throw new Error(t("app.error_not_connected", currentLocale()));
|
||||
throw new Error(t("providers.not_connected"));
|
||||
}
|
||||
|
||||
const trimmed = apiKey.trim();
|
||||
if (!trimmed) {
|
||||
throw new Error("API key is required");
|
||||
throw new Error(t("providers.api_key_required"));
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -397,9 +397,9 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
auth: { type: "api", key: trimmed },
|
||||
});
|
||||
await refreshProviders({ dispose: true });
|
||||
return `Connected ${providerId}`;
|
||||
return `${t("status.connected")} ${providerId}`;
|
||||
} catch (error) {
|
||||
const message = describeProviderError(error, "Failed to save API key");
|
||||
const message = describeProviderError(error, t("providers.save_api_key_failed"));
|
||||
setProviderAuthError(message);
|
||||
throw error instanceof Error ? error : new Error(message);
|
||||
}
|
||||
@@ -409,12 +409,12 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
setProviderAuthError(null);
|
||||
const c = options.client();
|
||||
if (!c) {
|
||||
throw new Error(t("app.error_not_connected", currentLocale()));
|
||||
throw new Error(t("providers.not_connected"));
|
||||
}
|
||||
|
||||
const resolved = providerId.trim();
|
||||
if (!resolved) {
|
||||
throw new Error("Provider ID is required");
|
||||
throw new Error(t("providers.provider_id_required"));
|
||||
}
|
||||
|
||||
const provider = options.providers().find((entry) => entry.id === resolved) as
|
||||
@@ -447,7 +447,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error("Provider auth removal is not supported by this client.");
|
||||
throw new Error(t("providers.removal_unsupported"));
|
||||
};
|
||||
|
||||
const disableProvider = async () => {
|
||||
@@ -492,18 +492,18 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
}
|
||||
if (!Array.isArray(updated?.connected) || !updated.connected.includes(resolved)) {
|
||||
return disabled
|
||||
? `Disconnected ${resolved} and disabled it in OpenCode config.`
|
||||
: `Disconnected ${resolved}.`;
|
||||
? `${t("providers.disconnected_prefix")} ${resolved} ${t("providers.disabled_in_config_suffix")}`
|
||||
: `${t("providers.disconnected_prefix")} ${resolved}.`;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(updated?.connected) && updated.connected.includes(resolved)) {
|
||||
return `Removed stored credentials for ${resolved}, but the worker still reports it as connected. Clear any remaining API key or OAuth credentials and restart the worker to fully disconnect.`;
|
||||
return `Removed stored credentials for ${resolved}${t("providers.still_connected_suffix")}`;
|
||||
}
|
||||
removeProviderFromState(resolved);
|
||||
return `Disconnected ${resolved}`;
|
||||
return `${t("providers.disconnected_prefix")} ${resolved}`;
|
||||
} catch (error) {
|
||||
const message = describeProviderError(error, "Failed to disconnect provider");
|
||||
const message = describeProviderError(error, t("providers.disconnect_failed"));
|
||||
setProviderAuthError(message);
|
||||
throw error instanceof Error ? error : new Error(message);
|
||||
}
|
||||
@@ -524,7 +524,7 @@ export function createProvidersStore(options: CreateProvidersStoreOptions) {
|
||||
} catch (error) {
|
||||
setProviderAuthPreferredProviderId(null);
|
||||
setProviderAuthReturnFocusTarget("none");
|
||||
const message = describeProviderError(error, "Failed to load providers");
|
||||
const message = describeProviderError(error, t("providers.load_failed"));
|
||||
setProviderAuthError(message);
|
||||
throw error;
|
||||
} finally {
|
||||
|
||||
@@ -1284,4 +1284,57 @@ export default {
|
||||
"session.restart_update_title": "Restart to apply update {version}",
|
||||
"session.downloading_update_title": "Downloading update {version}",
|
||||
"session.update_available_title": "Update available {version}",
|
||||
|
||||
// ==================== Automations context ====================
|
||||
"automations.server_unavailable": "OpenWork server unavailable. Connect to sync scheduled tasks.",
|
||||
"automations.server_needs_token": "OpenWork server needs a token to load scheduled tasks.",
|
||||
"automations.server_not_ready": "OpenWork server not ready.",
|
||||
"automations.failed_to_load": "Failed to load scheduled tasks.",
|
||||
"automations.desktop_required": "Scheduled tasks require the desktop app.",
|
||||
"automations.schedule_required": "Schedule is required.",
|
||||
"automations.prompt_required": "Prompt is required.",
|
||||
"automations.prompt_empty": "Automation prompt is empty.",
|
||||
|
||||
// ==================== Question Modal ====================
|
||||
"question_modal.question_counter": "Question {current} of {total}",
|
||||
"question_modal.custom_answer_label": "Or type a custom answer",
|
||||
"question_modal.custom_answer_placeholder": "Type your answer here...",
|
||||
|
||||
// ==================== Common (additions) ====================
|
||||
"common.navigate": "navigate",
|
||||
"common.select": "select",
|
||||
"common.submit": "Submit",
|
||||
"common.next": "Next",
|
||||
"common.question": "Question",
|
||||
|
||||
// ==================== Providers store ====================
|
||||
"providers.api_key_label": "API key",
|
||||
"providers.not_connected": "Not connected to a server",
|
||||
"providers.connect_failed": "Failed to connect provider",
|
||||
"providers.oauth_failed": "Failed to complete OAuth",
|
||||
"providers.save_api_key_failed": "Failed to save API key",
|
||||
"providers.disconnect_failed": "Failed to disconnect provider",
|
||||
"providers.load_failed": "Failed to load providers",
|
||||
"providers.auth_failed": "Authentication failed",
|
||||
"providers.rate_limit_exceeded": "Rate limit exceeded",
|
||||
"providers.provider_error": "Provider error ({provider})",
|
||||
"providers.request_failed": "Request failed",
|
||||
"providers.api_key_required": "API key is required",
|
||||
"providers.no_providers_available": "No providers available",
|
||||
"providers.provider_id_required": "Provider ID is required",
|
||||
"providers.unknown_provider": "Unknown provider",
|
||||
"providers.no_oauth_prefix": "No OAuth flow available for",
|
||||
"providers.use_api_key_suffix": "Use an API key instead.",
|
||||
"providers.not_oauth_flow_prefix": "Selected auth method is not an OAuth flow for",
|
||||
"providers.oauth_method_required": "OAuth method is required",
|
||||
"providers.removal_unsupported": "Provider auth removal is not supported by this client.",
|
||||
"providers.disconnected_prefix": "Disconnected",
|
||||
"providers.disabled_in_config_suffix": "and disabled it in OpenCode config.",
|
||||
"providers.still_connected_suffix": ", but the worker still reports it as connected. Clear any remaining API key or OAuth credentials and restart the worker to fully disconnect.",
|
||||
|
||||
// ==================== MCP Auth Modal (additions) ====================
|
||||
"mcp.auth.authorization_link": "Authorization link",
|
||||
"mcp.auth.copied": "Copied",
|
||||
"mcp.auth.copy_link": "Copy link",
|
||||
"mcp.auth.request_timed_out": "Request timed out.",
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user