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- {__( - "You do not have permission to enroll devices in any organization.", - )} + {t("deviceEnrollment.unavailable.description")}
{__("Device enrollment")}
-{__("Setup")}
+{t("deviceEnrollment.title")}
+{t("deviceEnrollment.setup")}
- {sprintf(__("Step %s of %s"), activeStepIndex, steps.length)} + {t("deviceEnrollment.stepProgress", { current: activeStepIndex, total: steps.length })}
- {__( - "Probo collects the following device metadata for inventory and posture reporting:", - )} + {t("deviceEnrollment.intro.description")}
- {__( - "Pick which organization will own and manage this device.", - )} + {t("deviceEnrollment.organization.description")}
- {__( - "Open the desktop agent to finish setup, then keep this page open until enrollment is confirmed.", - )} + {t("deviceEnrollment.openAgent.description")}
- {__( - "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