feat(i18n): localize Settings → Integrations → GitHub connection and auth (#2155)
Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,29 +2,38 @@ import { IconBrandGithub, IconKey, IconTerminal2 } from "@tabler/icons-react";
|
||||
import { Label } from "@kandev/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@kandev/ui/radio-group";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export type GitHubAutomationMethod = "pat" | "cli" | "app";
|
||||
|
||||
const methods = [
|
||||
// `value` is the wire enum the connection form switches on — never translated.
|
||||
// The copy travels as catalog keys resolved at render: a `t()` call here would
|
||||
// be module scope and freeze at the boot locale (see docs/i18n.md). Every entry
|
||||
// carries both keys, so `t()` never receives `string | undefined`.
|
||||
type AuthMethodOption = {
|
||||
value: GitHubAutomationMethod;
|
||||
labelKey: string;
|
||||
descriptionKey: string;
|
||||
icon: typeof IconTerminal2;
|
||||
};
|
||||
|
||||
const methods: AuthMethodOption[] = [
|
||||
{
|
||||
value: "cli" as const,
|
||||
label: "GitHub CLI account",
|
||||
description:
|
||||
"Resolved from one named host account when needed. Managed tasks receive a scoped brokered identity; host Git is not inherited unless selected below.",
|
||||
value: "cli",
|
||||
labelKey: "github:githubCliAccount",
|
||||
descriptionKey: "github:resolvedFromOneNamedHostAccount",
|
||||
icon: IconTerminal2,
|
||||
},
|
||||
{
|
||||
value: "pat" as const,
|
||||
label: "Personal access token",
|
||||
description:
|
||||
"Stored encrypted by Kandev. Workspace automation and managed task GitHub HTTPS/gh act as your account.",
|
||||
value: "pat",
|
||||
labelKey: "github:personalAccessToken",
|
||||
descriptionKey: "github:storedEncryptedByKandevWorkspaceAutomation",
|
||||
icon: IconKey,
|
||||
},
|
||||
{
|
||||
value: "app" as const,
|
||||
label: "GitHub App",
|
||||
description:
|
||||
"Stored App credentials mint short-lived installation tokens. Managed tasks receive a scoped brokered App identity for allowed repositories.",
|
||||
value: "app",
|
||||
labelKey: "github:githubApp",
|
||||
descriptionKey: "github:storedAppCredentialsMintShortLived",
|
||||
icon: IconBrandGithub,
|
||||
},
|
||||
];
|
||||
@@ -36,12 +45,13 @@ export function GitHubAuthMethodList({
|
||||
value: GitHubAutomationMethod;
|
||||
onChange: (value: GitHubAutomationMethod) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<RadioGroup
|
||||
value={value}
|
||||
onValueChange={(next) => onChange(next as GitHubAutomationMethod)}
|
||||
className="grid gap-2 sm:grid-cols-3"
|
||||
aria-label="Connection method"
|
||||
aria-label={t("github:connectionMethod")}
|
||||
>
|
||||
{methods.map((method) => {
|
||||
const Icon = method.icon;
|
||||
@@ -63,10 +73,10 @@ export function GitHubAuthMethodList({
|
||||
<span className="min-w-0 space-y-1">
|
||||
<span className="flex items-center gap-2 text-sm font-medium">
|
||||
<Icon className="h-4 w-4 shrink-0" />
|
||||
{method.label}
|
||||
{t(method.labelKey)}
|
||||
</span>
|
||||
<span className="block text-xs font-normal leading-5 text-muted-foreground">
|
||||
{method.description}
|
||||
{t(method.descriptionKey)}
|
||||
</span>
|
||||
</span>
|
||||
</Label>
|
||||
|
||||
Reference in New Issue
Block a user