diff --git a/apps/app/src/app/lib/model-behavior.ts b/apps/app/src/app/lib/model-behavior.ts index 2883be910..a8cccd76e 100644 --- a/apps/app/src/app/lib/model-behavior.ts +++ b/apps/app/src/app/lib/model-behavior.ts @@ -143,7 +143,7 @@ const getVariantDescription = ( if (key === "xhigh" || key === "max") return family === "anthropic" ? t("model_behavior.desc_max_anthropic") : t("model_behavior.desc_max"); - return t("model_behavior.desc_generic", undefined, { label: label.toLowerCase() }); + return t("model_behavior.desc_generic", { label: label.toLowerCase() }); }; export const getModelBehaviorOptions = ( diff --git a/apps/app/src/app/utils/index.ts b/apps/app/src/app/utils/index.ts index aa556c228..294401db9 100644 --- a/apps/app/src/app/utils/index.ts +++ b/apps/app/src/app/utils/index.ts @@ -269,15 +269,15 @@ export function formatRelativeTime(timestampMs: number) { } if (delta < 60_000) { - return t("time.seconds_ago", undefined, { count: Math.max(1, Math.round(delta / 1000)) }); + return t("time.seconds_ago", { count: Math.max(1, Math.round(delta / 1000)) }); } if (delta < 60 * 60_000) { - return t("time.minutes_ago", undefined, { count: Math.max(1, Math.round(delta / 60_000)) }); + return t("time.minutes_ago", { count: Math.max(1, Math.round(delta / 60_000)) }); } if (delta < 24 * 60 * 60_000) { - return t("time.hours_ago", undefined, { count: Math.max(1, Math.round(delta / (60 * 60_000))) }); + return t("time.hours_ago", { count: Math.max(1, Math.round(delta / (60 * 60_000))) }); } return new Date(timestampMs).toLocaleDateString(); diff --git a/apps/app/src/hooks/use-translate.ts b/apps/app/src/hooks/use-translate.ts index 311872ab4..502ba7ffb 100644 --- a/apps/app/src/hooks/use-translate.ts +++ b/apps/app/src/hooks/use-translate.ts @@ -1,11 +1,10 @@ import * as React from "react"; -import { currentLocale, t } from "@/i18n"; +import { t } from "@/i18n"; export function useTranslate() { - const tr = React.useCallback((key: string) => t(key, currentLocale()), []); + const tr = React.useCallback((key: string) => t(key), []); const tx = React.useCallback( - (key: string, params?: Record) => - t(key, currentLocale(), params), + (key: string, params?: Record) => t(key, params), [], ); diff --git a/apps/app/src/i18n/index.ts b/apps/app/src/i18n/index.ts index d989368b7..1a3a72cc8 100644 --- a/apps/app/src/i18n/index.ts +++ b/apps/app/src/i18n/index.ts @@ -101,8 +101,8 @@ export const setLocale = (newLocale: Language) => { * @param localeOverride - Optional locale override (defaults to current locale) * @returns Translated string or fallback */ -export const t = (key: string, localeOverride?: Language, params?: Record): string => { - const loc = localeOverride ?? locale(); +export const t = (key: string, params?: Record & { lng?: Language }): string => { + const loc = params?.lng ?? locale(); // Try target language first let result: string; @@ -116,9 +116,10 @@ export const t = (key: string, localeOverride?: Language, params?: Record @@ -48,7 +48,7 @@ export function RestrictionNoticeModal(props: RestrictionNoticeModalProps) {

diff --git a/apps/app/src/react-app/domains/bundles/skill-destination-modal.tsx b/apps/app/src/react-app/domains/bundles/skill-destination-modal.tsx index bbd830f25..9a721314e 100644 --- a/apps/app/src/react-app/domains/bundles/skill-destination-modal.tsx +++ b/apps/app/src/react-app/domains/bundles/skill-destination-modal.tsx @@ -11,7 +11,7 @@ import { } from "lucide-react"; import type { WorkspaceInfo } from "../../../app/lib/desktop"; -import { currentLocale, t } from "../../../i18n"; +import { t } from "../../../i18n"; import { isSandboxWorkspace } from "../../../app/utils"; import { Button } from "../../design-system/button"; @@ -43,7 +43,6 @@ const displayName = (workspace: WorkspaceInfo, fallback: string): string => fallback; export function SkillDestinationModal(props: SkillDestinationModalProps) { - const translate = (key: string) => t(key, currentLocale()); const [selectedWorkspaceId, setSelectedWorkspaceId] = useState< string | null >(null); @@ -72,7 +71,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { if (workspace.workspaceType === "local") { return ( workspace.path?.trim() || - translate("share_skill_destination.local_badge") + t("share_skill_destination.local_badge") ); } return ( @@ -80,18 +79,18 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { workspace.openworkHostUrl?.trim() || workspace.baseUrl?.trim() || workspace.path?.trim() || - translate("share_skill_destination.remote_badge") + t("share_skill_destination.remote_badge") ); }; const workspaceBadge = (workspace: WorkspaceInfo): string => { if (isSandboxWorkspace(workspace)) { - return translate("share_skill_destination.sandbox_badge"); + return t("share_skill_destination.sandbox_badge"); } if (workspace.workspaceType === "remote") { - return translate("share_skill_destination.remote_badge"); + return t("share_skill_destination.remote_badge"); } - return translate("share_skill_destination.local_badge"); + return t("share_skill_destination.local_badge"); }; const workspaceCircleClass = ( @@ -126,7 +125,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
- {translate("share_skill_destination.skill_label")} + {t("share_skill_destination.skill_label")}
@@ -135,11 +134,11 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
- {translate("share_skill_destination.skill_label")} + {t("share_skill_destination.skill_label")}

{props.skill?.name ?? - translate("share_skill_destination.fallback_skill_name")} + t("share_skill_destination.fallback_skill_name")}

{props.skill?.description?.trim() ? (

@@ -149,7 +148,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { {props.skill?.trigger?.trim() ? (

- {translate("share_skill_destination.trigger_label")} + {t("share_skill_destination.trigger_label")} {props.skill.trigger.trim()} @@ -161,10 +160,10 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {

- {translate("share_skill_destination.title")} + {t("share_skill_destination.title")}

- {translate("share_skill_destination.subtitle")} + {t("share_skill_destination.subtitle")}

@@ -175,7 +174,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { className={`rounded-full p-2 text-gray-9 transition hover:bg-gray-2 hover:text-gray-12 ${ footerBusy ? "cursor-not-allowed opacity-50" : "" }`.trim()} - aria-label={translate("common.close")} + aria-label={t("common.close")} > @@ -186,7 +185,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
- {translate("share_skill_destination.existing_workers")} + {t("share_skill_destination.existing_workers")}
{props.workspaces.length > 0 ? ( @@ -197,7 +196,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { {props.workspaces.length === 0 ? (
- {translate("share_skill_destination.no_workers")} + {t("share_skill_destination.no_workers")}
) : (
@@ -240,7 +239,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
{isActive ? ( - {translate("share_skill_destination.current_badge")} + {t("share_skill_destination.current_badge")} ) : null} @@ -248,9 +247,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { {isSelected ? ( - {translate( - "share_skill_destination.selected_badge", - )} + {t("share_skill_destination.selected_badge")} ) : null}
@@ -260,9 +257,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
{isSelected ? (
- {translate( - "share_skill_destination.selected_hint", - )} + {t("share_skill_destination.selected_hint")}
) : null}
@@ -290,7 +285,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { {props.onCreateWorker || props.onConnectRemote ? (
- {translate("share_skill_destination.more_options")} + {t("share_skill_destination.more_options")}
{props.onCreateWorker ? ( @@ -308,12 +303,10 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
- {translate("share_skill_destination.create_worker")} + {t("share_skill_destination.create_worker")}
- {translate( - "share_skill_destination.create_worker_hint", - )} + {t("share_skill_destination.create_worker_hint")}
@@ -335,12 +328,10 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) {
- {translate("share_skill_destination.connect_remote")} + {t("share_skill_destination.connect_remote")}
- {translate( - "share_skill_destination.connect_remote_hint", - )} + {t("share_skill_destination.connect_remote_hint")}
@@ -371,7 +362,7 @@ export function SkillDestinationModal(props: SkillDestinationModalProps) { onClick={props.onClose} disabled={footerBusy} > - {translate("common.cancel")} + {t("common.cancel")} diff --git a/apps/app/src/react-app/domains/cloud/den-signin-surface.tsx b/apps/app/src/react-app/domains/cloud/den-signin-surface.tsx index a44d313e7..f65267259 100644 --- a/apps/app/src/react-app/domains/cloud/den-signin-surface.tsx +++ b/apps/app/src/react-app/domains/cloud/den-signin-surface.tsx @@ -1,7 +1,7 @@ /** @jsxImportSource react */ import { ArrowUpRight, Cloud } from "lucide-react"; -import { currentLocale, t } from "../../../i18n"; +import { t } from "../../../i18n"; import { DEFAULT_DEN_BASE_URL } from "../../../app/lib/den"; import { Button } from "../../design-system/button"; import { TextInput } from "../../design-system/text-input"; @@ -50,7 +50,6 @@ const errorBannerClass = * feature parity is obvious. */ export function DenSignInSurface(props: DenSignInSurfaceProps) { - const tr = (key: string) => t(key, currentLocale()); const variant: DenSignInSurfaceVariant = props.variant ?? "panel"; const content = ( @@ -59,11 +58,11 @@ export function DenSignInSurface(props: DenSignInSurfaceProps) {
- {tr("den.cloud_section_title")} + {t("den.cloud_section_title")}
- {tr("den.signin_title")} + {t("den.signin_title")}
@@ -72,13 +71,13 @@ export function DenSignInSurface(props: DenSignInSurfaceProps) { {props.developerMode ? (
props.onBaseUrlDraftInput(event.currentTarget.value) } placeholder={DEFAULT_DEN_BASE_URL} - hint={tr("den.cloud_control_plane_url_hint")} + hint={t("den.cloud_control_plane_url_hint")} disabled={props.authBusy || props.baseUrlBusy || props.sessionBusy} />
@@ -88,7 +87,7 @@ export function DenSignInSurface(props: DenSignInSurfaceProps) { onClick={props.onResetBaseUrl} disabled={props.authBusy || props.baseUrlBusy || props.sessionBusy} > - {tr("den.cloud_control_plane_reset")} + {t("den.cloud_control_plane_reset")}
@@ -120,7 +119,7 @@ export function DenSignInSurface(props: DenSignInSurfaceProps) {
- {tr("den.auto_reconnect_hint")} + {t("den.auto_reconnect_hint")}
@@ -129,7 +128,7 @@ export function DenSignInSurface(props: DenSignInSurfaceProps) { variant="secondary" onClick={() => props.onOpenBrowserAuth("sign-in")} > - {tr("den.signin_button")} + {t("den.signin_button")}
{props.manualAuthOpen ? (
props.onManualAuthInput(event.currentTarget.value) } - placeholder={tr("den.signin_link_placeholder")} + placeholder={t("den.signin_link_placeholder")} disabled={props.authBusy || props.sessionBusy} - hint={tr("den.signin_link_hint")} + hint={t("den.signin_link_hint")} />
- {tr("den.signin_code_note")} + {t("den.signin_code_note")}
diff --git a/apps/app/src/react-app/domains/cloud/forced-signin-page.tsx b/apps/app/src/react-app/domains/cloud/forced-signin-page.tsx index 0457895a8..9e673b55d 100644 --- a/apps/app/src/react-app/domains/cloud/forced-signin-page.tsx +++ b/apps/app/src/react-app/domains/cloud/forced-signin-page.tsx @@ -1,7 +1,7 @@ /** @jsxImportSource react */ import { useCallback, useEffect, useState } from "react"; -import { currentLocale, t } from "../../../i18n"; +import { t } from "../../../i18n"; import { buildDenAuthUrl, clearDenSession, @@ -78,7 +78,6 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { const denAuth = useDenAuth(); const desktopConfig = useDesktopConfig(); const { markRouteReady } = useBootState(); - const tr = useCallback((key: string) => t(key, currentLocale()), []); const initial = readDenSettings(); const initialBaseUrl = initial.baseUrl || DEFAULT_DEN_BASE_URL; @@ -102,19 +101,19 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { platform.openLink(buildDenAuthUrl(baseUrl, mode)); setStatusMessage( mode === "sign-up" - ? tr("den.status_browser_signup") - : tr("den.status_browser_signin"), + ? t("den.status_browser_signup") + : t("den.status_browser_signin"), ); setAuthError(null); }, - [baseUrl, platform, tr], + [baseUrl, platform], ); const submitManualAuth = useCallback(async () => { const parsed = parseManualAuthInput(manualAuthInput); if (!parsed || authBusy) { if (!parsed) { - setAuthError(tr("den.error_paste_valid_code")); + setAuthError(t("den.error_paste_valid_code")); } return; } @@ -123,14 +122,14 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { setAuthBusy(true); setAuthError(null); - setStatusMessage(tr("den.signing_in")); + setStatusMessage(t("den.signing_in")); try { const result = await createDenClient({ baseUrl: nextBaseUrl, }).exchangeDesktopHandoff(parsed.grant); if (!result.token) { - throw new Error(tr("den.error_no_token")); + throw new Error(t("den.error_no_token")); } if (developerMode) { @@ -161,17 +160,17 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { message: error instanceof Error ? error.message - : tr("den.error_signin_failed"), + : t("den.error_signin_failed"), }); } finally { setAuthBusy(false); } - }, [authBusy, baseUrl, developerMode, manualAuthInput, tr]); + }, [authBusy, baseUrl, developerMode, manualAuthInput]); const applyBaseUrl = useCallback(async () => { const normalized = normalizeDenBaseUrl(baseUrlDraft); if (!normalized) { - setBaseUrlError(tr("den.error_base_url")); + setBaseUrlError(t("den.error_base_url")); return; } @@ -200,19 +199,19 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { { persistBootstrap: false }, ); setAuthError(null); - setStatusMessage(tr("den.status_base_url_updated")); + setStatusMessage(t("den.status_base_url_updated")); void desktopConfig.refresh(); void denAuth.refresh(); } catch (error) { setBaseUrlError( error instanceof Error ? error.message - : tr("den.error_base_url"), + : t("den.error_base_url"), ); } finally { setBaseUrlBusy(false); } - }, [baseUrlDraft, denAuth, desktopConfig, developerMode, tr]); + }, [baseUrlDraft, denAuth, desktopConfig, developerMode]); // Listen for Den session events broadcast from the Tauri deep-link handler, // a successful browser auth, or an org switch, and reflect the result in @@ -239,12 +238,12 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { const email = customEvent.detail.email?.trim(); setStatusMessage( email - ? t("den.status_cloud_signed_in_as", currentLocale(), { email }) - : tr("den.status_cloud_signin_done"), + ? t("den.status_cloud_signed_in_as", { email }) + : t("den.status_cloud_signin_done"), ); } else if (customEvent.detail?.status === "error") { setAuthError( - customEvent.detail.message?.trim() || tr("den.error_signin_failed"), + customEvent.detail.message?.trim() || t("den.error_signin_failed"), ); } }; @@ -256,7 +255,7 @@ export function ForcedSigninPage({ developerMode }: ForcedSigninPageProps) { handler as EventListener, ); }; - }, [tr]); + }, []); return ( void | Promise; }; export function McpAuthModal(props: McpAuthModalProps) { - const translate = (key: string, replacements?: Record) => { - let result = t(key, props.language); - if (replacements) { - for (const [placeholder, value] of Object.entries(replacements)) { - result = result.replace(`{${placeholder}}`, value); - } - } - return result; - }; - const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [needsReload, setNeedsReload] = useState(false); @@ -177,7 +166,7 @@ export function McpAuthModal(props: McpAuthModalProps) { statusPollRef.current = window.setInterval(async () => { if (Date.now() - startedAt >= MCP_AUTH_TIMEOUT_MS) { stopStatusPolling(); - setError(translate("mcp.auth.request_timed_out")); + setError(t("mcp.auth.request_timed_out")); return; } @@ -197,7 +186,7 @@ export function McpAuthModal(props: McpAuthModalProps) { try { slug = resolveSlug(props.entry.name); } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.failed_to_start_oauth"); + const message = err instanceof Error ? err.message : t("mcp.auth.failed_to_start_oauth"); setError(message); setLoading(false); setAuthInProgress(false); @@ -221,7 +210,7 @@ export function McpAuthModal(props: McpAuthModalProps) { try { const directory = await resolveDirectory(); if (!directory) { - setError(translate("mcp.pick_workspace_first")); + setError(t("mcp.pick_workspace_first")); return; } @@ -230,8 +219,8 @@ export function McpAuthModal(props: McpAuthModalProps) { setNeedsReload(true); setReloadNotice( props.reloadBlocked - ? translate("mcp.auth.reload_blocked") - : translate("mcp.auth.reload_notice"), + ? t("mcp.auth.reload_blocked") + : t("mcp.auth.reload_notice"), ); return; } @@ -255,13 +244,13 @@ export function McpAuthModal(props: McpAuthModalProps) { } if (status.status === "needs_client_registration") { - setError(status.error ?? translate("mcp.auth.client_registration_required")); + setError(status.error ?? t("mcp.auth.client_registration_required")); } else if (status.status === "disabled") { - setError(translate("mcp.auth.server_disabled")); + setError(t("mcp.auth.server_disabled")); } else if (status.status === "failed") { - setError(status.error ?? translate("mcp.auth.oauth_failed")); + setError(status.error ?? t("mcp.auth.oauth_failed")); } else { - setError(translate("mcp.auth.authorization_still_required")); + setError(t("mcp.auth.authorization_still_required")); } return; } @@ -281,7 +270,7 @@ export function McpAuthModal(props: McpAuthModalProps) { await openAuthorizationUrl(auth.authorizationUrl); startStatusPolling(slug); } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.failed_to_start_oauth"); + const message = err instanceof Error ? err.message : t("mcp.auth.failed_to_start_oauth"); if (message.toLowerCase().includes("does not support oauth")) { const serverSlug = props.entry.name.toLowerCase().replace(/[^a-z0-9]+/g, "-") || "server"; @@ -297,18 +286,18 @@ export function McpAuthModal(props: McpAuthModalProps) { if (props.reloadRequired && !reloadSatisfied) { setReloadNotice( props.reloadBlocked - ? translate("mcp.auth.reload_blocked") - : translate("mcp.auth.reload_notice"), + ? t("mcp.auth.reload_blocked") + : t("mcp.auth.reload_notice"), ); } else { setError( - `${message}\n\n${translate("mcp.auth.oauth_not_supported_hint", { server: serverSlug })}`, + `${message}\n\n${t("mcp.auth.oauth_not_supported_hint", { server: serverSlug })}`, ); } setNeedsReload(true); } else if (message.toLowerCase().includes("not found") || message.toLowerCase().includes("unknown")) { setNeedsReload(true); - setError(translate("mcp.auth.try_reload_engine", { message })); + setError(t("mcp.auth.try_reload_engine", { message })); } else { setError(message); } @@ -339,12 +328,12 @@ export function McpAuthModal(props: McpAuthModalProps) { if (result.ok) { setError(null); setNeedsReload(true); - setReloadNotice(translate("mcp.auth.oauth_completed_reload")); + setReloadNotice(t("mcp.auth.oauth_completed_reload")); } else { - setCliAuthResult(result.stderr || result.stdout || translate("mcp.auth.reauth_failed")); + setCliAuthResult(result.stderr || result.stdout || t("mcp.auth.reauth_failed")); } } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.reauth_failed"); + const message = err instanceof Error ? err.message : t("mcp.auth.reauth_failed"); setCliAuthResult(message); } finally { setCliAuthBusy(false); @@ -403,8 +392,8 @@ export function McpAuthModal(props: McpAuthModalProps) { setNeedsReload(true); setReloadNotice( props.reloadBlocked - ? translate("mcp.auth.reload_blocked") - : translate("mcp.auth.reload_notice"), + ? t("mcp.auth.reload_blocked") + : t("mcp.auth.reload_notice"), ); return; } @@ -413,7 +402,7 @@ export function McpAuthModal(props: McpAuthModalProps) { setAwaitingReload(false); await startAuth(false, false); } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.reload_failed"); + const message = err instanceof Error ? err.message : t("mcp.auth.reload_failed"); if (cancelled) return; setAwaitingReload(false); setNeedsReload(true); @@ -437,7 +426,7 @@ export function McpAuthModal(props: McpAuthModalProps) { const handleReloadAndRetry = async () => { if (!props.onReloadEngine) return; if (props.isRemoteWorkspace && typeof window !== "undefined") { - const proceed = window.confirm(translate("mcp.auth.reload_remote_confirm")); + const proceed = window.confirm(t("mcp.auth.reload_remote_confirm")); if (!proceed) return; } await props.onReloadEngine(); @@ -502,14 +491,14 @@ export function McpAuthModal(props: McpAuthModalProps) { try { slug = resolveSlug(props.entry.name); } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.failed_to_start_oauth"); + const message = err instanceof Error ? err.message : t("mcp.auth.failed_to_start_oauth"); setError(message); return; } const code = parseAuthCode(callbackInput); if (!code) { - setError(translate("mcp.auth.callback_invalid")); + setError(t("mcp.auth.callback_invalid")); return; } @@ -520,7 +509,7 @@ export function McpAuthModal(props: McpAuthModalProps) { try { const directory = await resolveDirectory(); if (!directory) { - setError(translate("mcp.pick_workspace_first")); + setError(t("mcp.pick_workspace_first")); return; } @@ -538,16 +527,16 @@ export function McpAuthModal(props: McpAuthModalProps) { } if (status.status === "needs_client_registration") { - setError(status.error ?? translate("mcp.auth.client_registration_required")); + setError(status.error ?? t("mcp.auth.client_registration_required")); } else if (status.status === "disabled") { - setError(translate("mcp.auth.server_disabled")); + setError(t("mcp.auth.server_disabled")); } else if (status.status === "failed") { - setError(status.error ?? translate("mcp.auth.oauth_failed")); + setError(status.error ?? t("mcp.auth.oauth_failed")); } else { - setError(translate("mcp.auth.authorization_still_required")); + setError(t("mcp.auth.authorization_still_required")); } } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.oauth_failed"); + const message = err instanceof Error ? err.message : t("mcp.auth.oauth_failed"); setError(message); } finally { setManualAuthBusy(false); @@ -564,7 +553,7 @@ export function McpAuthModal(props: McpAuthModalProps) { try { slug = resolveSlug(props.entry.name); } catch (err) { - const message = err instanceof Error ? err.message : translate("mcp.auth.failed_to_start_oauth"); + const message = err instanceof Error ? err.message : t("mcp.auth.failed_to_start_oauth"); setError(message); setStatusChecking(false); return; @@ -579,13 +568,13 @@ export function McpAuthModal(props: McpAuthModalProps) { } if (statusEntry?.status === "needs_client_registration") { - setError(statusEntry.error ?? translate("mcp.auth.client_registration_required")); + setError(statusEntry.error ?? t("mcp.auth.client_registration_required")); } else if (statusEntry?.status === "disabled") { - setError(translate("mcp.auth.server_disabled")); + setError(t("mcp.auth.server_disabled")); } else if (statusEntry?.status === "failed") { - setError(statusEntry.error ?? translate("mcp.auth.oauth_failed")); + setError(statusEntry.error ?? t("mcp.auth.oauth_failed")); } else { - setError(translate("mcp.auth.authorization_still_required")); + setError(t("mcp.auth.authorization_still_required")); } setStatusChecking(false); @@ -608,9 +597,9 @@ export function McpAuthModal(props: McpAuthModalProps) {

- {translate("mcp.auth.connect_server", { server: serverName })} + {t("mcp.auth.connect_server", { server: serverName })}

-

{translate("mcp.auth.open_browser_signin")}

+

{t("mcp.auth.open_browser_signin")}

-

{translate("mcp.auth.waiting_authorization")}

-

{translate("mcp.auth.follow_browser_steps")}

+

{t("mcp.auth.waiting_authorization")}

+

{t("mcp.auth.follow_browser_steps")}

@@ -649,13 +638,13 @@ export function McpAuthModal(props: McpAuthModalProps) {

{props.reloadBlocked - ? translate("mcp.auth.waiting_for_conversation_title") - : translate("mcp.auth.applying_changes_title")} + ? t("mcp.auth.waiting_for_conversation_title") + : t("mcp.auth.applying_changes_title")}

{props.reloadBlocked - ? translate("mcp.auth.waiting_for_conversation_body") - : translate("mcp.auth.applying_changes_body")} + ? t("mcp.auth.waiting_for_conversation_body") + : t("mcp.auth.applying_changes_body")}

{props.reloadBlocked && (props.activeSessions?.length ?? 0) > 0 ? ( @@ -666,7 +655,7 @@ export function McpAuthModal(props: McpAuthModalProps) { className="flex items-center justify-between gap-3 rounded-lg border border-amber-6/50 bg-amber-1/40 px-3 py-2" > - {translate("mcp.auth.waiting_for_session", { session: session.title })} + {t("mcp.auth.waiting_for_session", { session: session.title })} ))} @@ -692,13 +681,13 @@ export function McpAuthModal(props: McpAuthModalProps) {
-

{translate("mcp.auth.already_connected")}

+

{t("mcp.auth.already_connected")}

- {translate("mcp.auth.already_connected_description", { server: serverName })} + {t("mcp.auth.already_connected_description", { server: serverName })}

-

{translate("mcp.auth.configured_previously")}

+

{t("mcp.auth.configured_previously")}

) : null} @@ -712,14 +701,14 @@ export function McpAuthModal(props: McpAuthModalProps) { variant="secondary" onClick={() => void handleReloadAndRetry()} disabled={props.reloadBlocked} - title={props.reloadBlocked ? translate("mcp.reload_banner_blocked_hint") : undefined} + title={props.reloadBlocked ? t("mcp.reload_banner_blocked_hint") : undefined} > - {translate("mcp.auth.reload_engine_retry")} + {t("mcp.auth.reload_engine_retry")} ) : null} @@ -736,42 +725,42 @@ export function McpAuthModal(props: McpAuthModalProps) { variant="secondary" onClick={() => void handleReloadAndRetry()} disabled={props.reloadBlocked} - title={props.reloadBlocked ? translate("mcp.reload_banner_blocked_hint") : undefined} + title={props.reloadBlocked ? t("mcp.reload_banner_blocked_hint") : undefined} > - {translate("mcp.auth.reload_engine_retry")} + {t("mcp.auth.reload_engine_retry")} ) : null} ) : (
)} {isInvalidRefreshToken() ? (
-

{translate("mcp.auth.invalid_refresh_token")}

+

{t("mcp.auth.invalid_refresh_token")}

{!props.isRemoteWorkspace ? ( isDesktopRuntime() ? ( ) : (
- {translate("mcp.auth.reauth_cli_hint", { server: serverName })} + {t("mcp.auth.reauth_cli_hint", { server: serverName })}
) ) : ( -
{translate("mcp.auth.reauth_remote_hint")}
+
{t("mcp.auth.reauth_remote_hint")}
)} {cliAuthResult ?
{cliAuthResult}
: null}
@@ -781,26 +770,26 @@ export function McpAuthModal(props: McpAuthModalProps) { {!isBusy && authorizationUrl && props.isRemoteWorkspace && !alreadyConnected ? (
-
{translate("mcp.auth.manual_finish_title")}
-
{translate("mcp.auth.manual_finish_hint")}
+
{t("mcp.auth.manual_finish_title")}
+
{t("mcp.auth.manual_finish_hint")}
- {translate("mcp.auth.authorization_link")} + {t("mcp.auth.authorization_link")}
{authorizationUrl}
setCallbackInput(event.currentTarget.value)} /> -
{translate("mcp.auth.port_forward_hint")}
+
{t("mcp.auth.port_forward_hint")}
@@ -822,9 +811,9 @@ export function McpAuthModal(props: McpAuthModalProps) { 1
-

{translate("mcp.auth.step1_title")}

+

{t("mcp.auth.step1_title")}

- {translate("mcp.auth.step1_description", { server: serverName })} + {t("mcp.auth.step1_description", { server: serverName })}

@@ -834,8 +823,8 @@ export function McpAuthModal(props: McpAuthModalProps) { 2
-

{translate("mcp.auth.step2_title")}

-

{translate("mcp.auth.step2_description")}

+

{t("mcp.auth.step2_title")}

+

{t("mcp.auth.step2_description")}

@@ -844,22 +833,22 @@ export function McpAuthModal(props: McpAuthModalProps) { 3
-

{translate("mcp.auth.step3_title")}

-

{translate("mcp.auth.step3_description")}

+

{t("mcp.auth.step3_title")}

+

{t("mcp.auth.step3_description")}

-

{translate("mcp.auth.waiting_authorization")}

-

{translate("mcp.auth.follow_browser_steps")}

+

{t("mcp.auth.waiting_authorization")}

+

{t("mcp.auth.follow_browser_steps")}

@@ -871,16 +860,16 @@ export function McpAuthModal(props: McpAuthModalProps) { {alreadyConnected ? ( ) : ( <> )} diff --git a/apps/app/src/react-app/domains/connections/modals.tsx b/apps/app/src/react-app/domains/connections/modals.tsx index 3ac2ad8a4..1367cb257 100644 --- a/apps/app/src/react-app/domains/connections/modals.tsx +++ b/apps/app/src/react-app/domains/connections/modals.tsx @@ -1,6 +1,5 @@ /** @jsxImportSource react */ import type { Client } from "../../../app/types"; -import type { Language } from "../../../i18n"; import type { McpDirectoryInfo } from "../../../app/constants"; import { McpAuthModal } from "./mcp-auth-modal"; @@ -14,7 +13,6 @@ export type ConnectionsModalsState = { export type ConnectionsModalsProps = { client: Client | null; projectDir: string; - language: Language; reloadBlocked: boolean; activeSessions: Array<{ id: string; title: string }>; isRemoteWorkspace: boolean; @@ -32,7 +30,6 @@ export default function ConnectionsModals(props: ConnectionsModalsProps) { client={props.client} entry={props.modalState.mcpAuthEntry} projectDir={props.projectDir} - language={props.language} reloadRequired={props.modalState.mcpAuthNeedsReload} reloadBlocked={props.reloadBlocked} activeSessions={props.activeSessions} diff --git a/apps/app/src/react-app/domains/connections/modals/add-mcp-modal.tsx b/apps/app/src/react-app/domains/connections/modals/add-mcp-modal.tsx index 29480d5d7..d6c7d8adb 100644 --- a/apps/app/src/react-app/domains/connections/modals/add-mcp-modal.tsx +++ b/apps/app/src/react-app/domains/connections/modals/add-mcp-modal.tsx @@ -5,7 +5,7 @@ import { Loader2, Plus, X } from "lucide-react"; import { Button } from "../../../design-system/button"; import { TextInput } from "../../../design-system/text-input"; import type { McpDirectoryInfo } from "../../../../app/constants"; -import { t, type Language } from "../../../../i18n"; +import { t } from "../../../../i18n"; export type AddMcpModalProps = { open: boolean; @@ -13,12 +13,9 @@ export type AddMcpModalProps = { onAdd: (entry: McpDirectoryInfo) => void; busy: boolean; isRemoteWorkspace: boolean; - language: Language; }; export function AddMcpModal(props: AddMcpModalProps) { - const tr = (key: string) => t(key, props.language); - const [name, setName] = useState(""); const [serverType, setServerType] = useState<"remote" | "local">("remote"); const [url, setUrl] = useState(""); @@ -48,7 +45,7 @@ export function AddMcpModal(props: AddMcpModalProps) { const trimmedName = name.trim(); if (!trimmedName) { - setError(tr("mcp.name_required")); + setError(t("mcp.name_required")); return; } @@ -57,7 +54,7 @@ export function AddMcpModal(props: AddMcpModalProps) { if (serverType === "remote") { const trimmedUrl = url.trim(); if (!trimmedUrl) { - setError(tr("mcp.url_or_command_required")); + setError(t("mcp.url_or_command_required")); setSubmitting(false); return; } @@ -78,7 +75,7 @@ export function AddMcpModal(props: AddMcpModalProps) { } else { const trimmedCommand = command.trim(); if (!trimmedCommand) { - setError(tr("mcp.url_or_command_required")); + setError(t("mcp.url_or_command_required")); setSubmitting(false); return; } @@ -116,10 +113,10 @@ export function AddMcpModal(props: AddMcpModalProps) {

- {tr("mcp.add_modal_title")} + {t("mcp.add_modal_title")}

- {tr("mcp.add_modal_subtitle")} + {t("mcp.add_modal_subtitle")}

{props.isRemoteWorkspace ? (
- {tr("mcp.remote_workspace_url_hint")} + {t("mcp.remote_workspace_url_hint")}
) : null} @@ -182,14 +179,14 @@ export function AddMcpModal(props: AddMcpModalProps) { {serverType === "remote" ? (
setUrl(event.currentTarget.value)} />
- {tr("mcp.sign_in_section_label")} + {t("mcp.sign_in_section_label")}
@@ -215,9 +212,9 @@ export function AddMcpModal(props: AddMcpModalProps) { {serverType === "local" ? ( setCommand(event.currentTarget.value)} /> @@ -236,7 +233,7 @@ export function AddMcpModal(props: AddMcpModalProps) { onClick={handleClose} disabled={submitting} > - {tr("mcp.auth.cancel")} + {t("mcp.auth.cancel")}
diff --git a/apps/app/src/react-app/domains/connections/modals/control-chrome-setup-modal.tsx b/apps/app/src/react-app/domains/connections/modals/control-chrome-setup-modal.tsx index 4426b4e17..4b2201442 100644 --- a/apps/app/src/react-app/domains/connections/modals/control-chrome-setup-modal.tsx +++ b/apps/app/src/react-app/domains/connections/modals/control-chrome-setup-modal.tsx @@ -9,13 +9,12 @@ import { X, } from "lucide-react"; -import { t, type Language } from "../../../../i18n"; +import { t } from "../../../../i18n"; import { Button } from "../../../design-system/button"; export type ControlChromeSetupModalProps = { open: boolean; busy: boolean; - language: Language; mode: "connect" | "edit"; initialUseExistingProfile: boolean; onClose: () => void; @@ -23,7 +22,6 @@ export type ControlChromeSetupModalProps = { }; export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) { - const tr = (key: string) => t(key, props.language); const [useExistingProfile, setUseExistingProfile] = useState( props.initialUseExistingProfile, ); @@ -37,8 +35,8 @@ export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) { const ctaLabel = props.mode === "edit" - ? tr("mcp.control_chrome_save") - : tr("mcp.control_chrome_connect"); + ? t("mcp.control_chrome_save") + : t("mcp.control_chrome_connect"); return (
@@ -57,10 +55,10 @@ export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) {

- {tr("mcp.control_chrome_setup_title")} + {t("mcp.control_chrome_setup_title")}

- {tr("mcp.control_chrome_setup_subtitle")} + {t("mcp.control_chrome_setup_subtitle")}

@@ -68,7 +66,7 @@ export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) { type="button" className="rounded-xl p-2 text-gray-11 transition-colors hover:bg-gray-4 hover:text-gray-12" onClick={props.onClose} - aria-label={tr("common.cancel")} + aria-label={t("common.cancel")} > @@ -83,15 +81,15 @@ export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) {

- {tr("mcp.control_chrome_browser_title")} + {t("mcp.control_chrome_browser_title")}

- {tr("mcp.control_chrome_browser_hint")} + {t("mcp.control_chrome_browser_hint")}

    -
  1. 1. {tr("mcp.control_chrome_browser_step_one")}
  2. -
  3. 2. {tr("mcp.control_chrome_browser_step_two")}
  4. -
  5. 3. {tr("mcp.control_chrome_browser_step_three")}
  6. +
  7. 1. {t("mcp.control_chrome_browser_step_one")}
  8. +
  9. 2. {t("mcp.control_chrome_browser_step_two")}
  10. +
  11. 3. {t("mcp.control_chrome_browser_step_three")}
- {tr("mcp.control_chrome_docs")} + {t("mcp.control_chrome_docs")}
@@ -113,10 +111,10 @@ export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) {

- {tr("mcp.control_chrome_profile_title")} + {t("mcp.control_chrome_profile_title")}

- {tr("mcp.control_chrome_profile_hint")} + {t("mcp.control_chrome_profile_hint")}

@@ -160,7 +158,7 @@ export function ControlChromeSetupModal(props: ControlChromeSetupModalProps) {
diff --git a/apps/app/src/react-app/domains/session/modals/rename-session-modal.tsx b/apps/app/src/react-app/domains/session/modals/rename-session-modal.tsx index 6b1a779c5..05787702b 100644 --- a/apps/app/src/react-app/domains/session/modals/rename-session-modal.tsx +++ b/apps/app/src/react-app/domains/session/modals/rename-session-modal.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef } from "react"; import { X } from "lucide-react"; -import { currentLocale, t } from "../../../../i18n"; +import { t } from "../../../../i18n"; import { inputClass, pillGhostClass, @@ -22,7 +22,6 @@ export type RenameSessionModalProps = { export function RenameSessionModal(props: RenameSessionModalProps) { const inputRef = useRef(null); - const translate = (key: string) => t(key, currentLocale()); useEffect(() => { if (!props.open) return; @@ -42,10 +41,10 @@ export function RenameSessionModal(props: RenameSessionModalProps) {

- {translate("session.rename_title")} + {t("session.rename_title")}

- {translate("session.rename_description")} + {t("session.rename_description")}

@@ -88,7 +87,7 @@ export function RenameSessionModal(props: RenameSessionModalProps) { onClick={props.onClose} disabled={props.busy} > - {translate("common.cancel")} + {t("common.cancel")} diff --git a/apps/app/src/react-app/domains/session/surface/composer/composer.tsx b/apps/app/src/react-app/domains/session/surface/composer/composer.tsx index 0ddcbee61..e666aeba3 100644 --- a/apps/app/src/react-app/domains/session/surface/composer/composer.tsx +++ b/apps/app/src/react-app/domains/session/surface/composer/composer.tsx @@ -5,7 +5,7 @@ import { ArrowUp, Check, ChevronDown, ChevronRight, FileText, Paperclip, Plug, S import fuzzysort from "fuzzysort"; import type { CloudImportedPlugin, CloudImportedPluginFile } from "../../../../../app/cloud/import-state"; import type { ComposerAttachment, McpServerEntry, McpStatusMap, SkillCard, SlashCommandOption } from "../../../../../app/types"; -import { currentLocale, t, type Language } from "../../../../../i18n"; +import { t } from "../../../../../i18n"; import { LexicalPromptEditor } from "./editor"; import { ReactComposerNotice, @@ -177,20 +177,20 @@ async function compressImageFile(file: File): Promise { return new File([blob], `${stem}.jpg`, { type: "image/jpeg" }); } -function formatMcpStatusLabel(status: McpServerStatus | undefined, locale: Language) { +function formatMcpStatusLabel(status: McpServerStatus | undefined) { switch (status) { case "connected": - return t("mcp.friendly_status_ready", locale); + return t("mcp.friendly_status_ready"); case "needs_auth": case "needs_client_registration": - return t("mcp.friendly_status_needs_signin", locale); + return t("mcp.friendly_status_needs_signin"); case "disabled": - return t("mcp.friendly_status_paused", locale); + return t("mcp.friendly_status_paused"); case "disconnected": - return t("mcp.friendly_status_offline", locale); + return t("mcp.friendly_status_offline"); case "failed": default: - return t("mcp.friendly_status_issue", locale); + return t("mcp.friendly_status_issue"); } } @@ -280,7 +280,6 @@ export function ReactSessionComposer(props: ComposerProps) { // compositionstart/compositionend events below. const imeComposingRef = useRef(false); const rootRef = useRef(null); - const locale = currentLocale(); const draftRef = useRef(props.draft); useEffect(() => { draftRef.current = props.draft; @@ -707,7 +706,7 @@ export function ReactSessionComposer(props: ComposerProps) { if (!inputFiles.length) return; if (!props.attachmentsEnabled) { props.onNotice({ - title: props.attachmentsDisabledReason ?? t("composer.attachments_unavailable", locale), + title: props.attachmentsDisabledReason ?? t("composer.attachments_unavailable"), tone: "warning", }); return; @@ -719,7 +718,7 @@ export function ReactSessionComposer(props: ComposerProps) { for (const original of inputFiles) { if (!isSupportedAttachmentType(original.type)) { - unsupported.push(original.name || t("composer.file_kind", locale)); + unsupported.push(original.name || t("composer.file_kind")); continue; } const processed = original.type.startsWith("image/") ? await compressImageFile(original) : original; @@ -735,8 +734,8 @@ export function ReactSessionComposer(props: ComposerProps) { props.onNotice({ title: accepted.length === 1 - ? t("composer.uploaded_single_file", locale, { name: accepted[0]?.name ?? t("composer.file_kind", locale) }) - : t("composer.uploaded_multiple_files", locale, { count: accepted.length }), + ? t("composer.uploaded_single_file", { name: accepted[0]?.name ?? t("composer.file_kind") }) + : t("composer.uploaded_multiple_files", { count: accepted.length }), tone: "success", }); } @@ -745,7 +744,7 @@ export function ReactSessionComposer(props: ComposerProps) { props.onNotice({ title: oversize.length === 1 - ? t("composer.file_exceeds_limit", locale, { name: oversize[0] }) + ? t("composer.file_exceeds_limit", { name: oversize[0] }) : `${oversize.length} files exceed the 8MB limit.`, tone: "warning", }); @@ -755,8 +754,8 @@ export function ReactSessionComposer(props: ComposerProps) { props.onNotice({ title: unsupported.length === 1 - ? `${unsupported[0]} · ${t("composer.unsupported_attachment_type", locale)}` - : `${unsupported.length} ${t("composer.unsupported_attachment_type", locale).toLowerCase()}`, + ? `${unsupported[0]} · ${t("composer.unsupported_attachment_type")}` + : `${unsupported.length} ${t("composer.unsupported_attachment_type").toLowerCase()}`, tone: "warning", }); } @@ -807,7 +806,7 @@ export function ReactSessionComposer(props: ComposerProps) {
/{command.name}
{command.source && command.source !== "command" ? ( - {command.source === "skill" ? t("composer.skill_source", locale) : t("composer.mcps_label", locale)} + {command.source === "skill" ? t("composer.skill_source") : t("composer.mcps_label")} ) : null} @@ -818,7 +817,7 @@ export function ReactSessionComposer(props: ComposerProps) { ) : (
- {commandsLoading ? t("composer.loading_commands", locale) : t("composer.no_commands", locale)} + {commandsLoading ? t("composer.loading_commands") : t("composer.no_commands")}
)} @@ -860,8 +859,8 @@ export function ReactSessionComposer(props: ComposerProps) {
@{item.label}
{item.kind === "agent" - ? t("composer.agent_label", locale) - : t("composer.file_kind", locale)} + ? t("composer.agent_label") + : t("composer.file_kind")}
@@ -910,7 +909,7 @@ export function ReactSessionComposer(props: ComposerProps) {
{attachment.name}
- {isImageAttachment(attachment) ? t("composer.image_kind", locale) : t("composer.file_kind", locale)} + {isImageAttachment(attachment) ? t("composer.image_kind") : t("composer.file_kind")} · {formatBytes(attachment.size)}
@@ -919,7 +918,7 @@ export function ReactSessionComposer(props: ComposerProps) { type="button" className="ml-1 inline-flex h-5 w-5 items-center justify-center rounded-full text-gray-10 transition-colors hover:bg-gray-3 hover:text-gray-12" onClick={() => props.onRemoveAttachment(attachment.id)} - title={t("action.remove", locale)} + title={t("action.remove")} > @@ -939,7 +938,7 @@ export function ReactSessionComposer(props: ComposerProps) { {dropzoneActive ? (
-
{t("composer.attach_files", locale)}
+
{t("composer.attach_files")}
Images and PDFs are supported.
@@ -952,7 +951,7 @@ export function ReactSessionComposer(props: ComposerProps) { mentions={props.mentions} pastedText={pastedTextTokens} disabled={props.disabled} - placeholder={t("composer.placeholder", locale)} + placeholder={t("composer.placeholder")} onChange={props.onDraftChange} onSubmit={props.onSend} onPasteText={props.onPasteText} @@ -980,7 +979,7 @@ export function ReactSessionComposer(props: ComposerProps) { event.preventDefault(); props.onUnsupportedFileLinks(uriList); props.onNotice({ - title: t("composer.inserted_links_unsupported", locale), + title: t("composer.inserted_links_unsupported"), tone: "info", }); return; @@ -1007,11 +1006,11 @@ export function ReactSessionComposer(props: ComposerProps) { ) { const attachedFiles = props.attachments.map((attachment) => attachment.file); props.onNotice({ - title: t("composer.remote_worker_paste_warning", locale), + title: t("composer.remote_worker_paste_warning"), tone: "warning", actionLabel: props.onUploadInboxFiles && attachedFiles.length > 0 - ? t("composer.upload_to_shared_folder", locale) + ? t("composer.upload_to_shared_folder") : undefined, onAction: props.onUploadInboxFiles && attachedFiles.length > 0 @@ -1068,7 +1067,7 @@ export function ReactSessionComposer(props: ComposerProps) { fileInput?.click(); }} disabled={!props.attachmentsEnabled} - title={props.attachmentsDisabledReason ?? t("composer.attach_files", locale)} + title={props.attachmentsDisabledReason ?? t("composer.attach_files")} > @@ -1084,7 +1083,7 @@ export function ReactSessionComposer(props: ComposerProps) { }} aria-expanded={toolMenuOpen} aria-haspopup="dialog" - title={t("composer.tools_label", locale)} + title={t("composer.tools_label")} > @@ -1093,9 +1092,9 @@ export function ReactSessionComposer(props: ComposerProps) {
{([ - ["commands", t("dashboard.commands", locale)], - ["skills", t("dashboard.skills", locale)], - ["mcps", t("composer.mcps_label", locale)], + ["commands", t("dashboard.commands")], + ["skills", t("dashboard.skills")], + ["mcps", t("composer.mcps_label")], ] as const).map(([section, label]) => (
{toolMenuSection === "commands" ? ( @@ -1154,7 +1153,7 @@ export function ReactSessionComposer(props: ComposerProps) {
) : (
- {commandsLoading ? t("composer.loading_commands", locale) : t("composer.no_commands", locale)} + {commandsLoading ? t("composer.loading_commands") : t("composer.no_commands")}
) ) : null} @@ -1178,7 +1177,7 @@ export function ReactSessionComposer(props: ComposerProps) {
) : (
- {skillsLoading || commandsLoading ? t("composer.loading_commands", locale) : t("context_panel.no_skills", locale)} + {skillsLoading || commandsLoading ? t("composer.loading_commands") : t("context_panel.no_skills")}
) ) : null} @@ -1192,7 +1191,7 @@ export function ReactSessionComposer(props: ComposerProps) {
{entry.name}
- {formatMcpStatusLabel(status, locale)} + {formatMcpStatusLabel(status)}
{entry.config.type === "remote" ? entry.config.url ?? entry.config.command?.join(" ") ?? "Remote MCP" : entry.config.command?.join(" ") ?? "Local MCP"}
@@ -1202,7 +1201,7 @@ export function ReactSessionComposer(props: ComposerProps) { ) : (
- {mcpLoading ? t("composer.loading_commands", locale) : (mcpStatus ?? t("context_panel.no_mcp", locale))} + {mcpLoading ? t("composer.loading_commands") : (mcpStatus ?? t("context_panel.no_mcp"))}
) ) : null} @@ -1233,7 +1232,7 @@ export function ReactSessionComposer(props: ComposerProps) { ) ) : toolMenuSection.startsWith("plugin:") ? (
- {pluginsLoading ? t("composer.loading_commands", locale) : "Plugin files are unavailable."} + {pluginsLoading ? t("composer.loading_commands") : "Plugin files are unavailable."}
) : null} @@ -1255,10 +1254,10 @@ export function ReactSessionComposer(props: ComposerProps) { type="button" onClick={props.onStop} className="inline-flex h-9 max-h-9 items-center gap-2 rounded-full bg-gray-12 px-4 text-[13px] font-medium text-gray-1 transition-colors hover:bg-gray-11" - title={t("composer.stop", locale)} + title={t("composer.stop")} > - {t("composer.stop", locale)} + {t("composer.stop")} ) : ( )} @@ -1291,7 +1290,7 @@ export function ReactSessionComposer(props: ComposerProps) { onClick={() => setAgentMenuOpen((value) => !value)} disabled={props.busy} aria-expanded={agentMenuOpen} - title={t("composer.agent_label", locale)} + title={t("composer.agent_label")} > {props.agentLabel} @@ -1299,7 +1298,7 @@ export function ReactSessionComposer(props: ComposerProps) { {agentMenuOpen ? (
- {t("composer.agent_label", locale)} + {t("composer.agent_label")}
- {t("composer.default_agent", locale)} + {t("composer.default_agent")} {!props.selectedAgent ? : null} {agents.map((agent, index) => { @@ -1384,7 +1383,7 @@ export function ReactSessionComposer(props: ComposerProps) { {variantMenuOpen ? (
- {t("composer.behavior_label", locale)} + {t("composer.behavior_label")}
{props.modelBehaviorOptions.map((option) => { diff --git a/apps/app/src/react-app/domains/session/sync/actions-store.ts b/apps/app/src/react-app/domains/session/sync/actions-store.ts index dbf5f41bd..bb6afc713 100644 --- a/apps/app/src/react-app/domains/session/sync/actions-store.ts +++ b/apps/app/src/react-app/domains/session/sync/actions-store.ts @@ -7,7 +7,7 @@ import type { TextPartInput, } from "@opencode-ai/sdk/v2/client"; -import { t, currentLocale } from "../../../../i18n"; +import { t } from "../../../../i18n"; import { unwrap } from "../../../../app/lib/opencode"; import { abortSession as abortSessionTyped, @@ -279,8 +279,8 @@ export function createSessionActionsStore(options: { 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 (status === 401 || status === 403) return t("app.error_auth_failed"); + if (status === 429) return t("app.error_rate_limit"); if (provider) return `Provider error (${provider})`; return fallback; })(); @@ -304,7 +304,7 @@ export function createSessionActionsStore(options: { 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("app.error_request_failed"))); }; const lastPromptSent = () => snapshot.lastPromptSent; @@ -437,7 +437,7 @@ export function createSessionActionsStore(options: { error: e instanceof Error ? e.message : safeStringify(e), workspaceId: id, }); - const message = e instanceof Error ? e.message : t("app.unknown_error", currentLocale()); + const message = e instanceof Error ? e.message : t("app.unknown_error"); options.setError(addOpencodeCacheHint(message)); return undefined; } finally { @@ -498,7 +498,7 @@ export function createSessionActionsStore(options: { const compactCommand = resolvedDraft.command?.name === "compact" || compactShortcut; const commandName = compactCommand ? "compact" : (resolvedDraft.command?.name ?? null); if (compactCommand && !options.selectedSessionId()) { - options.setError(t("app.error_compact_no_session", currentLocale())); + options.setError(t("app.error_compact_no_session")); return; } @@ -560,7 +560,7 @@ export function createSessionActionsStore(options: { const command = resolvedDraft.command; if (!command) { - throw new Error(t("app.error_command_not_resolved", currentLocale())); + throw new Error(t("app.error_command_not_resolved")); } const modelString = `${model.providerID}/${model.modelID}`; @@ -640,17 +640,17 @@ export function createSessionActionsStore(options: { async function compactCurrentSession(sessionIdOverride?: string) { const c = options.client(); if (!c) { - throw new Error(t("app.error_not_connected", currentLocale())); + throw new Error(t("app.error_not_connected")); } const sessionID = (sessionIdOverride ?? options.selectedSessionId() ?? "").trim(); if (!sessionID) { - throw new Error(t("app.error_compact_no_session_id", currentLocale())); + throw new Error(t("app.error_compact_no_session_id")); } const visible = options.messages(); if (!visible.length) { - throw new Error(t("app.error_compact_empty", currentLocale())); + throw new Error(t("app.error_compact_empty")); } const model = options.selectedSessionModel(); @@ -765,7 +765,7 @@ export function createSessionActionsStore(options: { async function renameSessionTitle(sessionID: string, title: string) { const trimmed = title.trim(); if (!trimmed) { - throw new Error(t("app.error_session_name_required", currentLocale())); + throw new Error(t("app.error_session_name_required")); } await options.renameSession(sessionID, trimmed); @@ -777,7 +777,7 @@ export function createSessionActionsStore(options: { if (!trimmed) return; const c = options.client(); if (!c) { - throw new Error(t("app.error_not_connected", currentLocale())); + throw new Error(t("app.error_not_connected")); } const root = options.selectedWorkspaceRoot().trim(); @@ -829,7 +829,7 @@ export function createSessionActionsStore(options: { const BUILTIN_COMPACT_COMMAND = { id: "builtin:compact", name: "compact", - description: t("app.compact_command_desc", currentLocale()), + description: t("app.compact_command_desc"), source: "command" as const, }; diff --git a/apps/app/src/react-app/domains/session/sync/usechat-adapter.ts b/apps/app/src/react-app/domains/session/sync/usechat-adapter.ts index 9880e08a9..5f7a75662 100644 --- a/apps/app/src/react-app/domains/session/sync/usechat-adapter.ts +++ b/apps/app/src/react-app/domains/session/sync/usechat-adapter.ts @@ -360,7 +360,7 @@ function handleEventChunk( export function createOpenworkChatTransport(options: TransportOptions): ChatTransport { return { async sendMessages({ messages, abortSignal }) { - const client = createClient(options.baseUrl, undefined, { + const client = createClient(options.baseUrl, { token: options.openworkToken, mode: "openwork", }); diff --git a/apps/app/src/react-app/domains/settings/modals/reset-modal.tsx b/apps/app/src/react-app/domains/settings/modals/reset-modal.tsx index 84aa3a939..1b939105c 100644 --- a/apps/app/src/react-app/domains/settings/modals/reset-modal.tsx +++ b/apps/app/src/react-app/domains/settings/modals/reset-modal.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from "react"; import { X } from "lucide-react"; -import { t, type Language } from "../../../../i18n"; +import { t } from "../../../../i18n"; const RESET_CONFIRM_PLACEHOLDER = "{resetWord}"; const RESET_CONFIRM_WORD = "RESET"; @@ -21,17 +21,14 @@ export type ResetModalProps = { busy: boolean; canReset: boolean; hasActiveRuns: boolean; - language: Language; onClose: () => void; onConfirm: () => void; onTextChange: (value: string) => void; }; export function ResetModal(props: ResetModalProps) { - const translate = (key: string) => t(key, props.language); - const resetConfirmationHint = (): ReactNode => { - const template = translate("settings.reset_confirmation_hint"); + const template = t("settings.reset_confirmation_hint"); const parts = template.split(RESET_CONFIRM_PLACEHOLDER); if (parts.length === 1) return template; const nodes: ReactNode[] = []; @@ -58,8 +55,8 @@ export function ResetModal(props: ResetModalProps) {

{props.mode === "onboarding" - ? translate("settings.reset_onboarding_title") - : translate("settings.reset_app_data_title")} + ? t("settings.reset_onboarding_title") + : t("settings.reset_app_data_title")}

{resetConfirmationHint()} @@ -78,23 +75,23 @@ export function ResetModal(props: ResetModalProps) {

{props.mode === "onboarding" - ? translate("settings.reset_onboarding_warning") - : translate("settings.reset_app_data_warning")} + ? t("settings.reset_onboarding_warning") + : t("settings.reset_app_data_warning")}
{props.hasActiveRuns ? (
- {translate("settings.reset_stop_active_runs")} + {t("settings.reset_stop_active_runs")}
) : null}
diff --git a/apps/app/src/react-app/domains/settings/pages/mcp-view.tsx b/apps/app/src/react-app/domains/settings/pages/mcp-view.tsx index df357832d..33f492d54 100644 --- a/apps/app/src/react-app/domains/settings/pages/mcp-view.tsx +++ b/apps/app/src/react-app/domains/settings/pages/mcp-view.tsx @@ -37,7 +37,7 @@ import { } from "../../../../app/mcp"; import type { McpServerEntry, McpStatusMap } from "../../../../app/types"; import { formatRelativeTime, isDesktopRuntime, isWindowsPlatform } from "../../../../app/utils"; -import { currentLocale, t, type Language } from "../../../../i18n"; +import { t } from "../../../../i18n"; import { Button } from "../../../design-system/button"; import { ConfirmModal } from "../../../design-system/modals/confirm-modal"; import { AddMcpModal } from "../../connections/modals/add-mcp-modal"; @@ -88,19 +88,19 @@ const statusDot = (status: ReactMcpStatus) => { } }; -const friendlyStatus = (status: ReactMcpStatus, locale: Language) => { +const friendlyStatus = (status: ReactMcpStatus) => { switch (status) { case "connected": - return t("mcp.friendly_status_ready", locale); + return t("mcp.friendly_status_ready"); case "needs_auth": case "needs_client_registration": - return t("mcp.friendly_status_needs_signin", locale); + return t("mcp.friendly_status_needs_signin"); case "disabled": - return t("mcp.friendly_status_paused", locale); + return t("mcp.friendly_status_paused"); case "disconnected": - return t("mcp.friendly_status_offline", locale); + return t("mcp.friendly_status_offline"); default: - return t("mcp.friendly_status_issue", locale); + return t("mcp.friendly_status_issue"); } }; @@ -159,8 +159,6 @@ const serviceIconBg = (name: string) => { }; export function McpView(props: McpViewProps) { - const locale = currentLocale(); - const tr = (key: string) => t(key, locale); const showHeader = props.showHeader !== false; const [logoutOpen, setLogoutOpen] = useState(false); @@ -215,17 +213,17 @@ export function McpView(props: McpViewProps) { setProjectConfig(null); setGlobalConfig(null); setConfigError( - error instanceof Error ? error.message : tr("mcp.config_load_failed"), + error instanceof Error ? error.message : t("mcp.config_load_failed"), ); } })(); - }, [locale, props.readConfigFile, props.selectedWorkspaceRoot]); + }, [props.readConfigFile, props.selectedWorkspaceRoot]); const activeConfig = configScope === "project" ? projectConfig : globalConfig; const revealLabel = isWindowsPlatform() - ? tr("mcp.open_file") - : tr("mcp.reveal_in_finder"); + ? t("mcp.open_file") + : t("mcp.reveal_in_finder"); const canRevealConfig = isDesktopRuntime() && @@ -314,7 +312,7 @@ export function McpView(props: McpViewProps) { const root = props.selectedWorkspaceRoot.trim(); if (configScope === "project" && !root) { - setConfigError(tr("mcp.pick_workspace_error")); + setConfigError(t("mcp.pick_workspace_error")); return; } @@ -325,7 +323,7 @@ export function McpView(props: McpViewProps) { ? await props.readConfigFile(configScope) : await readOpencodeConfig(configScope, root); if (!resolved) { - throw new Error(tr("mcp.config_load_failed")); + throw new Error(t("mcp.config_load_failed")); } if (isWindowsPlatform()) { await openDesktopPath(resolved.path); @@ -334,7 +332,7 @@ export function McpView(props: McpViewProps) { } } catch (error) { setConfigError( - error instanceof Error ? error.message : tr("mcp.reveal_config_failed"), + error instanceof Error ? error.message : t("mcp.reveal_config_failed"), ); } finally { setRevealBusy(false); @@ -345,13 +343,13 @@ export function McpView(props: McpViewProps) {
{showHeader ? (
-

{tr("mcp.apps_title")}

-

{tr("mcp.apps_subtitle")}

+

{t("mcp.apps_title")}

+

{t("mcp.apps_subtitle")}

{connectedCount > 0 ? (
- {connectedCount} {connectedCount === 1 ? tr("mcp.app_connected") : tr("mcp.apps_connected")} + {connectedCount} {connectedCount === 1 ? t("mcp.app_connected") : t("mcp.apps_connected")}
) : null} @@ -367,12 +365,12 @@ export function McpView(props: McpViewProps) {
-
{tr("mcp.add_modal_title")}
-
{tr("mcp.custom_app_cta_hint")}
+
{t("mcp.add_modal_title")}
+
{t("mcp.custom_app_cta_hint")}
@@ -380,9 +378,9 @@ export function McpView(props: McpViewProps) {

- {tr("mcp.available_apps")} + {t("mcp.available_apps")}

- {tr("mcp.one_click_connect")} + {t("mcp.one_click_connect")}
@@ -399,7 +397,7 @@ export function McpView(props: McpViewProps) {
@@ -467,7 +465,7 @@ export function McpView(props: McpViewProps) {

{!configured && !connecting ? (
- {tr("mcp.tap_to_connect")} + {t("mcp.tap_to_connect")}
) : null}
@@ -482,11 +480,11 @@ export function McpView(props: McpViewProps) {

- {tr("mcp.your_apps")} + {t("mcp.your_apps")}

{props.mcpLastUpdatedAt ? ( - {tr("mcp.last_synced")} {formatRelativeTime(props.mcpLastUpdatedAt ?? Date.now())} + {t("mcp.last_synced")} {formatRelativeTime(props.mcpLastUpdatedAt ?? Date.now())} ) : null}
@@ -502,7 +500,7 @@ export function McpView(props: McpViewProps) { resolvedStatus && resolvedStatus.status === "failed" ? "error" in resolvedStatus ? resolvedStatus.error - : tr("mcp.connection_failed") + : t("mcp.connection_failed") : null; return ( @@ -542,7 +540,7 @@ export function McpView(props: McpViewProps) {
- {friendlyStatus(status, locale)} + {friendlyStatus(status)}
@@ -554,19 +552,19 @@ export function McpView(props: McpViewProps) { {isSelected ? (
- {tr("mcp.connection_type")} + {t("mcp.connection_type")} - {entry.config.type === "remote" ? tr("mcp.type_cloud") : tr("mcp.type_local")} + {entry.config.type === "remote" ? t("mcp.type_cloud") : t("mcp.type_local")}
- {tr("mcp.cap_tools")} + {t("mcp.cap_tools")} {entry.config.type === "remote" ? ( - {tr("mcp.cap_signin")} + {t("mcp.cap_signin")} ) : null}
@@ -580,7 +578,7 @@ export function McpView(props: McpViewProps) {
- {tr("mcp.technical_details")} + {t("mcp.technical_details")}
@@ -593,24 +591,24 @@ export function McpView(props: McpViewProps) { {supportsOauth(entry) && status !== "connected" ? ( <>
-
{tr("mcp.logout_label")}
+
{t("mcp.logout_label")}
-
{tr("mcp.login_hint")}
+
{t("mcp.login_hint")}
) : null} {supportsOauth(entry) && status === "connected" ? ( <>
-
{tr("mcp.logout_label")}
+
{t("mcp.logout_label")}
-
{tr("mcp.logout_hint")}
+
{t("mcp.logout_hint")}
) : null} @@ -634,7 +632,7 @@ export function McpView(props: McpViewProps) { onClick={() => openControlChromeModal("edit", entry)} > - {tr("mcp.control_chrome_edit")} + {t("mcp.control_chrome_edit")} ) : null} {props.setMcpEnabled && entry.source !== "config.global" ? ( @@ -654,8 +652,8 @@ export function McpView(props: McpViewProps) { > {entry.config.enabled === false - ? tr("mcp.enable_app") - : tr("mcp.disable_app")} + ? t("mcp.enable_app") + : t("mcp.disable_app")} ) : null}
@@ -679,18 +677,18 @@ export function McpView(props: McpViewProps) { ) : (
-
{tr("mcp.no_apps_yet")}
-
{tr("mcp.no_apps_hint")}
+
{t("mcp.no_apps_yet")}
+
{t("mcp.no_apps_hint")}
)}
{ if (logoutBusy) return; @@ -704,10 +702,10 @@ export function McpView(props: McpViewProps) { { setRemoveOpen(false); @@ -729,8 +727,8 @@ export function McpView(props: McpViewProps) {
-
{tr("mcp.advanced_settings")}
-
{tr("mcp.advanced_settings_hint")}
+
{t("mcp.advanced_settings")}
+
{t("mcp.advanced_settings_hint")}
@@ -750,7 +748,7 @@ export function McpView(props: McpViewProps) { }`} onClick={() => setConfigScope("project")} > - {tr("mcp.scope_project")} + {t("mcp.scope_project")}
-
{tr("mcp.config_file")}
+
{t("mcp.config_file")}
- {activeConfig?.path ?? tr("mcp.config_not_loaded")} + {activeConfig?.path ?? t("mcp.config_not_loaded")}
@@ -778,7 +776,7 @@ export function McpView(props: McpViewProps) { {revealBusy ? ( <> - {tr("mcp.opening_label")} + {t("mcp.opening_label")} ) : ( <> @@ -793,12 +791,12 @@ export function McpView(props: McpViewProps) { rel="noopener noreferrer" className="inline-flex items-center gap-1 text-xs text-dls-secondary transition-colors hover:text-dls-text" > - {tr("mcp.docs_link")} + {t("mcp.docs_link")}
{activeConfig && activeConfig.exists === false ? ( -
{tr("mcp.file_not_found")}
+
{t("mcp.file_not_found")}
) : null}
@@ -813,13 +811,11 @@ export function McpView(props: McpViewProps) { onAdd={(entry) => props.connectMcp(entry)} busy={props.busy} isRemoteWorkspace={props.isRemoteWorkspace} - language={locale} /> setControlChromeModalOpen(false)} diff --git a/apps/app/src/react-app/domains/settings/state/extensions-store.ts b/apps/app/src/react-app/domains/settings/state/extensions-store.ts index b22a03d9e..ea3c45740 100644 --- a/apps/app/src/react-app/domains/settings/state/extensions-store.ts +++ b/apps/app/src/react-app/domains/settings/state/extensions-store.ts @@ -2,7 +2,7 @@ import * as React from "react"; import { applyEdits, modify } from "jsonc-parser"; -import { currentLocale, t } from "../../../../i18n"; +import { t } from "../../../../i18n"; import type { Client, DenOrgSkillCard, @@ -192,7 +192,6 @@ export function createExtensionsStore(options: { markReloadRequired?: (reason: ReloadReason, trigger?: ReloadTrigger) => void; }) { const listeners = new Set<() => void>(); - const translate = (key: string) => t(key, currentLocale()); let disposed = false; let started = false; @@ -539,18 +538,18 @@ export function createExtensionsStore(options: { } if (!isDesktopRuntime()) { - throw new Error(translate("skills.desktop_required")); + throw new Error(t("skills.desktop_required")); } if (!isLocalWorkspace || !root) { - throw new Error(translate("skills.pick_workspace_first")); + throw new Error(t("skills.pick_workspace_first")); } const result = await installSkillTemplate(root, name, content, { overwrite: optionsOverride?.overwrite ?? false, }); if (!result.ok) { - throw new Error(result.stderr || result.stdout || translate("skills.install_failed")); + throw new Error(result.stderr || result.stdout || t("skills.install_failed")); } }; @@ -609,16 +608,16 @@ export function createExtensionsStore(options: { } if (!isDesktopRuntime()) { - throw new Error(translate("skills.desktop_required")); + throw new Error(t("skills.desktop_required")); } if (!isLocalWorkspace || !root) { - throw new Error(translate("skills.pick_workspace_first")); + throw new Error(t("skills.pick_workspace_first")); } const result = await uninstallSkillCommand(root, name); if (!result.ok) { - throw new Error(result.stderr || result.stdout || translate("skills.uninstall_failed")); + throw new Error(result.stderr || result.stdout || t("skills.uninstall_failed")); } }; @@ -1016,7 +1015,7 @@ export function createExtensionsStore(options: { ...current, cloudOrgSkills: [], cloudOrgSkillsStatus: - error instanceof Error ? error.message : translate("skills.cloud_org_load_failed"), + error instanceof Error ? error.message : t("skills.cloud_org_load_failed"), })); } finally { refreshCloudOrgSkillsInFlight = false; @@ -1168,7 +1167,7 @@ export function createExtensionsStore(options: { files, }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message, files: [] }; } finally { @@ -1206,7 +1205,7 @@ export function createExtensionsStore(options: { importedNames, }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message, importedNames }; } finally { @@ -1241,7 +1240,7 @@ export function createExtensionsStore(options: { await refreshCloudOrgSkillHubs({ force: true }); return { ok: true, message: `Synced ${hub.name} from cloud.`, importedNames: applied.nextSkillNames }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message, importedNames: [] }; } finally { @@ -1277,7 +1276,7 @@ export function createExtensionsStore(options: { removedNames: imported.skillNames, }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message, removedNames: [] }; } finally { @@ -1318,7 +1317,7 @@ export function createExtensionsStore(options: { if (!result?.ok) return { ok: false, message: "Install failed." }; return { ok: true, message: `Installed ${trimmed}.` }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message }; } finally { @@ -1350,10 +1349,10 @@ export function createExtensionsStore(options: { await refreshCloudOrgSkills({ force: true }); return { ok: true, - message: t(existingImport ? "skills.cloud_updated" : "skills.cloud_installed", currentLocale(), { name: installName }), + message: t(existingImport ? "skills.cloud_updated" : "skills.cloud_installed", { name: installName }), }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message }; } finally { @@ -1387,11 +1386,11 @@ export function createExtensionsStore(options: { await refreshCloudOrgSkills({ force: true }); return { ok: true, - message: t("skills.cloud_removed", currentLocale(), { name: imported.installedName }), + message: t("skills.cloud_removed", { name: imported.installedName }), removedName: imported.installedName, }; } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); return { ok: false, message, removedName: null }; } finally { @@ -1438,7 +1437,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: [], - skillsStatus: translate("skills.pick_workspace_first"), + skillsStatus: t("skills.pick_workspace_first"), })); return; } @@ -1465,7 +1464,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: next, - skillsStatus: next.length ? null : translate("skills.no_skills_found"), + skillsStatus: next.length ? null : t("skills.no_skills_found"), skillsContextKey: getWorkspaceContextKey(), })); skillsLoaded = true; @@ -1475,7 +1474,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: [], - skillsStatus: error instanceof Error ? error.message : translate("skills.failed_to_load"), + skillsStatus: error instanceof Error ? error.message : t("skills.failed_to_load"), })); } finally { refreshSkillsInFlight = false; @@ -1505,7 +1504,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: next, - skillsStatus: next.length ? null : translate("skills.no_skills_found"), + skillsStatus: next.length ? null : t("skills.no_skills_found"), skillsContextKey: getWorkspaceContextKey(), })); skillsLoaded = true; @@ -1515,7 +1514,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: [], - skillsStatus: error instanceof Error ? error.message : translate("skills.failed_to_load"), + skillsStatus: error instanceof Error ? error.message : t("skills.failed_to_load"), })); } finally { refreshSkillsInFlight = false; @@ -1549,7 +1548,7 @@ export function createExtensionsStore(options: { }; if (result?.data === undefined) { const err = result?.error; - const message = err instanceof Error ? err.message : typeof err === "string" ? err : translate("skills.failed_to_load"); + const message = err instanceof Error ? err.message : typeof err === "string" ? err : t("skills.failed_to_load"); throw new Error(message); } if (refreshSkillsAborted) return; @@ -1563,7 +1562,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: next, - skillsStatus: next.length ? null : translate("skills.no_skills_found"), + skillsStatus: next.length ? null : t("skills.no_skills_found"), skillsContextKey: getWorkspaceContextKey(), })); skillsLoaded = true; @@ -1573,7 +1572,7 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, skills: [], - skillsStatus: error instanceof Error ? error.message : translate("skills.failed_to_load"), + skillsStatus: error instanceof Error ? error.message : t("skills.failed_to_load"), })); } finally { refreshSkillsInFlight = false; @@ -1651,9 +1650,9 @@ export function createExtensionsStore(options: { if (!isDesktopRuntime()) { mutateState((current) => ({ ...current, - pluginStatus: translate("skills.plugin_management_host_only"), + pluginStatus: t("skills.plugin_management_host_only"), pluginList: [], - sidebarPluginStatus: translate("skills.plugins_host_only"), + sidebarPluginStatus: t("skills.plugins_host_only"), sidebarPluginList: [], })); refreshPluginsInFlight = false; @@ -1675,9 +1674,9 @@ export function createExtensionsStore(options: { if (scope === "project" && !targetDir) { mutateState((current) => ({ ...current, - pluginStatus: translate("skills.pick_project_for_plugins"), + pluginStatus: t("skills.pick_project_for_plugins"), pluginList: [], - sidebarPluginStatus: translate("skills.pick_project_for_active"), + sidebarPluginStatus: t("skills.pick_project_for_active"), sidebarPluginList: [], })); refreshPluginsInFlight = false; @@ -1695,9 +1694,9 @@ export function createExtensionsStore(options: { mutateState((current) => ({ ...current, pluginList: [], - pluginStatus: translate("skills.no_opencode_found"), + pluginStatus: t("skills.no_opencode_found"), sidebarPluginList: [], - sidebarPluginStatus: translate("skills.no_opencode_workspace"), + sidebarPluginStatus: t("skills.no_opencode_workspace"), })); return; } @@ -1708,7 +1707,7 @@ export function createExtensionsStore(options: { nextSidebarPluginList = parsePluginListFromContent(config.content ?? ""); } catch { nextSidebarPluginList = []; - nextSidebarPluginStatus = translate("skills.failed_parse_opencode"); + nextSidebarPluginStatus = t("skills.failed_parse_opencode"); } const nextPluginList: string[] = []; @@ -1738,8 +1737,8 @@ export function createExtensionsStore(options: { pluginConfig: null, pluginConfigPath: null, pluginList: [], - pluginStatus: error instanceof Error ? error.message : translate("skills.failed_load_opencode"), - sidebarPluginStatus: translate("skills.failed_load_active"), + pluginStatus: error instanceof Error ? error.message : t("skills.failed_load_opencode"), + sidebarPluginStatus: t("skills.failed_load_active"), sidebarPluginList: [], })); } finally { @@ -1764,7 +1763,7 @@ export function createExtensionsStore(options: { openworkSnapshot.openworkServerCapabilities?.plugins?.write; if (!pluginName) { - if (isManualInput) setStateField("pluginStatus", translate("skills.enter_plugin_name")); + if (isManualInput) setStateField("pluginStatus", t("skills.enter_plugin_name")); return; } @@ -1787,7 +1786,7 @@ export function createExtensionsStore(options: { } if (!isDesktopRuntime()) { - setStateField("pluginStatus", translate("skills.plugin_management_host_only")); + setStateField("pluginStatus", t("skills.plugin_management_host_only")); return; } @@ -1800,7 +1799,7 @@ export function createExtensionsStore(options: { const targetDir = options.projectDir().trim(); if (scope === "project" && !targetDir) { - setStateField("pluginStatus", translate("skills.pick_project_for_plugins")); + setStateField("pluginStatus", t("skills.pick_project_for_plugins")); return; } @@ -1821,7 +1820,7 @@ export function createExtensionsStore(options: { const plugins = parsePluginListFromContent(raw); const desired = stripPluginVersion(pluginName).toLowerCase(); if (plugins.some((entry) => stripPluginVersion(entry).toLowerCase() === desired)) { - setStateField("pluginStatus", translate("skills.plugin_already_listed")); + setStateField("pluginStatus", t("skills.plugin_already_listed")); return; } @@ -1833,7 +1832,7 @@ export function createExtensionsStore(options: { if (isManualInput) setStateField("pluginInput", ""); await refreshPlugins(scope); } catch (error) { - setStateField("pluginStatus", error instanceof Error ? error.message : translate("skills.failed_update_opencode")); + setStateField("pluginStatus", error instanceof Error ? error.message : t("skills.failed_update_opencode")); } } @@ -1870,7 +1869,7 @@ export function createExtensionsStore(options: { } if (!isDesktopRuntime()) { - setStateField("pluginStatus", translate("skills.plugin_management_host_only")); + setStateField("pluginStatus", t("skills.plugin_management_host_only")); return; } @@ -1882,7 +1881,7 @@ export function createExtensionsStore(options: { const scope = snapshot.pluginScope; const targetDir = options.projectDir().trim(); if (scope === "project" && !targetDir) { - setStateField("pluginStatus", translate("skills.pick_project_for_plugins")); + setStateField("pluginStatus", t("skills.pick_project_for_plugins")); return; } @@ -1909,14 +1908,14 @@ export function createExtensionsStore(options: { options.markReloadRequired?.("plugins", { type: "plugin", name: triggerName, action: "removed" }); await refreshPlugins(scope); } catch (error) { - setStateField("pluginStatus", error instanceof Error ? error.message : translate("skills.failed_update_opencode")); + setStateField("pluginStatus", error instanceof Error ? error.message : t("skills.failed_update_opencode")); } } async function importLocalSkill() { const isLocalWorkspace = options.workspaceType() === "local"; if (!isDesktopRuntime()) { - options.setError(translate("skills.desktop_required")); + options.setError(t("skills.desktop_required")); return; } if (!isLocalWorkspace) { @@ -1925,7 +1924,7 @@ export function createExtensionsStore(options: { } const targetDir = options.projectDir().trim(); if (!targetDir) { - options.setError(translate("skills.pick_project_first")); + options.setError(t("skills.pick_project_first")); return; } @@ -1933,20 +1932,20 @@ export function createExtensionsStore(options: { options.setError(null); setStateField("skillsStatus", null); try { - const selection = await pickDirectory({ title: translate("skills.select_skill_folder") }); + const selection = await pickDirectory({ title: t("skills.select_skill_folder") }); const sourceDir = typeof selection === "string" ? selection : Array.isArray(selection) ? selection[0] : null; if (!sourceDir) return; const inferredName = sourceDir.split(/[\\/]/).filter(Boolean).pop(); const result = await importSkill(targetDir, sourceDir, { overwrite: false }); if (!result.ok) { - setStateField("skillsStatus", result.stderr || result.stdout || translate("skills.import_failed").replace("{status}", String(result.status))); + setStateField("skillsStatus", result.stderr || result.stdout || t("skills.import_failed").replace("{status}", String(result.status))); } else { - setStateField("skillsStatus", result.stdout || translate("skills.imported")); + setStateField("skillsStatus", result.stdout || t("skills.imported")); options.markReloadRequired?.("skills", { type: "skill", name: inferredName, action: "added" }); } await refreshSkills({ force: true }); } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); } finally { options.setBusy(false); @@ -1968,16 +1967,16 @@ export function createExtensionsStore(options: { if (canUseOpenworkServer) { options.setBusy(true); options.setError(null); - setStateField("skillsStatus", translate("skills.installing_skill_creator")); + setStateField("skillsStatus", t("skills.installing_skill_creator")); try { await openworkClient.upsertSkill(openworkWorkspaceId, { name: "skill-creator", content: skillCreatorTemplate }); - const message = translate("skills.skill_creator_installed"); + const message = t("skills.skill_creator_installed"); setStateField("skillsStatus", message); options.markReloadRequired?.("skills", { type: "skill", name: "skill-creator", action: "added" }); await refreshSkills({ force: true }); return { ok: true, message }; } catch (error) { - const raw = error instanceof Error ? error.message : translate("skills.unknown_error"); + const raw = error instanceof Error ? error.message : t("skills.unknown_error"); const message = addOpencodeCacheHint(raw); setStateField("skillsStatus", message); options.setError(message); @@ -1993,7 +1992,7 @@ export function createExtensionsStore(options: { return { ok: false, message }; } if (!isDesktopRuntime()) { - const message = translate("skills.desktop_required"); + const message = t("skills.desktop_required"); setStateField("skillsStatus", message); return { ok: false, message }; } @@ -2006,35 +2005,35 @@ export function createExtensionsStore(options: { const targetDir = options.selectedWorkspaceRoot().trim(); if (!targetDir) { - const message = translate("skills.pick_workspace_first"); + const message = t("skills.pick_workspace_first"); setStateField("skillsStatus", message); return { ok: false, message }; } options.setBusy(true); options.setError(null); - setStateField("skillsStatus", translate("skills.installing_skill_creator")); + setStateField("skillsStatus", t("skills.installing_skill_creator")); try { const result = await installSkillTemplate(targetDir, "skill-creator", skillCreatorTemplate, { overwrite: false }); if (!result.ok && /already exists/i.test(result.stderr)) { - const message = translate("skills.skill_creator_already_installed"); + const message = t("skills.skill_creator_already_installed"); setStateField("skillsStatus", message); await refreshSkills({ force: true }); return { ok: true, message }; } if (!result.ok) { - const message = result.stderr || result.stdout || translate("skills.install_failed"); + const message = result.stderr || result.stdout || t("skills.install_failed"); setStateField("skillsStatus", message); await refreshSkills({ force: true }); return { ok: false, message }; } - const message = result.stdout || translate("skills.skill_creator_installed"); + const message = result.stdout || t("skills.skill_creator_installed"); setStateField("skillsStatus", message); options.markReloadRequired?.("skills", { type: "skill", name: "skill-creator", action: "added" }); await refreshSkills({ force: true }); return { ok: true, message }; } catch (error) { - const raw = error instanceof Error ? error.message : translate("skills.unknown_error"); + const raw = error instanceof Error ? error.message : t("skills.unknown_error"); const message = addOpencodeCacheHint(raw); setStateField("skillsStatus", message); options.setError(message); @@ -2046,12 +2045,12 @@ export function createExtensionsStore(options: { async function revealSkillsFolder() { if (!isDesktopRuntime()) { - setStateField("skillsStatus", translate("skills.desktop_required")); + setStateField("skillsStatus", t("skills.desktop_required")); return; } const root = options.selectedWorkspaceRoot().trim(); if (!root) { - setStateField("skillsStatus", translate("skills.pick_workspace_first")); + setStateField("skillsStatus", t("skills.pick_workspace_first")); return; } @@ -2072,14 +2071,14 @@ export function createExtensionsStore(options: { if (await tryOpen(legacySkills)) return; await revealDesktopItemInDir(opencodeSkills); } catch (error) { - setStateField("skillsStatus", error instanceof Error ? error.message : translate("skills.reveal_failed")); + setStateField("skillsStatus", error instanceof Error ? error.message : t("skills.reveal_failed")); } } async function uninstallSkill(name: string) { const root = options.selectedWorkspaceRoot().trim(); if (!root) { - setStateField("skillsStatus", translate("skills.pick_workspace_first")); + setStateField("skillsStatus", t("skills.pick_workspace_first")); return; } const trimmed = name.trim(); @@ -2090,11 +2089,11 @@ export function createExtensionsStore(options: { setStateField("skillsStatus", null); try { await deleteWorkspaceSkill(trimmed); - setStateField("skillsStatus", translate("skills.uninstalled")); + setStateField("skillsStatus", t("skills.uninstalled")); options.markReloadRequired?.("skills", { type: "skill", name: trimmed, action: "removed" }); await refreshSkills({ force: true }); } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); setStateField("skillsStatus", message); options.setError(addOpencodeCacheHint(message)); } finally { @@ -2107,7 +2106,7 @@ export function createExtensionsStore(options: { if (!trimmed) return null; const root = options.selectedWorkspaceRoot().trim(); if (!root) { - setStateField("skillsStatus", translate("skills.pick_workspace_first")); + setStateField("skillsStatus", t("skills.pick_workspace_first")); return null; } @@ -2128,7 +2127,7 @@ export function createExtensionsStore(options: { const result = await openworkClient.getSkill(openworkWorkspaceId, trimmed, { includeGlobal: isLocalWorkspace }); return { name: result.item.name, path: result.item.path, content: result.content }; } catch (error) { - setStateField("skillsStatus", error instanceof Error ? error.message : translate("skills.failed_to_load")); + setStateField("skillsStatus", error instanceof Error ? error.message : t("skills.failed_to_load")); return null; } } @@ -2138,7 +2137,7 @@ export function createExtensionsStore(options: { return null; } if (!isDesktopRuntime()) { - setStateField("skillsStatus", translate("skills.desktop_required")); + setStateField("skillsStatus", t("skills.desktop_required")); return null; } if (!isLocalWorkspace) { @@ -2151,7 +2150,7 @@ export function createExtensionsStore(options: { const result = await readLocalSkill(root, trimmed); return { name: trimmed, path: result.path, content: result.content }; } catch (error) { - setStateField("skillsStatus", error instanceof Error ? error.message : translate("skills.failed_to_load")); + setStateField("skillsStatus", error instanceof Error ? error.message : t("skills.failed_to_load")); return null; } } @@ -2161,7 +2160,7 @@ export function createExtensionsStore(options: { if (!trimmed) return; const root = options.selectedWorkspaceRoot().trim(); if (!root) { - setStateField("skillsStatus", translate("skills.pick_workspace_first")); + setStateField("skillsStatus", t("skills.pick_workspace_first")); return; } @@ -2190,7 +2189,7 @@ export function createExtensionsStore(options: { await refreshSkills({ force: true }); setStateField("skillsStatus", "Saved."); } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); } finally { options.setBusy(false); @@ -2203,7 +2202,7 @@ export function createExtensionsStore(options: { return; } if (!isDesktopRuntime()) { - setStateField("skillsStatus", translate("skills.desktop_required")); + setStateField("skillsStatus", t("skills.desktop_required")); return; } if (!isLocalWorkspace) { @@ -2217,14 +2216,14 @@ export function createExtensionsStore(options: { try { const result = await writeLocalSkill(root, trimmed, input.content); if (!result.ok) { - setStateField("skillsStatus", result.stderr || result.stdout || translate("skills.unknown_error")); + setStateField("skillsStatus", result.stderr || result.stdout || t("skills.unknown_error")); } else { setStateField("skillsStatus", result.stdout || "Saved."); options.markReloadRequired?.("skills", { type: "skill", name: trimmed, action: "updated" }); } await refreshSkills({ force: true }); } catch (error) { - const message = error instanceof Error ? error.message : translate("skills.unknown_error"); + const message = error instanceof Error ? error.message : t("skills.unknown_error"); options.setError(addOpencodeCacheHint(message)); } finally { options.setBusy(false); diff --git a/apps/app/src/react-app/domains/workspace/create-remote-workspace-modal.tsx b/apps/app/src/react-app/domains/workspace/create-remote-workspace-modal.tsx index ff09f5c0b..5220e1ba9 100644 --- a/apps/app/src/react-app/domains/workspace/create-remote-workspace-modal.tsx +++ b/apps/app/src/react-app/domains/workspace/create-remote-workspace-modal.tsx @@ -2,7 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { X } from "lucide-react"; -import { currentLocale, t } from "../../../i18n"; +import { t } from "../../../i18n"; import { errorBannerClass, modalBodyClass, @@ -22,7 +22,6 @@ export function CreateRemoteWorkspaceModal( props: CreateRemoteWorkspaceModalProps, ) { const inputRef = useRef(null); - const translate = (key: string) => t(key, currentLocale()); const [openworkHostUrl, setOpenworkHostUrl] = useState(""); const [openworkToken, setOpenworkToken] = useState(""); @@ -31,11 +30,11 @@ export function CreateRemoteWorkspaceModal( const [displayName, setDisplayName] = useState(""); const showClose = props.showClose ?? true; - const title = props.title ?? translate("dashboard.create_remote_workspace_title"); + const title = props.title ?? t("dashboard.create_remote_workspace_title"); const subtitle = - props.subtitle ?? translate("dashboard.create_remote_workspace_subtitle"); + props.subtitle ?? t("dashboard.create_remote_workspace_subtitle"); const confirmLabel = - props.confirmLabel ?? translate("dashboard.create_remote_workspace_confirm"); + props.confirmLabel ?? t("dashboard.create_remote_workspace_confirm"); const isInline = props.inline ?? false; const submitting = props.submitting ?? false; @@ -116,7 +115,7 @@ export function CreateRemoteWorkspaceModal( disabled={submitting} className={pillGhostClass} > - {translate("common.cancel")} + {t("common.cancel")} ) : null}
@@ -229,7 +229,7 @@ export function CreateWorkspaceLocalPanel( props.workerDisabledReason ? (
- {props.translate("dashboard.sandbox_get_ready_title")} + {t("dashboard.sandbox_get_ready_title")}
{props.workerDisabledReason || props.workerCtaDescription} @@ -286,7 +286,7 @@ export function CreateWorkspaceLocalPanel( disabled={props.submitting} className={pillGhostClass} > - {props.translate("common.cancel")} + {t("common.cancel")} {props.onConfirmWorker ? ( ) : null} @@ -324,7 +324,7 @@ export function CreateWorkspaceLocalPanel( disabled={!props.selectedFolder || props.submitting} title={ !props.selectedFolder - ? props.translate("dashboard.choose_folder_continue") + ? t("dashboard.choose_folder_continue") : undefined } className={pillPrimaryClass} @@ -336,7 +336,7 @@ export function CreateWorkspaceLocalPanel( ) : ( (props.confirmLabel ?? - props.translate("dashboard.create_workspace_confirm")) + t("dashboard.create_workspace_confirm")) )}
diff --git a/apps/app/src/react-app/domains/workspace/create-workspace-modal.tsx b/apps/app/src/react-app/domains/workspace/create-workspace-modal.tsx index 3ce8f2cdf..527e607b1 100644 --- a/apps/app/src/react-app/domains/workspace/create-workspace-modal.tsx +++ b/apps/app/src/react-app/domains/workspace/create-workspace-modal.tsx @@ -8,7 +8,7 @@ import { } from "react"; import { ArrowLeft, Cloud, FolderPlus, Globe, Loader2, X } from "lucide-react"; -import { currentLocale, t } from "../../../i18n"; +import { t } from "../../../i18n"; import { buildDenAuthUrl, createDenClient, @@ -42,35 +42,32 @@ import type { RemoteWorkspaceInput, } from "./types"; -function workerStatusMeta( - status: string, - translate: (key: string) => string, -) { +function workerStatusMeta(status: string) { const normalized = status.trim().toLowerCase(); switch (normalized) { case "healthy": return { - label: translate("dashboard.worker_status_ready"), + label: t("dashboard.worker_status_ready"), tone: "ready" as const, canOpen: true, }; case "provisioning": case "starting": return { - label: translate("dashboard.worker_status_starting"), + label: t("dashboard.worker_status_starting"), tone: "warning" as const, canOpen: false, }; case "failed": case "error": return { - label: translate("dashboard.worker_status_attention"), + label: t("dashboard.worker_status_attention"), tone: "error" as const, canOpen: false, }; case "stopped": return { - label: translate("dashboard.worker_status_stopped"), + label: t("dashboard.worker_status_stopped"), tone: "neutral" as const, canOpen: false, }; @@ -78,29 +75,21 @@ function workerStatusMeta( return { label: normalized ? `${normalized.slice(0, 1).toUpperCase()}${normalized.slice(1)}` - : translate("common.unknown"), + : t("common.unknown"), tone: "neutral" as const, canOpen: normalized === "ready", }; } } -function workerSecondaryLine( - worker: DenWorkerSummary, - translate: (key: string) => string, -) { - const parts = [worker.provider?.trim() || translate("dashboard.cloud_worker")]; +function workerSecondaryLine(worker: DenWorkerSummary) { + const parts = [worker.provider?.trim() || t("dashboard.cloud_worker")]; if (worker.instanceUrl?.trim()) parts.push(worker.instanceUrl.trim()); return parts.join(" · "); } export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { const remoteUrlRef = useRef(null); - const translate = useCallback( - (key: string, params?: Record) => - t(key, currentLocale(), params), - [], - ); const platform = usePlatform(); const [screen, setScreen] = useState("chooser"); @@ -175,28 +164,28 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { const headerTitle = (() => { switch (screen) { case "local": - return translate("dashboard.create_local_workspace_title"); + return t("dashboard.create_local_workspace_title"); case "remote": - return translate("dashboard.create_remote_custom_title"); + return t("dashboard.create_remote_custom_title"); case "shared": - return translate("dashboard.create_shared_title"); + return t("dashboard.create_shared_title"); default: - return props.title ?? translate("dashboard.create_workspace_title"); + return props.title ?? t("dashboard.create_workspace_title"); } })(); const headerSubtitle = (() => { switch (screen) { case "local": - return translate("dashboard.create_local_workspace_subtitle"); + return t("dashboard.create_local_workspace_subtitle"); case "remote": - return translate("dashboard.create_remote_custom_subtitle"); + return t("dashboard.create_remote_custom_subtitle"); case "shared": return isSignedIn - ? translate("dashboard.create_shared_subtitle_signed_in") - : translate("dashboard.create_shared_subtitle_signed_out"); + ? t("dashboard.create_shared_subtitle_signed_in") + : t("dashboard.create_shared_subtitle_signed_out"); default: - return props.subtitle ?? translate("dashboard.create_workspace_subtitle"); + return props.subtitle ?? t("dashboard.create_workspace_subtitle"); } })(); @@ -288,7 +277,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { setOrgsError( error instanceof Error ? error.message - : translate("dashboard.error_load_orgs"), + : t("dashboard.error_load_orgs"), ); } finally { setOrgsBusy(false); @@ -298,7 +287,6 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { cloudSettings.activeOrgId, denClient, isSignedIn, - translate, ]); const refreshWorkers = useCallback( @@ -313,13 +301,13 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { setWorkersError( error instanceof Error ? error.message - : translate("dashboard.error_load_shared_workspaces"), + : t("dashboard.error_load_shared_workspaces"), ); } finally { setWorkersBusy(false); } }, - [activeOrgId, denClient, isSignedIn, translate], + [activeOrgId, denClient, isSignedIn], ); // Load orgs/workers when the shared tab is active and signed in. @@ -374,7 +362,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { if (!props.onConfirmRemote) return; const orgId = activeOrgId.trim(); if (!orgId) { - setWorkersError(translate("dashboard.error_choose_org")); + setWorkersError(t("dashboard.error_choose_org")); return; } setOpeningWorkerId(worker.workerId); @@ -385,7 +373,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { const accessToken = tokens.ownerToken?.trim() || tokens.clientToken?.trim() || ""; if (!openworkUrl || !accessToken) { - throw new Error(translate("dashboard.error_workspace_not_ready")); + throw new Error(t("dashboard.error_workspace_not_ready")); } const ok = await Promise.resolve( props.onConfirmRemote({ @@ -400,7 +388,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { ); if (ok === false) { throw new Error( - translate("dashboard.error_connect_worker", { + t("dashboard.error_connect_worker", { name: worker.workerName, }), ); @@ -409,7 +397,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { setWorkersError( error instanceof Error ? error.message - : translate("dashboard.error_connect_worker", { + : t("dashboard.error_connect_worker", { name: worker.workerName, }), ); @@ -436,7 +424,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { onClick={() => setScreen("chooser")} disabled={submitting || remoteSubmitting} className={modalHeaderButtonClass} - aria-label={translate("dashboard.modal_back")} + aria-label={t("dashboard.modal_back")} > @@ -452,7 +440,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { onClick={props.onClose} disabled={submitting || remoteSubmitting} className={modalHeaderButtonClass} - aria-label={translate("dashboard.modal_close")} + aria-label={t("dashboard.modal_close")} > @@ -463,12 +451,12 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) {
setScreen("local")} @@ -476,20 +464,20 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { endAdornment={ props.localDisabled ? ( - {translate("dashboard.desktop_badge")} + {t("dashboard.desktop_badge")} ) : undefined } /> setScreen("remote")} /> setScreen("shared")} /> @@ -505,10 +493,10 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { {props.importingConfig ? ( - {translate("dashboard.importing")} + {t("dashboard.importing")} ) : ( - translate("dashboard.import_config") + t("dashboard.import_config") )}
@@ -519,7 +507,6 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { {screen === "local" ? (
@@ -583,7 +570,7 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { onClick={props.onClose} disabled={remoteSubmitting} > - {translate("common.cancel")} + {t("common.cancel")}
@@ -623,8 +610,8 @@ export function CreateWorkspaceModal(props: CreateWorkspaceModalProps) { onWorkerSearchInput={setWorkerSearch} filteredWorkers={filteredWorkers} openingWorkerId={openingWorkerId} - workerStatusMeta={(status) => workerStatusMeta(status, translate)} - workerSecondaryLine={(worker) => workerSecondaryLine(worker, translate)} + workerStatusMeta={(status) => workerStatusMeta(status)} + workerSecondaryLine={(worker) => workerSecondaryLine(worker)} onOpenWorker={(worker) => void handleOpenWorker(worker)} onOpenCloudSignIn={openCloudSignIn} onRefreshWorkers={() => void refreshWorkers()} diff --git a/apps/app/src/react-app/domains/workspace/rename-workspace-modal.tsx b/apps/app/src/react-app/domains/workspace/rename-workspace-modal.tsx index 672b088dc..d7178aa47 100644 --- a/apps/app/src/react-app/domains/workspace/rename-workspace-modal.tsx +++ b/apps/app/src/react-app/domains/workspace/rename-workspace-modal.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef } from "react"; import { X } from "lucide-react"; -import { currentLocale, t } from "../../../i18n"; +import { t } from "../../../i18n"; import { inputClass, pillGhostClass, pillPrimaryClass, pillSecondaryClass } from "./modal-styles"; export type RenameWorkspaceModalProps = { @@ -17,7 +17,6 @@ export type RenameWorkspaceModalProps = { export function RenameWorkspaceModal(props: RenameWorkspaceModalProps) { const inputRef = useRef(null); - const translate = (key: string) => t(key, currentLocale()); useEffect(() => { if (!props.open) return; @@ -37,10 +36,10 @@ export function RenameWorkspaceModal(props: RenameWorkspaceModalProps) {

- {translate("workspace.rename_title")} + {t("workspace.rename_title")}

- {translate("workspace.rename_description")} + {t("workspace.rename_description")}

@@ -83,7 +82,7 @@ export function RenameWorkspaceModal(props: RenameWorkspaceModalProps) { onClick={props.onClose} disabled={props.busy} > - {translate("common.cancel")} + {t("common.cancel")}
diff --git a/apps/app/src/react-app/kernel/global-sync-provider.tsx b/apps/app/src/react-app/kernel/global-sync-provider.tsx index 8f2516e43..c6dff22ed 100644 --- a/apps/app/src/react-app/kernel/global-sync-provider.tsx +++ b/apps/app/src/react-app/kernel/global-sync-provider.tsx @@ -24,7 +24,7 @@ import type { VcsInfo, } from "@opencode-ai/sdk/v2/client"; -import { currentLocale, t } from "../../i18n"; +import { t } from "../../i18n"; import { unwrap } from "../../app/lib/opencode"; import type { McpStatusMap, TodoItem } from "../../app/types"; import { safeStringify } from "../../app/utils"; @@ -134,7 +134,7 @@ export function GlobalSyncProvider({ children }: GlobalSyncProviderProps) { error instanceof Error ? error.message : safeStringify(error); setState((previous) => ({ ...previous, - error: message || t("app.unknown_error", currentLocale()), + error: message || t("app.unknown_error"), })); }, []); diff --git a/apps/app/src/react-app/shell/settings-route.tsx b/apps/app/src/react-app/shell/settings-route.tsx index 122a36aec..418a2683a 100644 --- a/apps/app/src/react-app/shell/settings-route.tsx +++ b/apps/app/src/react-app/shell/settings-route.tsx @@ -1410,7 +1410,6 @@ export function SettingsRoute() { 0} activeSessions={activeReloadBlockingSessions} isRemoteWorkspace={selectedWorkspace?.workspaceType === "remote"} diff --git a/scripts/i18n-audit.mjs b/scripts/i18n-audit.mjs index 1e515b932..f73fddc39 100644 --- a/scripts/i18n-audit.mjs +++ b/scripts/i18n-audit.mjs @@ -3,7 +3,7 @@ * i18n-audit.mjs — Find missing translations and improperly used translation keys. * * Usage: - * node scripts/i18n-audit.mjs # full audit (default, excludes --hardcoded, --aliases, --prune, --sort) + * node scripts/i18n-audit.mjs # full audit (default, excludes --hardcoded, --prune, --sort) * node scripts/i18n-audit.mjs --missing # missing keys (in EN but not in locale) * node scripts/i18n-audit.mjs --orphan # orphan keys (in locale but not in EN) * node scripts/i18n-audit.mjs --duplicates # duplicate keys in any locale @@ -29,7 +29,7 @@ const LOCALES = ["ja", "zh", "vi", "pt-BR", "th", "fr", "ca", "es"]; const EN_FILE = join(LOCALES_DIR, "en.ts"); const mode = process.argv[2] ?? "--all"; -const EXCLUDED_FROM_ALL = new Set(["--hardcoded", "--aliases"]); +const EXCLUDED_FROM_ALL = new Set(["--hardcoded"]); const shouldRun = (...modes) => (mode === "--all" && !modes.some((m) => EXCLUDED_FROM_ALL.has(m))) || modes.includes(mode); // --------------------------------------------------------------------------- @@ -329,14 +329,15 @@ if (shouldRun("--aliases")) { const aliasSourceFiles = collectSourceFiles(APP_SRC, (dir) => dir.includes("locales")); const aliasPattern = /\b(?:translate|tr)\s*\(/g; const aliasDefPattern = /(?:const|function)\s+(?:translate|tr)\s*[=(]/; + const aliasSkipPattern = /translate\s*\(\s*[-\d]|translate\s*\(\s*0|props\.translate|:\s*\(key:\s*string\)|`translate\(/; const hits = []; for (const file of aliasSourceFiles) { const content = readFileSync(file, "utf-8"); const lines = content.split("\n"); for (let i = 0; i < lines.length; i++) { - // Skip alias definitions themselves if (aliasDefPattern.test(lines[i])) continue; + if (aliasSkipPattern.test(lines[i])) continue; if (aliasPattern.test(lines[i])) { hits.push({ file: file.replace(REPO_ROOT + "/", ""), line: i + 1, text: lines[i].trim() }); }