diff --git a/apps/console/src/_locales/en-US.json b/apps/console/src/_locales/en-US.json index 97df7138e..51229e3bb 100644 --- a/apps/console/src/_locales/en-US.json +++ b/apps/console/src/_locales/en-US.json @@ -1170,7 +1170,7 @@ } } }, - "common": { "error": "Error", "success": "Success", "create": "Create" }, + "common": { "error": "Error", "success": "Success", "create": "Create", "actions": { "back": "Back", "close": "Close", "continue": "Continue", "copy": "Copy", "tryAgain": "Try again" }, "messages": { "copied": "Copied", "copiedToClipboard": "Copied to clipboard" } }, "mutation": { "messages": { "completed": "Operation completed successfully" }, "errors": { "commit": "Failed to commit this operation" } @@ -1331,10 +1331,10 @@ "membershipsDropdown": { "searchPlaceholder": "Search organizations...", "loading": "Loading organizations...", "addOrganization": "Add organization" }, "membershipsDropdownInvitingItem": { "title": "Check your email to accept the invitation" }, "membershipsDropdownMenu": { "pendingInvitations": "Pending invitations" }, - "sidebar": { "context": "Context", "tasks": "Tasks", "measures": "Measures", "risks": "Risks", "frameworks": "Frameworks", "people": "People", "thirdParties": "Third parties", "documents": "Documents", "assets": "Assets", "data": "Data", "audits": "Audits", "findings": "Findings", "obligations": "Obligations", "processingActivities": "Processing Activities", "statementsOfApplicability": "Statements of Applicability", "rightsRequests": "Rights Requests", "accessReviews": "Access Reviews", "compliancePage": "Compliance Page", "cookieBanners": "Cookie Banners", "settings": "Settings" }, + "sidebar": { "context": "Context", "tasks": "Tasks", "measures": "Measures", "risks": "Risks", "frameworks": "Frameworks", "people": "People", "thirdParties": "Third parties", "documents": "Documents", "assets": "Assets", "devices": "Devices", "data": "Data", "audits": "Audits", "findings": "Findings", "obligations": "Obligations", "processingActivities": "Processing Activities", "statementsOfApplicability": "Statements of Applicability", "rightsRequests": "Rights Requests", "accessReviews": "Access Reviews", "compliancePage": "Compliance Page", "cookieBanners": "Cookie Banners", "settings": "Settings" }, "viewerMembershipDropdown": { "errors": { "requestFailed": "Request failed", "cannotSignOut": "Cannot sign out" }, - "actions": { "apiKeys": "API Keys", "oauthTokens": "OAuth tokens", "mySignatures": "My Signatures", "help": "Help", "logout": "Logout" } + "actions": { "apiKeys": "API Keys", "oauthTokens": "OAuth tokens", "mySignatures": "My Signatures", "employeePortal": "Employee Portal", "help": "Help", "logout": "Logout" } }, "peoplePage": { "title": "People", "actions": { "add": "Add Person" } }, "personPage": { @@ -2461,6 +2461,11 @@ "magicLinkExpired": { "title": "Link Expired", "description": "This magic link has expired. Magic links are only valid for 15 minutes. Please request a new one." }, "magicLinkForm": { "errors": { "send": "Cannot send magic link" }, "messages": { "sent": "Magic link sent!" }, "fields": { "email": "Email" }, "sentDescription": "Magic link sent! Check your email and use the link to continue.", "actions": { "resend": "Resend Link", "resendIn": "Resend Link in {{count}}s", "send": "Send Magic Link" } }, "auth": { "actions": { "signIn": "Sign in" } }, + "authError": { "enterpriseAccountRequired": { "title": "Enterprise account required", "description": "Personal Google and Microsoft accounts cannot be used to sign in. Please use your work or school account instead." }, "emailNotVerified": { "title": "Email not verified", "description": "Your email address is not verified with the identity provider. Please verify it, then try signing in again." }, "signInSessionExpired": { "title": "Sign-in session expired", "description": "This sign-in attempt is no longer valid. Please start again from the sign-in page." }, "magicLinkExpired": { "title": "Link Expired", "description": "This magic link has expired. Magic links are only valid for 15 minutes. Please request a new one." }, "magicLinkAlreadyUsed": { "title": "Link Already Used", "description": "This magic link has already been used. Please request a new one." }, "invalidLink": { "title": "Invalid link", "description": "This magic link is invalid. Please request a new one." }, "default": { "title": "Authentication failed", "description": "We could not complete your sign-in. Please try again." } }, + "accessReviewSource": { "documentation": "Documentation", "regions": { "label": "Region", "placeholder": "Select a region", "unitedStates": "United States", "europe": "Europe" } }, + "devices": { "title": "Devices", "description": "Manage computers enrolled with the Probo posture agent.", "empty": "No devices enrolled yet", "actions": { "add": "Add device", "new": "New device", "reassign": "Re-assign", "revoke": "Revoke" }, "fields": { "organization": "Organization", "hostname": "Hostname", "owner": "Owner", "state": "State", "platform": "Platform", "osVersion": "OS version", "hardwareUuid": "Hardware UUID", "serialNumber": "Serial number", "agentVersion": "Agent version", "enrolledAt": "Enrolled at", "lastSeen": "Last seen" }, "values": { "pending": "(pending)", "never": "Never", "unassigned": "Unassigned" }, "messages": { "ownerUpdated": "Device owner updated", "revoked": "Device revoked" }, "errors": { "create": "Failed to create device", "reassign": "Failed to re-assign device", "revoke": "Failed to revoke device" }, "confirmations": { "revoke": "Revoke device \"{{hostname}}\"? The agent on the device will stop reporting and must be re-enrolled." }, "postures": { "title": "Posture", "navigation": "Postures", "summaryHelp": "How posture summary is calculated", "summaryDescription": "Shown as pass / fail / total.", "empty": "No posture checks recorded", "columns": { "check": "Check", "status": "Status", "observedAt": "Observed at" }, "status": { "pass": "Pass", "fail": "Fail", "unknown": "Unknown", "notApplicable": "Not applicable" }, "checks": { "diskEncryption": "Disk encryption", "screenLock": "Screen lock", "firewallEnabled": "Firewall enabled", "timeSync": "Time sync", "osVersion": "OS version", "autoUpdate": "Auto update", "passwordPolicy": "Password policy", "remoteLogin": "Remote login", "malwareProtection": "Malware protection" } } }, + "employeeDevices": { "title": "Your devices" }, + "deviceEnrollment": { "pageTitle": "Enroll device", "title": "Device enrollment", "setup": "Setup", "stepProgress": "Step {{current}} of {{total}}", "steps": { "privacy": { "title": "Privacy", "description": "Review collected data" }, "organization": { "title": "Organization", "description": "Choose destination workspace" }, "enroll": { "title": "Open and wait", "description": "Finish setup in the desktop agent" } }, "unavailable": { "title": "Enrollment unavailable", "description": "You do not have permission to enroll devices in any organization." }, "intro": { "title": "Before you start", "description": "Probo collects the following device metadata for inventory and posture reporting:" }, "privacy": { "identity": "Device identity: hardware UUID, hostname, and serial number (when available).", "systemDetails": "System details: platform, OS version, and Probo agent version.", "activitySignals": "Activity signals: enrollment time, heartbeats, and posture check results." }, "organization": { "title": "Choose organization", "description": "Pick which organization will own and manage this device." }, "openAgent": { "title": "Open the Probo agent", "description": "Open the desktop agent to finish setup, then keep this page open until enrollment is confirmed." }, "actions": { "backToOrganizations": "Back to organizations", "enrollNew": "Enroll new device", "openAgent": "Open Probo agent", "preparing": "Preparing…" }, "status": { "enrolledWithHostname": "{{hostname}} is enrolled.", "enrolled": "This device is enrolled.", "closeWindow": "You can close this window.", "waitingForCheckIn": "Waiting for the agent's first check-in…", "timedOut": "We haven't heard from the agent yet. Make sure the desktop agent is installed and running, then try again." }, "manual": { "cannotEnroll": "Can't enroll new device?", "tryCreating": "Try creating it manually", "title": "Manual enrollment", "creating": "Creating device…" }, "token": { "title": "Enrollment token generated", "description": "Share this enrollment token only with the device owner through a secure channel. It can be used once and expires after seven days.", "manualInstall": "Manual install (CLI / MDM)", "installUnix": "Install on macOS or Linux (run from a shell with sudo access)", "installWindows": "Install on Windows (run from an elevated PowerShell session)", "securityNotice": "The token is passed as a CLI flag (not via curl-piped-to-shell or sudo env vars). Once installed, the agent self-updates from GitHub Releases with cosign signature verification." }, "messages": { "created": "Device created. Copy the enrollment token now — it will not be shown again." }, "errors": { "copyToClipboard": "Failed to copy to clipboard" } }, "thirdPartyRiskAssessmentRow": { "expired": "Expired", "notes": "Notes" diff --git a/apps/console/src/pages/iam/auth/AuthErrorPage.tsx b/apps/console/src/pages/iam/auth/AuthErrorPage.tsx index 1366a0bd0..2200a9f9f 100644 --- a/apps/console/src/pages/iam/auth/AuthErrorPage.tsx +++ b/apps/console/src/pages/iam/auth/AuthErrorPage.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button } from "@probo/ui"; import { useSearchParams } from "react-router"; @@ -29,63 +29,49 @@ type AuthErrorContent = { }; function useAuthErrorContent(code: string | null): AuthErrorContent { - const { __ } = useTranslate(); + const { t } = useTranslation(); switch (code) { case "personal_account_not_allowed": return { - title: __("Enterprise account required"), - description: __( - "Personal Google and Microsoft accounts cannot be used to sign in. Please use your work or school account instead.", - ), + title: t("authError.enterpriseAccountRequired.title"), + description: t("authError.enterpriseAccountRequired.description"), }; case "email_not_verified": return { - title: __("Email not verified"), - description: __( - "Your email address is not verified with the identity provider. Please verify it, then try signing in again.", - ), + title: t("authError.emailNotVerified.title"), + description: t("authError.emailNotVerified.description"), }; case "invalid_state": return { - title: __("Sign-in session expired"), - description: __( - "This sign-in attempt is no longer valid. Please start again from the sign-in page.", - ), + title: t("authError.signInSessionExpired.title"), + description: t("authError.signInSessionExpired.description"), }; case "magic_link_expired": return { - title: __("Link Expired"), - description: __( - "This magic link has expired. Magic links are only valid for 15 minutes. Please request a new one.", - ), + title: t("authError.magicLinkExpired.title"), + description: t("authError.magicLinkExpired.description"), }; case "magic_link_already_used": return { - title: __("Link Already Used"), - description: __( - "This magic link has already been used. Please request a new one.", - ), + title: t("authError.magicLinkAlreadyUsed.title"), + description: t("authError.magicLinkAlreadyUsed.description"), }; case "magic_link_invalid": return { - title: __("Invalid link"), - description: __( - "This magic link is invalid. Please request a new one.", - ), + title: t("authError.invalidLink.title"), + description: t("authError.invalidLink.description"), }; default: return { - title: __("Authentication failed"), - description: __( - "We could not complete your sign-in. Please try again.", - ), + title: t("authError.default.title"), + description: t("authError.default.description"), }; } } export default function AuthErrorPage() { - const { __ } = useTranslate(); + const { t } = useTranslation(); const [searchParams] = useSearchParams(); const content = useAuthErrorContent(searchParams.get("error")); @@ -98,7 +84,7 @@ export default function AuthErrorPage() {

{content.description}

); diff --git a/apps/console/src/pages/iam/enroll/EnrollDevicePage.tsx b/apps/console/src/pages/iam/enroll/EnrollDevicePage.tsx index 05d7bab18..b72e2b414 100644 --- a/apps/console/src/pages/iam/enroll/EnrollDevicePage.tsx +++ b/apps/console/src/pages/iam/enroll/EnrollDevicePage.tsx @@ -19,9 +19,8 @@ // SOFTWARE. import { LaptopIcon } from "@phosphor-icons/react"; -import { sprintf } from "@probo/helpers"; import { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button, Card } from "@probo/ui"; import { useCallback, useMemo, useState } from "react"; import { type PreloadedQuery, usePreloadedQuery } from "react-relay"; @@ -65,8 +64,8 @@ interface EnrollDevicePageProps { } export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) { - const { __ } = useTranslate(); - usePageTitle(__("Enroll device")); + const { t } = useTranslation(); + usePageTitle(t("deviceEnrollment.pageTitle")); const { viewer } = usePreloadedQuery( enrollDevicePageQuery, @@ -125,18 +124,18 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) { const steps = [ { key: "intro", - title: __("Privacy"), - description: __("Review collected data"), + title: t("deviceEnrollment.steps.privacy.title"), + description: t("deviceEnrollment.steps.privacy.description"), }, { key: "organization", - title: __("Organization"), - description: __("Choose destination workspace"), + title: t("devices.fields.organization"), + description: t("deviceEnrollment.steps.organization.description"), }, { key: "enroll", - title: __("Open and wait"), - description: __("Finish setup in the desktop agent"), + title: t("deviceEnrollment.steps.enroll.title"), + description: t("deviceEnrollment.steps.enroll.description"), }, ] as const; @@ -147,16 +146,14 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) {

- {__("Enrollment unavailable")} + {t("deviceEnrollment.unavailable.title")}

- {__( - "You do not have permission to enroll devices in any organization.", - )} + {t("deviceEnrollment.unavailable.description")}

) @@ -169,8 +166,8 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) {
-

{__("Device enrollment")}

-

{__("Setup")}

+

{t("deviceEnrollment.title")}

+

{t("deviceEnrollment.setup")}

@@ -211,7 +208,7 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) {

- {sprintf(__("Step %s of %s"), activeStepIndex, steps.length)} + {t("deviceEnrollment.stepProgress", { current: activeStepIndex, total: steps.length })}

{steps.map((item, index) => ( @@ -231,21 +228,19 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) { {step === "intro" && (
-

{__("Before you start")}

+

{t("deviceEnrollment.intro.title")}

- {__( - "Probo collects the following device metadata for inventory and posture reporting:", - )} + {t("deviceEnrollment.intro.description")}

    -
  • {__("Device identity: hardware UUID, hostname, and serial number (when available).")}
  • -
  • {__("System details: platform, OS version, and Probo agent version.")}
  • -
  • {__("Activity signals: enrollment time, heartbeats, and posture check results.")}
  • +
  • {t("deviceEnrollment.privacy.identity")}
  • +
  • {t("deviceEnrollment.privacy.systemDetails")}
  • +
  • {t("deviceEnrollment.privacy.activitySignals")}
@@ -254,11 +249,9 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) { {step === "organization" && (
-

{__("Choose organization")}

+

{t("deviceEnrollment.organization.title")}

- {__( - "Pick which organization will own and manage this device.", - )} + {t("deviceEnrollment.organization.description")}

setStep("enroll")} disabled={selectedOrganizationId == null} > - {__("Continue")} + {t("common.actions.continue")}
@@ -286,11 +279,9 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) { {step === "enroll" && (
-

{__("Open the Probo agent")}

+

{t("deviceEnrollment.openAgent.title")}

- {__( - "Open the desktop agent to finish setup, then keep this page open until enrollment is confirmed.", - )} + {t("deviceEnrollment.openAgent.description")}

@@ -304,7 +295,7 @@ export function EnrollDevicePage({ queryRef }: EnrollDevicePageProps) { {!isEnrollmentComplete && (
)} diff --git a/apps/console/src/pages/iam/enroll/_components/EnrollOrganizationPicker.tsx b/apps/console/src/pages/iam/enroll/_components/EnrollOrganizationPicker.tsx index 61d298c81..50ce748cd 100644 --- a/apps/console/src/pages/iam/enroll/_components/EnrollOrganizationPicker.tsx +++ b/apps/console/src/pages/iam/enroll/_components/EnrollOrganizationPicker.tsx @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; interface OrganizationOption { id: string; @@ -38,12 +38,12 @@ export function EnrollOrganizationPicker( onChange, }: EnrollOrganizationPickerProps, ) { - const { __ } = useTranslate(); + const { t } = useTranslation(); return (
); diff --git a/apps/console/src/pages/organizations/access-reviews/dialogs/_components/ConnectorDocumentationLink.tsx b/apps/console/src/pages/organizations/access-reviews/dialogs/_components/ConnectorDocumentationLink.tsx index 4f22c67f0..a5a1afc3b 100644 --- a/apps/console/src/pages/organizations/access-reviews/dialogs/_components/ConnectorDocumentationLink.tsx +++ b/apps/console/src/pages/organizations/access-reviews/dialogs/_components/ConnectorDocumentationLink.tsx @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button, IconArrowLink } from "@probo/ui"; type Props = { @@ -33,7 +33,7 @@ type Props = { // the provider has no documentation URL. Shared by the provider card and the // connect dialogs so the URL/label/target markup lives in one place. export function ConnectorDocumentationLink({ url, variant = "link" }: Props) { - const { __ } = useTranslate(); + const { t } = useTranslation(); if (!url) { return null; @@ -45,7 +45,7 @@ export function ConnectorDocumentationLink({ url, variant = "link" }: Props) { return ( @@ -59,7 +59,7 @@ export function ConnectorDocumentationLink({ url, variant = "link" }: Props) { rel="noopener noreferrer" className="inline-flex items-center gap-1 text-xs text-txt-tertiary underline hover:no-underline" > - {__("Documentation")} + {t("accessReviewSource.documentation")} ); diff --git a/apps/console/src/pages/organizations/devices/DeviceLayout.tsx b/apps/console/src/pages/organizations/devices/DeviceLayout.tsx index 2f78bd445..a75648462 100644 --- a/apps/console/src/pages/organizations/devices/DeviceLayout.tsx +++ b/apps/console/src/pages/organizations/devices/DeviceLayout.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Breadcrumb, Button, @@ -67,9 +67,9 @@ interface DeviceLayoutProps { } export function DeviceLayout({ queryRef }: DeviceLayoutProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const organizationId = useOrganizationId(); - const pendingLabel = __("(pending)"); + const pendingLabel = t("devices.values.pending"); const { device, organization } = usePreloadedQuery( deviceLayoutQuery, @@ -96,7 +96,7 @@ export function DeviceLayout({ queryRef }: DeviceLayoutProps) { - {__("Revoke")} + {t("devices.actions.revoke")} )} @@ -124,7 +124,7 @@ export function DeviceLayout({ queryRef }: DeviceLayoutProps) { - {__("Postures")} + {t("devices.postures.navigation")} diff --git a/apps/console/src/pages/organizations/devices/DevicesPage.tsx b/apps/console/src/pages/organizations/devices/DevicesPage.tsx index b53bf24bc..86b0acf39 100644 --- a/apps/console/src/pages/organizations/devices/DevicesPage.tsx +++ b/apps/console/src/pages/organizations/devices/DevicesPage.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button, IconPlusLarge, PageHeader, Tbody, Th, Thead, Tr } from "@probo/ui"; import type { ComponentProps } from "react"; import { @@ -89,10 +89,10 @@ interface DevicesPageProps { } export function DevicesPage({ queryRef }: DevicesPageProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const organizationId = useOrganizationId(); - usePageTitle(__("Devices")); + usePageTitle(t("devices.title")); const { organization } = usePreloadedQuery( devicesPageQuery, @@ -112,10 +112,8 @@ export function DevicesPage({ queryRef }: DevicesPageProps) { return (
{organization.canCreateDevice && ( - + )} @@ -137,12 +135,12 @@ export function DevicesPage({ queryRef }: DevicesPageProps) { > - {__("Hostname")} - {__("Owner")} - {__("State")} - {__("Platform")} - {__("OS version")} - {__("Last seen")} + {t("devices.fields.hostname")} + {t("devices.fields.owner")} + {t("devices.fields.state")} + {t("devices.fields.platform")} + {t("devices.fields.osVersion")} + {t("devices.fields.lastSeen")} diff --git a/apps/console/src/pages/organizations/devices/_components/DeviceDetailsCard.tsx b/apps/console/src/pages/organizations/devices/_components/DeviceDetailsCard.tsx index 62d262808..dad069953 100644 --- a/apps/console/src/pages/organizations/devices/_components/DeviceDetailsCard.tsx +++ b/apps/console/src/pages/organizations/devices/_components/DeviceDetailsCard.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { formatDate } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Badge, Card } from "@probo/ui"; import type { ReactNode } from "react"; import { useFragment } from "react-relay"; @@ -48,52 +48,52 @@ const deviceFragment = graphql` export function DeviceDetailsCard(props: { deviceFragmentRef: DeviceDetailsCard_deviceFragment$key; }) { - const { __ } = useTranslate(); - const pendingLabel = __("(pending)"); + const { t } = useTranslation(); + const pendingLabel = t("devices.values.pending"); const device = useFragment(deviceFragment, props.deviceFragmentRef); return (
{device.state} } />
diff --git a/apps/console/src/pages/organizations/devices/_components/DeviceRow.tsx b/apps/console/src/pages/organizations/devices/_components/DeviceRow.tsx index 61c443245..d84d44f05 100644 --- a/apps/console/src/pages/organizations/devices/_components/DeviceRow.tsx +++ b/apps/console/src/pages/organizations/devices/_components/DeviceRow.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { formatDate } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { ActionDropdown, Badge, @@ -67,10 +67,10 @@ interface DeviceRowProps { } export function DeviceRow({ canAssignDevice, canRevoke, fKey }: DeviceRowProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const organizationId = useOrganizationId(); const reassignDialogRef = useDialogRef(); - const pendingLabel = __("(pending)"); + const pendingLabel = t("devices.values.pending"); const device = useFragment(deviceRowFragment, fKey); @@ -89,13 +89,13 @@ export function DeviceRow({ canAssignDevice, canRevoke, fKey }: DeviceRowProps) /> {displayValue(device.hostname, pendingLabel)} - {device.owner?.fullName ?? __("Unassigned")} + {device.owner?.fullName ?? t("devices.values.unassigned")} {device.state} {displayValue(device.platform, pendingLabel)} {displayValue(device.osVersion, pendingLabel)} - {device.lastSeenAt ? formatDate(device.lastSeenAt) : __("Never")} + {device.lastSeenAt ? formatDate(device.lastSeenAt) : t("devices.values.never")} {summary.pass} {" / "} @@ -113,7 +113,7 @@ export function DeviceRow({ canAssignDevice, canRevoke, fKey }: DeviceRowProps) icon={IconUser} onClick={() => reassignDialogRef.current?.open()} > - {__("Re-assign")} + {t("devices.actions.reassign")} )} {canRevoke && ( @@ -124,7 +124,7 @@ export function DeviceRow({ canAssignDevice, canRevoke, fKey }: DeviceRowProps) variant="danger" icon={IconTrashCan} > - {__("Revoke")} + {t("devices.actions.revoke")} )} diff --git a/apps/console/src/pages/organizations/devices/_components/PostureColumnHeader.tsx b/apps/console/src/pages/organizations/devices/_components/PostureColumnHeader.tsx index 0107f6fc3..0753d1ac3 100644 --- a/apps/console/src/pages/organizations/devices/_components/PostureColumnHeader.tsx +++ b/apps/console/src/pages/organizations/devices/_components/PostureColumnHeader.tsx @@ -18,22 +18,22 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { IconCircleInfo } from "@probo/ui"; import * as Popover from "@radix-ui/react-popover"; export function PostureColumnHeader() { - const { __ } = useTranslate(); + const { t } = useTranslation(); return ( - {__("Posture")} + {t("devices.postures.title")} @@ -45,9 +45,7 @@ export function PostureColumnHeader() { align="start" >

- {__( - "Shown as pass / fail / total.", - )} + {t("devices.postures.summaryDescription")}

diff --git a/apps/console/src/pages/organizations/devices/_lib/useRevokeDevice.ts b/apps/console/src/pages/organizations/devices/_lib/useRevokeDevice.ts index 1a2b1ebd2..6beca9103 100644 --- a/apps/console/src/pages/organizations/devices/_lib/useRevokeDevice.ts +++ b/apps/console/src/pages/organizations/devices/_lib/useRevokeDevice.ts @@ -18,8 +18,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { formatError, sprintf } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { formatError } from "@probo/helpers"; +import { useTranslation } from "react-i18next"; import { useConfirm, useToast } from "@probo/ui"; import { useCallback } from "react"; import { useMutation } from "react-relay"; @@ -48,10 +48,10 @@ interface RevokeDeviceInput { } export function useRevokeDevice() { - const { __ } = useTranslate(); + const { t } = useTranslation(); const { toast } = useToast(); const confirm = useConfirm(); - const pendingLabel = __("(pending)"); + const pendingLabel = t("devices.values.pending"); const [revokeDevice, isRevoking] = useMutation( revokeDeviceMutation, @@ -67,14 +67,14 @@ export function useRevokeDevice() { onCompleted(_, errors) { if (errors?.length) { toast({ - title: __("Error"), + title: t("common.error"), description: errors[0].message, variant: "error", }); } else { toast({ - title: __("Success"), - description: __("Device revoked"), + title: t("common.success"), + description: t("devices.messages.revoked"), variant: "success", }); } @@ -82,9 +82,9 @@ export function useRevokeDevice() { }, onError(error) { toast({ - title: __("Error"), + title: t("common.error"), description: formatError( - __("Failed to revoke device"), + t("devices.errors.revoke"), error, ), variant: "error", @@ -94,18 +94,13 @@ export function useRevokeDevice() { }); }), { - message: sprintf( - __( - "Revoke device \"%s\"? The agent on the device will stop reporting and must be re-enrolled.", - ), - displayValue(device.hostname, pendingLabel), - ), + message: t("devices.confirmations.revoke", { hostname: displayValue(device.hostname, pendingLabel) }), variant: "danger", - label: __("Revoke"), + label: t("devices.actions.revoke"), }, ); }, - [__, confirm, pendingLabel, revokeDevice, toast], + [t, confirm, pendingLabel, revokeDevice, toast], ); return [confirmRevoke, isRevoking] as const; diff --git a/apps/console/src/pages/organizations/devices/dialogs/CreateDeviceDialog.tsx b/apps/console/src/pages/organizations/devices/dialogs/CreateDeviceDialog.tsx index a802c85ab..c33947e8b 100644 --- a/apps/console/src/pages/organizations/devices/dialogs/CreateDeviceDialog.tsx +++ b/apps/console/src/pages/organizations/devices/dialogs/CreateDeviceDialog.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { formatError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Breadcrumb, Button, @@ -67,7 +67,7 @@ export function CreateDeviceDialog({ organizationId, onCreated, }: Props) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const { toast } = useToast(); const dialogRef = useDialogRef(); const [enrollment, setEnrollment] = useState<{ @@ -115,7 +115,7 @@ export function CreateDeviceDialog({ onCompleted(response, errors) { if (errors?.length) { toast({ - title: __("Error"), + title: t("common.error"), description: errors[0].message, variant: "error", }); @@ -127,18 +127,16 @@ export function CreateDeviceDialog({ serverUrl: response.createDevice.serverUrl, }); toast({ - title: __("Success"), - description: __( - "Device created. Copy the enrollment token now — it will not be shown again.", - ), + title: t("common.success"), + description: t("deviceEnrollment.messages.created"), variant: "success", }); }, onError(error) { toast({ - title: __("Error"), + title: t("common.error"), description: formatError( - __("Failed to create device"), + t("devices.errors.create"), error, ), variant: "error", @@ -153,7 +151,7 @@ export function CreateDeviceDialog({ trigger={children} onClose={handleClose} closable={!isCreating} - title={} + title={} >
void onSubmit(e)} className="space-y-4"> @@ -169,7 +167,7 @@ export function CreateDeviceDialog({ organizationId={organizationId} control={control} name="ownerId" - label={__("Owner")} + label={t("devices.fields.owner")} optional /> )} @@ -181,14 +179,14 @@ export function CreateDeviceDialog({ type="button" onClick={closeDialog} > - {__("Close")} + {t("common.actions.close")} ) : ( )} diff --git a/apps/console/src/pages/organizations/devices/dialogs/ReassignDeviceDialog.tsx b/apps/console/src/pages/organizations/devices/dialogs/ReassignDeviceDialog.tsx index 5454d58e8..034bcf1f1 100644 --- a/apps/console/src/pages/organizations/devices/dialogs/ReassignDeviceDialog.tsx +++ b/apps/console/src/pages/organizations/devices/dialogs/ReassignDeviceDialog.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { formatError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Breadcrumb, Button, @@ -77,7 +77,7 @@ export function ReassignDeviceDialog({ organizationId, ref: refProps, }: ReassignDeviceDialogProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const { toast } = useToast(); const dialogRef = useDialogRef(); const ref = refProps ?? dialogRef; @@ -121,7 +121,7 @@ export function ReassignDeviceDialog({ onCompleted(_, errors) { if (errors?.length) { toast({ - title: __("Error"), + title: t("common.error"), description: errors[0].message, variant: "error", }); @@ -129,8 +129,8 @@ export function ReassignDeviceDialog({ } toast({ - title: __("Success"), - description: __("Device owner updated"), + title: t("common.success"), + description: t("devices.messages.ownerUpdated"), variant: "success", }); handleClose(); @@ -138,9 +138,9 @@ export function ReassignDeviceDialog({ }, onError(error) { toast({ - title: __("Error"), + title: t("common.error"), description: formatError( - __("Failed to re-assign device"), + t("devices.errors.reassign"), error, ), variant: "error", @@ -154,7 +154,7 @@ export function ReassignDeviceDialog({ ref={ref} onClose={handleClose} onOpenChange={setOpen} - title={} + title={} > void handleSubmit(onSubmit)(e)} className="space-y-4"> @@ -163,14 +163,14 @@ export function ReassignDeviceDialog({ organizationId={organizationId} control={control} name="ownerId" - label={__("Owner")} + label={t("devices.fields.owner")} optional /> )} diff --git a/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureList.tsx b/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureList.tsx index a1f8ca2f6..9cf887a71 100644 --- a/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureList.tsx +++ b/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureList.tsx @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Table, Tbody, Td, Th, Thead, Tr } from "@probo/ui"; import { useFragment } from "react-relay"; import { graphql } from "relay-runtime"; @@ -41,23 +41,23 @@ interface DevicePostureListProps { } export function DevicePostureList({ deviceFragmentRef }: DevicePostureListProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const device = useFragment(deviceFragment, deviceFragmentRef); return ( - - - + + + {device.latestPostures.length === 0 && ( )} diff --git a/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureListItem.tsx b/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureListItem.tsx index 24a3d8d4b..a065e35db 100644 --- a/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureListItem.tsx +++ b/apps/console/src/pages/organizations/devices/postures/_components/DevicePostureListItem.tsx @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Badge, Td, Tr } from "@probo/ui"; import { useFragment } from "react-relay"; import { graphql } from "relay-runtime"; @@ -42,19 +42,19 @@ interface DevicePostureListItemProps { } export function DevicePostureListItem({ postureKey }: DevicePostureListItemProps) { - const { __, dateTimeFormat } = useTranslate(); + const { i18n, t } = useTranslation(); const posture = useFragment(postureFragment, postureKey); return ( - + ); diff --git a/apps/console/src/pages/organizations/devices/postures/_lib/getPostureCheckLabel.ts b/apps/console/src/pages/organizations/devices/postures/_lib/getPostureCheckLabel.ts index 7460191c5..8bee97e24 100644 --- a/apps/console/src/pages/organizations/devices/postures/_lib/getPostureCheckLabel.ts +++ b/apps/console/src/pages/organizations/devices/postures/_lib/getPostureCheckLabel.ts @@ -18,21 +18,21 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -type Translator = (s: string) => string; +type Translator = (key: string) => string; const checkKeyLabels: Record = { - DISK_ENCRYPTION: "Disk encryption", - SCREEN_LOCK: "Screen lock", - FIREWALL_ENABLED: "Firewall enabled", - TIME_SYNC: "Time sync", - OS_VERSION: "OS version", - AUTO_UPDATE: "Auto update", - PASSWORD_POLICY: "Password policy", - REMOTE_LOGIN: "Remote login", - MALWARE_PROTECTION: "Malware protection", + DISK_ENCRYPTION: "devices.postures.checks.diskEncryption", + SCREEN_LOCK: "devices.postures.checks.screenLock", + FIREWALL_ENABLED: "devices.postures.checks.firewallEnabled", + TIME_SYNC: "devices.postures.checks.timeSync", + OS_VERSION: "devices.postures.checks.osVersion", + AUTO_UPDATE: "devices.postures.checks.autoUpdate", + PASSWORD_POLICY: "devices.postures.checks.passwordPolicy", + REMOTE_LOGIN: "devices.postures.checks.remoteLogin", + MALWARE_PROTECTION: "devices.postures.checks.malwareProtection", }; -export function getPostureCheckLabel(__: Translator, checkKey: string) { +export function getPostureCheckLabel(t: Translator, checkKey: string) { const label = checkKeyLabels[checkKey]; - return label ? __(label) : checkKey; + return label ? t(label) : checkKey; } diff --git a/apps/console/src/pages/organizations/devices/postures/_lib/getPostureStatusLabel.ts b/apps/console/src/pages/organizations/devices/postures/_lib/getPostureStatusLabel.ts index b41765d1c..8f71fff30 100644 --- a/apps/console/src/pages/organizations/devices/postures/_lib/getPostureStatusLabel.ts +++ b/apps/console/src/pages/organizations/devices/postures/_lib/getPostureStatusLabel.ts @@ -18,16 +18,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -type Translator = (s: string) => string; +type Translator = (key: string) => string; const statusLabels: Record = { - PASS: "Pass", - FAIL: "Fail", - UNKNOWN: "Unknown", - NOT_APPLICABLE: "Not applicable", + PASS: "devices.postures.status.pass", + FAIL: "devices.postures.status.fail", + UNKNOWN: "devices.postures.status.unknown", + NOT_APPLICABLE: "devices.postures.status.notApplicable", }; -export function getPostureStatusLabel(__: Translator, status: string) { +export function getPostureStatusLabel(t: Translator, status: string) { const label = statusLabels[status]; - return label ? __(label) : status; + return label ? t(label) : status; } diff --git a/apps/console/src/pages/organizations/employee/EmployeeDevicesPage.tsx b/apps/console/src/pages/organizations/employee/EmployeeDevicesPage.tsx index f7e9e899c..6c30fe74d 100644 --- a/apps/console/src/pages/organizations/employee/EmployeeDevicesPage.tsx +++ b/apps/console/src/pages/organizations/employee/EmployeeDevicesPage.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { usePageTitle } from "@probo/hooks"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button, Card, IconPlusLarge, Tbody, Th, Thead, Tr } from "@probo/ui"; import { useTransition } from "react"; import { @@ -74,9 +74,9 @@ interface EmployeeDevicesPageProps { } export function EmployeeDevicesPage({ queryRef }: EmployeeDevicesPageProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); - usePageTitle(__("Devices")); + usePageTitle(t("devices.title")); const { viewer, organization } = usePreloadedQuery( employeeDevicesPageQuery, @@ -105,10 +105,10 @@ export function EmployeeDevicesPage({ queryRef }: EmployeeDevicesPageProps) { return (
-

{__("Your devices")}

+

{t("employeeDevices.title")}

{canEnrollDevice && ( )}
@@ -119,11 +119,11 @@ export function EmployeeDevicesPage({ queryRef }: EmployeeDevicesPageProps) {
{__("Check")}{__("Status")}{__("Observed at")}{t("devices.postures.columns.check")}{t("devices.postures.columns.status")}{t("devices.postures.columns.observedAt")}
- {__("No posture checks recorded")} + {t("devices.postures.empty")}
{getPostureCheckLabel(__, posture.checkKey)}{getPostureCheckLabel(t, posture.checkKey)} - {getPostureStatusLabel(__, posture.status)} + {getPostureStatusLabel(t, posture.status)} - {dateTimeFormat(posture.observedAt, { + {new Intl.DateTimeFormat(i18n.language, { year: "numeric", month: "short", day: "numeric", @@ -62,7 +62,7 @@ export function DevicePostureListItem({ postureKey }: DevicePostureListItemProps minute: "2-digit", second: "2-digit", hour12: false, - })} + }).format(posture.observedAt)}
- - - - - + + + + + @@ -139,7 +139,7 @@ export function EmployeeDevicesPage({ queryRef }: EmployeeDevicesPageProps) { : (

- {__("No devices enrolled yet")} + {t("devices.empty")}

)} diff --git a/apps/console/src/pages/organizations/employee/EmployeeTabsLayout.tsx b/apps/console/src/pages/organizations/employee/EmployeeTabsLayout.tsx index ac79d26b3..03e0303fe 100644 --- a/apps/console/src/pages/organizations/employee/EmployeeTabsLayout.tsx +++ b/apps/console/src/pages/organizations/employee/EmployeeTabsLayout.tsx @@ -36,7 +36,7 @@ export default function EmployeeTabsLayout() { {t("employeeTabsLayout.tabs.approvals")} - {__("Devices")} + {t("devices.title")} diff --git a/apps/console/src/pages/organizations/employee/_components/CreateDeviceForm.tsx b/apps/console/src/pages/organizations/employee/_components/CreateDeviceForm.tsx index e052629bc..f44729b67 100644 --- a/apps/console/src/pages/organizations/employee/_components/CreateDeviceForm.tsx +++ b/apps/console/src/pages/organizations/employee/_components/CreateDeviceForm.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { formatError } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button, Dialog, @@ -53,7 +53,7 @@ interface CreateDeviceFormProps { } export function CreateDeviceForm({ onDeviceCreated }: CreateDeviceFormProps) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const { toast } = useToast(); const dialogRef = useDialogRef(); @@ -90,7 +90,7 @@ export function CreateDeviceForm({ onDeviceCreated }: CreateDeviceFormProps) { onCompleted(response, errors) { if (errors?.length) { toast({ - title: __("Error"), + title: t("common.error"), description: errors[0].message, variant: "error", }); @@ -104,18 +104,16 @@ export function CreateDeviceForm({ onDeviceCreated }: CreateDeviceFormProps) { }); dialogRef.current?.open(); toast({ - title: __("Success"), - description: __( - "Device created. Copy the enrollment token now — it will not be shown again.", - ), + title: t("common.success"), + description: t("deviceEnrollment.messages.created"), variant: "success", }); }, onError(error) { toast({ - title: __("Error"), + title: t("common.error"), description: formatError( - __("Failed to create device"), + t("devices.errors.create"), error, ), variant: "error", @@ -135,7 +133,7 @@ export function CreateDeviceForm({ onDeviceCreated }: CreateDeviceFormProps) { return ( <>

- {__("Can't enroll new device?")} + {t("deviceEnrollment.manual.cannotEnroll")} {" "}

@@ -151,11 +149,11 @@ export function CreateDeviceForm({ onDeviceCreated }: CreateDeviceFormProps) { ref={dialogRef} onClose={handleClose} closable={!(isCreating && !enrollment)} - title={__("Manual enrollment")} + title={t("deviceEnrollment.manual.title")} > {isCreating && !enrollment - ?

{__("Creating device…")}

+ ?

{t("deviceEnrollment.manual.creating")}

: null} {enrollment ? ( @@ -170,7 +168,7 @@ export function CreateDeviceForm({ onDeviceCreated }: CreateDeviceFormProps) { ? (
) diff --git a/apps/console/src/pages/organizations/employee/_components/EmployeeDeviceListItem.tsx b/apps/console/src/pages/organizations/employee/_components/EmployeeDeviceListItem.tsx index 0a776a1e5..51f4f6c1d 100644 --- a/apps/console/src/pages/organizations/employee/_components/EmployeeDeviceListItem.tsx +++ b/apps/console/src/pages/organizations/employee/_components/EmployeeDeviceListItem.tsx @@ -19,7 +19,7 @@ // SOFTWARE. import { formatDate } from "@probo/helpers"; -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Badge, Td, Tr } from "@probo/ui"; import { useFragment } from "react-relay"; import { graphql } from "relay-runtime"; @@ -54,8 +54,8 @@ function stateVariant(state: string): "success" | "warning" | "info" { } export function EmployeeDeviceListItem({ deviceKey }: EmployeeDeviceListItemProps) { - const { __ } = useTranslate(); - const pendingLabel = __("(pending)"); + const { t } = useTranslation(); + const pendingLabel = t("devices.values.pending"); const device = useFragment(employeeDeviceListItemFragment, deviceKey); @@ -67,7 +67,7 @@ export function EmployeeDeviceListItem({ deviceKey }: EmployeeDeviceListItemProp
- + ); } diff --git a/apps/console/src/pages/organizations/employee/_components/EnrollmentInstructions.tsx b/apps/console/src/pages/organizations/employee/_components/EnrollmentInstructions.tsx index 719fda5b0..3743d4187 100644 --- a/apps/console/src/pages/organizations/employee/_components/EnrollmentInstructions.tsx +++ b/apps/console/src/pages/organizations/employee/_components/EnrollmentInstructions.tsx @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { useTranslate } from "@probo/i18n"; +import { useTranslation } from "react-i18next"; import { Button, Card, useToast } from "@probo/ui"; const RELEASE_BASE_URL @@ -32,7 +32,7 @@ interface EnrollmentInstructionsProps { export function EnrollmentInstructions( { enrollmentToken, serverUrl }: EnrollmentInstructionsProps, ) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const unixCommand = `# 1. Download and install the probo-agent binary OS=$(uname -s); ARCH=$(uname -m | sed 's/aarch64/arm64/; s/amd64/x86_64/') @@ -65,42 +65,34 @@ Remove-Item -Recurse -Force $zip, "$env:TEMP\\$name" return (
-

{__("Enrollment token generated")}

+

{t("deviceEnrollment.token.title")}

- {__( - "Share this enrollment token only with the device owner through a secure channel. It can be used once and expires after seven days.", - )} + {t("deviceEnrollment.token.description")}

- {__("Manual install (CLI / MDM)")} + {t("deviceEnrollment.token.manualInstall")}

- {__( - "Install on macOS or Linux (run from a shell with sudo access)", - )} + {t("deviceEnrollment.token.installUnix")}

- {__( - "Install on Windows (run from an elevated PowerShell session)", - )} + {t("deviceEnrollment.token.installWindows")}

- {__( - "The token is passed as a CLI flag (not via curl-piped-to-shell or sudo env vars). Once installed, the agent self-updates from GitHub Releases with cosign signature verification.", - )} + {t("deviceEnrollment.token.securityNotice")}

@@ -109,22 +101,22 @@ Remove-Item -Recurse -Force $zip, "$env:TEMP\\$name" } function CopyableCodeBlock({ code }: { code: string }) { - const { __ } = useTranslate(); + const { t } = useTranslation(); const { toast } = useToast(); const handleCopy = () => { navigator.clipboard.writeText(code).then( () => { toast({ - title: __("Copied"), - description: __("Copied to clipboard"), + title: t("common.messages.copied"), + description: t("common.messages.copiedToClipboard"), variant: "success", }); }, () => { toast({ - title: __("Error"), - description: __("Failed to copy to clipboard"), + title: t("common.error"), + description: t("deviceEnrollment.errors.copyToClipboard"), variant: "error", }); }, @@ -135,7 +127,7 @@ function CopyableCodeBlock({ code }: { code: string }) {
diff --git a/apps/console/src/pages/organizations/enroll/_components/EnrollDeviceButton.tsx b/apps/console/src/pages/organizations/enroll/_components/EnrollDeviceButton.tsx
index 830ff0112..9dd086dff 100644
--- a/apps/console/src/pages/organizations/enroll/_components/EnrollDeviceButton.tsx
+++ b/apps/console/src/pages/organizations/enroll/_components/EnrollDeviceButton.tsx
@@ -18,8 +18,8 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 // SOFTWARE.
 
-import { formatError, sprintf } from "@probo/helpers";
-import { useTranslate } from "@probo/i18n";
+import { formatError } from "@probo/helpers";
+import { useTranslation } from "react-i18next";
 import {
   Button,
   IconArrowsClockwise,
@@ -80,7 +80,7 @@ function EnrollDeviceButtonContent(
     onComplete,
   }: EnrollDeviceButtonProps,
 ) {
-  const { __ } = useTranslate();
+  const { t } = useTranslation();
   const { toast } = useToast();
   const environment = useRelayEnvironment();
   const matchingSession
@@ -212,7 +212,7 @@ function EnrollDeviceButtonContent(
       onCompleted(response, errors) {
         if (errors?.length) {
           toast({
-            title: __("Error"),
+            title: t("common.error"),
             description: errors[0].message,
             variant: "error",
           });
@@ -232,9 +232,9 @@ function EnrollDeviceButtonContent(
       },
       onError(error) {
         toast({
-          title: __("Error"),
+          title: t("common.error"),
           description: formatError(
-            __("Failed to create device"),
+            t("devices.errors.create"),
             error,
           ),
           variant: "error",
@@ -249,11 +249,11 @@ function EnrollDeviceButtonContent(
         
{deviceHostname - ? sprintf(__("%s is enrolled."), deviceHostname) - : __("This device is enrolled.")} + ? t("deviceEnrollment.status.enrolledWithHostname", { hostname: deviceHostname }) + : t("deviceEnrollment.status.enrolled")}

- {__("You can close this window.")} + {t("deviceEnrollment.status.closeWindow")}

); @@ -263,7 +263,7 @@ function EnrollDeviceButtonContent( return (
- {__("Waiting for the agent's first check-in…")} + {t("deviceEnrollment.status.waitingForCheckIn")}
); } @@ -272,9 +272,7 @@ function EnrollDeviceButtonContent(
{hasTimedOut && (

- {__( - "We haven't heard from the agent yet. Make sure the desktop agent is installed and running, then try again.", - )} + {t("deviceEnrollment.status.timedOut")}

)}
);
{__("Hostname")}{__("State")}{__("Platform")}{__("OS version")}{__("Last seen")}{t("devices.fields.hostname")}{t("devices.fields.state")}{t("devices.fields.platform")}{t("devices.fields.osVersion")}{t("devices.fields.lastSeen")}
{displayValue(device.platform, pendingLabel)} {displayValue(device.osVersion, pendingLabel)}{device.lastSeenAt ? formatDate(device.lastSeenAt) : __("Never")}{device.lastSeenAt ? formatDate(device.lastSeenAt) : t("devices.values.never")}