diff --git a/apps/web/components/github/github-app-connection-panel.tsx b/apps/web/components/github/github-app-connection-panel.tsx index 0c1b6a26f8..8e66f8b5ad 100644 --- a/apps/web/components/github/github-app-connection-panel.tsx +++ b/apps/web/components/github/github-app-connection-panel.tsx @@ -9,11 +9,13 @@ import { useGitHubAppRegistrations } from "@/hooks/domains/github/use-github-app import { GitHubAppCreateForm } from "./github-app-create-form"; import { GitHubAppImportForm } from "./github-app-import-form"; import { GitHubAppRegistrationList } from "./github-app-registration-list"; +import { useTranslation } from "react-i18next"; type AppView = "choose" | "import" | "create"; type RegistrationHook = ReturnType; export function GitHubAppConnectionPanel({ workspaceId }: { workspaceId: string }) { + const { t } = useTranslation(); const registrations = useGitHubAppRegistrations(workspaceId); const [view, setView] = useState("choose"); const { selectedId, setSelectedId, selectedRegistration } = useAppRegistrationSelection( @@ -31,11 +33,12 @@ export function GitHubAppConnectionPanel({ workspaceId }: { workspaceId: string try { const response = await registrations.startInstall(selectedRegistration.id); const url = response.url ?? response.URL; - if (!url) throw new Error("GitHub did not return an installation URL"); + // Surfaced to the user by the catch below, so it is copy. + if (!url) throw new Error(t("github:githubDidNotReturnAnInstallationUrl")); window.location.assign(url); } catch (error) { toast({ - description: error instanceof Error ? error.message : "App installation failed", + description: error instanceof Error ? error.message : t("github:appInstallationFailed"), variant: "error", }); } @@ -67,16 +70,14 @@ export function GitHubAppConnectionPanel({ workspaceId }: { workspaceId: string return (
-

Choose a GitHub App

+

{t("github:chooseAGithubApp")}

- Use an App when automation needs its own identity, short-lived tokens, and - repository-level installation control. Setup is more involved and requires a publicly - reachable HTTPS URL. + {t("github:useAnAppWhenAutomationNeeds")}

{registrations.loading ? (
- Loading registered Apps... + {t("github:loadingRegisteredApps")}
) : ( {registrations.mutating && } - Install for this workspace + {t("github:installForThisWorkspace")}

- A registration can be reused across workspaces, or you can keep work and personal Apps - separate. Each workspace selects and installs its own credential. + {t("github:aRegistrationCanBeReusedAcross")}

); @@ -129,9 +129,10 @@ function useAppRegistrationSelection(workspaceId: string, registrations: Registr } function BackButton({ onClick }: { onClick: () => void }) { + const { t } = useTranslation(); return ( ); } diff --git a/apps/web/components/github/github-app-create-form.tsx b/apps/web/components/github/github-app-create-form.tsx index 47fb192841..733ceab8bb 100644 --- a/apps/web/components/github/github-app-create-form.tsx +++ b/apps/web/components/github/github-app-create-form.tsx @@ -19,6 +19,7 @@ import { import { GitHubAppPolicyDialog } from "./github-app-policy-dialog"; import { GitHubAppVisibilityField } from "./github-app-visibility-field"; import type { useGitHubAppRegistrations } from "@/hooks/domains/github/use-github-app-registrations"; +import { useTranslation } from "react-i18next"; type RegistrationHook = ReturnType; @@ -29,6 +30,7 @@ export function GitHubAppCreateForm({ workspaceId: string; registrations: RegistrationHook; }) { + const { t } = useTranslation(); const [displayName, setDisplayName] = useState(""); const [ownerType, setOwnerType] = useState<"user" | "organization">("organization"); const [ownerLogin, setOwnerLogin] = useState(""); @@ -70,7 +72,10 @@ export function GitHubAppCreateForm({ ); } catch (error) { const detail = appRegistrationError(error); - toast({ description: detail?.error ?? "GitHub App setup could not start", variant: "error" }); + toast({ + description: detail?.error ?? t("github:githubAppSetupCouldNotStart"), + variant: "error", + }); } } @@ -104,13 +109,13 @@ function ManifestHandoff({ handoff: StartGitHubAppManifestResponse; onEdit: () => void; }) { + const { t } = useTranslation(); return (
-

GitHub is ready to create the App

+

{t("github:githubIsReadyToCreateThe")}

- GitHub will show the generated permissions and ask you to confirm. Returning from GitHub - adds the registration; installing it for this workspace remains an explicit step. + {t("github:githubWillShowTheGeneratedPermissions")}

@@ -118,11 +123,11 @@ function ManifestHandoff({ className="h-11 cursor-pointer" onClick={() => submitManifestToGitHub(handoff.registration_url, handoff.manifest)} > - Continue on GitHub + {t("github:continueOnGithub")}
@@ -146,24 +151,24 @@ type CreateFieldsProps = { }; function CreateAppFields(props: CreateFieldsProps) { + const { t } = useTranslation(); return (
-

Create a GitHub App

+

{t("github:createAGithubApp")}

- Kandev generates the exact App policy. You confirm creation on GitHub; Kandev then stores - this registration so it can be selected by a workspace. + {t("github:kandevGeneratesTheExactAppPolicy")}

- + props.onDisplayName(event.target.value)} /> - + - + props.onPublicBaseUrl(event.target.value)} /> -

- GitHub must reach this HTTPS origin for signed webhooks and callbacks. -

+

{t("github:githubMustReachThisHttpsOrigin")}

diff --git a/apps/web/components/github/github-app-import-fields.tsx b/apps/web/components/github/github-app-import-fields.tsx index 0af4230b26..5e1be5b407 100644 --- a/apps/web/components/github/github-app-import-fields.tsx +++ b/apps/web/components/github/github-app-import-fields.tsx @@ -4,6 +4,7 @@ import { RadioGroup, RadioGroupItem } from "@kandev/ui/radio-group"; import { Textarea } from "@kandev/ui/textarea"; import type { GitHubAppOwnerType, GitHubAppVisibility } from "@/lib/types/github"; import type { AppSetupErrors } from "./github-app-onboarding-model"; +import { useTranslation } from "react-i18next"; export type GitHubAppImportValues = { displayName: string; @@ -30,24 +31,25 @@ export function GitHubAppImportIdentityFields({ errors: AppSetupErrors; update: Update; }) { + const { t } = useTranslation(); return (
- + update("displayName", e.target.value)} /> - + update("slug", e.target.value)} /> - +
@@ -80,11 +82,14 @@ export function GitHubAppImportSecretFields({ errors: AppSetupErrors; update: Update; }) { + const { t } = useTranslation(); + // Keys are the value/error field names; only the labels are copy. Resolved + // here rather than at module scope so they follow a locale switch. const labels = { - appId: "App ID", - clientId: "Client ID", - clientSecret: "Client secret", - webhookSecret: "Webhook secret", + appId: t("github:appId"), + clientId: t("github:clientId"), + clientSecret: t("github:clientSecret"), + webhookSecret: t("github:webhookSecret"), } as const; return (
@@ -100,7 +105,7 @@ export function GitHubAppImportSecretFields({ ))}
- +