diff --git a/.changeset/built-in-localizations.md b/.changeset/built-in-localizations.md new file mode 100644 index 0000000..6b7c034 --- /dev/null +++ b/.changeset/built-in-localizations.md @@ -0,0 +1,5 @@ +--- +"@onkernel/managed-auth-react": minor +--- + +Ship built-in localizations for Danish, German, Spanish, Finnish, French, Italian, Norwegian Bokmål, Dutch, Polish, and Swedish, exported as `LOCALIZATIONS` with a `matchLocale` helper that picks one from the user's preferred languages. Error-code titles and descriptions and the "Powered by" footer are now part of `Localization` (`errorCodeMessages`, `poweredBy`), so they can be translated like the rest of the flow. `Localizer` now requires complete `mfaTypeLabels` and `errorCodeMessages` maps. diff --git a/packages/managed-auth-react/README.md b/packages/managed-auth-react/README.md index a350c25..e01a80e 100644 --- a/packages/managed-auth-react/README.md +++ b/packages/managed-auth-react/README.md @@ -216,7 +216,23 @@ Supported keys: `:hover`, `:focus`, `:focus-visible`, `:active`, `:disabled`, `: ## Localization -Pass a partial map; everything else falls back to English. +The package ships complete localizations for English (`en`), Danish (`da`), German (`de`), Spanish (`es`), Finnish (`fi`), French (`fr`), Italian (`it`), Norwegian Bokmål (`nb`), Dutch (`nl`), Polish (`pl`), and Swedish (`sv`). `matchLocale` takes language tags in order of preference, such as `navigator.languages`, and returns the first one with a built-in localization: + +```tsx +import { + KernelManagedAuth, + LOCALIZATIONS, + matchLocale, +} from "@onkernel/managed-auth-react"; + +const locale = matchLocale(navigator.languages) ?? "en"; + +; +``` + +Text that comes from the website being signed into, such as field labels and options, is shown as the website provides it. + +To write your own strings, pass a partial map; everything else falls back to English. ```tsx void` | no | — | Fires on `SUCCESS`. Payload: `{ profileName: string; domain: string }`. | | `onError` | `(p: AuthErrorPayload) => void` | no | — | Fires on `FAILED`, `CANCELED`, `EXPIRED`. Payload: `{ code?: string; message: string }`. | | `baseUrl` | `string` | no | `"https://api.onkernel.com"` | Override the Kernel API origin. Use `""` for same-origin proxying via your own rewrites. | diff --git a/packages/managed-auth-react/src/KernelManagedAuth.test.tsx b/packages/managed-auth-react/src/KernelManagedAuth.test.tsx index 4b9b66a..6512a4c 100644 --- a/packages/managed-auth-react/src/KernelManagedAuth.test.tsx +++ b/packages/managed-auth-react/src/KernelManagedAuth.test.tsx @@ -2,6 +2,7 @@ import { afterEach, describe, expect, test } from "bun:test"; import { createElement } from "react"; import { act, create, type ReactTestRenderer } from "react-test-renderer"; import { KernelManagedAuth } from "./KernelManagedAuth"; +import { LOCALIZATIONS } from "./localization/locales"; let renderer: ReactTestRenderer | null = null; @@ -128,3 +129,23 @@ describe("KernelManagedAuth human verification", () => { expect(continueButton().props.disabled).toBe(true); }); }); + +describe("KernelManagedAuth localization", () => { + test("renders the step and footer in the given localization", () => { + act(() => { + renderer = create( + createElement(KernelManagedAuth, { + sessionId: "session-id", + handoffCode: "handoff-code", + fetch: pendingExchangeFetch(), + localization: LOCALIZATIONS.sv, + }), + ); + }); + + const output = JSON.stringify(renderer!.toJSON()); + expect(output).toContain("Förbereder säker inloggning"); + expect(output).toContain("Drivs av"); + expect(output).not.toContain("Powered by"); + }); +}); diff --git a/packages/managed-auth-react/src/components/Shell.tsx b/packages/managed-auth-react/src/components/Shell.tsx index 799cb5d..f35d9c6 100644 --- a/packages/managed-auth-react/src/components/Shell.tsx +++ b/packages/managed-auth-react/src/components/Shell.tsx @@ -1,6 +1,7 @@ import type { CSSProperties, ReactNode } from "react"; import clsx from "clsx"; import { useSlot } from "../appearance/context"; +import { useLocalization } from "../localization/context"; import { variablesToStyle } from "../appearance/variables"; import type { Appearance, ColorScheme } from "../appearance/types"; import { KernelLogo } from "./KernelLogo"; @@ -18,6 +19,7 @@ function themeClass(theme: ColorScheme | undefined): string { export function Shell({ appearance, children }: ShellProps) { const slot = useSlot(); + const l = useLocalization(); const root = slot("root", clsx("kma-root", themeClass(appearance?.theme))); const shell = slot("shell", "kma-shell"); const card = slot("card", "kma-card"); @@ -37,7 +39,7 @@ export function Shell({ appearance, children }: ShellProps) {
{children}
{showPoweredBy && (
- Powered by + {l.poweredBy} { @@ -15,27 +19,34 @@ describe("errorDisplayForCode", () => { ]; for (const [code, title] of cases) { - const display = errorDisplayForCode(code); + const display = errorDisplayForCode(DEFAULT_LOCALIZATION, code); expect(display?.title).toBe(title); expect(display?.description?.toLowerCase()).not.toContain("reauth"); } }); test("does not infer TOTP secret availability", () => { - expect(errorDisplayForCode("totp_required")?.description).toBe( - "An authenticator code is required.", - ); + expect( + errorDisplayForCode(DEFAULT_LOCALIZATION, "totp_required")?.description, + ).toBe("An authenticator code is required."); }); test("uses customer-facing copy for additional input", () => { - expect(errorDisplayForCode("customer_input_required")?.description).toBe( - "Additional information is required before login can continue.", - ); + expect( + errorDisplayForCode(DEFAULT_LOCALIZATION, "customer_input_required") + ?.description, + ).toBe("Additional information is required before login can continue."); }); test("distinguishes a rejected authenticator code from invalid credentials", () => { - const display = errorDisplayForCode("totp_code_rejected"); - const invalidCredentials = errorDisplayForCode("credentials_invalid"); + const display = errorDisplayForCode( + DEFAULT_LOCALIZATION, + "totp_code_rejected", + ); + const invalidCredentials = errorDisplayForCode( + DEFAULT_LOCALIZATION, + "credentials_invalid", + ); expect(display?.title).toBe("Authenticator code rejected"); expect(display?.description).toContain("Try a fresh code"); @@ -48,7 +59,11 @@ describe("StepError description", () => { const timeout = "A CAPTCHA blocked the login. A person was asked to complete it but didn't finish in time. Please try again."; - function paragraphs(errorMessage?: string) { + function paragraphs( + errorMessage?: string, + errorCode = "captcha_blocked", + localization?: Localization, + ) { const hadWindow = "window" in globalThis; if (!hadWindow) { Object.assign(globalThis, { @@ -59,15 +74,18 @@ describe("StepError description", () => { let renderer!: ReturnType; act(() => { renderer = create( - createElement(StepError, { - targetDomain: "example.com", - errorCode: "captcha_blocked", - errorMessage, + createElement(LocalizationProvider, { + localization, + children: createElement(StepError, { + targetDomain: "example.com", + errorCode, + errorMessage, + }), }), ); }); const texts = renderer.root - .findAll((node) => node.type === "p") + .findAll((node) => node.type === "p" || node.type === "h1") .map((node) => node.children.join("")); const buttonCount = renderer.root.findAll( (node) => node.type === "button", @@ -90,4 +108,31 @@ describe("StepError description", () => { const { texts } = paragraphs(); expect(texts).toContain("A CAPTCHA blocked the login."); }); + + test("uses the localization's copy for a known error code", () => { + const { texts } = paragraphs( + undefined, + "credentials_invalid", + LOCALIZATIONS.de, + ); + expect(texts).toContain("Ungültige Zugangsdaten"); + expect(texts).toContain( + "Die Website hat den Benutzernamen oder das Passwort nicht akzeptiert.", + ); + }); + + test("keeps default copy for error codes a partial localization omits", () => { + const { texts } = paragraphs(undefined, "website_error", { + errorCodeMessages: { + credentials_invalid: { title: "Custom", description: "Custom" }, + }, + }); + expect(texts).toContain("Website error"); + }); + + test("falls back to the generic message for an unknown error code", () => { + const { texts } = paragraphs(undefined, "toString"); + expect(texts).toContain(DEFAULT_LOCALIZATION.errorTitle); + expect(texts).toContain(DEFAULT_LOCALIZATION.errorGenericMessage); + }); }); diff --git a/packages/managed-auth-react/src/components/StepError.tsx b/packages/managed-auth-react/src/components/StepError.tsx index 44623a3..d7b8955 100644 --- a/packages/managed-auth-react/src/components/StepError.tsx +++ b/packages/managed-auth-react/src/components/StepError.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { useSlot } from "../appearance/context"; import { useLocalization } from "../localization/context"; +import type { ErrorCode, Localizer } from "../localization/types"; import { extractDomainName } from "../lib/profile-name"; import { SiteIcon } from "./SiteIcon"; import { ChevronDownIcon, ChevronUpIcon, XCircleIcon } from "./icons"; @@ -11,101 +12,18 @@ interface StepErrorProps { errorCode?: string; } -// preferServerMessage shows the server's error_message when there is one, since -// it says how the flow ended (e.g. a person was asked and didn't finish in time). -const ERROR_DISPLAY: Record< - string, - { title: string; description: string; preferServerMessage?: boolean } -> = { - domain_not_allowed: { - title: "Domain not allowed", - description: - "The login flow redirected to a domain that isn't configured. Update the allowed_domains setting to include it.", - }, - login_form_not_found: { - title: "Login form not found", - description: - "We couldn't find a login form on this page. The website may have changed its layout, or the login URL might be incorrect.", - }, - credentials_invalid: { - title: "Invalid credentials", - description: "The username or password was not accepted by the website.", - }, - totp_required: { - title: "Authenticator code required", - description: "An authenticator code is required.", - }, - sms_code_required: { - title: "SMS code required", - description: "A code sent by SMS is required.", - }, - email_code_required: { - title: "Email code required", - description: "A code sent by email is required.", - }, - account_choice_required: { - title: "Account selection required", - description: - "An account or identity must be selected before login can continue.", - }, - customer_input_required: { - title: "Additional input required", - description: - "Additional information is required before login can continue.", - }, - external_action_required: { - title: "External action required", - description: - "An external action is required to continue. Check your authenticator app, email, or phone for a verification request.", - }, - totp_code_rejected: { - title: "Authenticator code rejected", - description: - "The website rejected the authenticator code. Try a fresh code, or reconnect the account if generated codes keep failing across new code windows.", - }, - bot_detected: { - title: "Verification required", - description: - "This website detected automated access and blocked the login.", - }, - captcha_blocked: { - title: "Verification required", - description: "A CAPTCHA blocked the login.", - preferServerMessage: true, - }, - stuck_in_loop: { - title: "Login couldn't complete", - description: - "We got stuck trying to complete the login. This can happen with unusual login flows.", - }, - max_attempts_reached: { - title: "Login couldn't complete", - description: - "We weren't able to complete the login after several attempts.", - }, - website_error: { - title: "Website error", - description: - "The website returned an error during login. The site may be experiencing issues.", - }, - navigation_confused: { - title: "Login couldn't complete", - description: - "We got confused navigating this website. This sometimes happens with complex login flows.", - }, - browser_error: { - title: "Browser error", - description: "There was an issue with the browser. Please try again.", - }, - session_expired: { - title: "Session expired", - description: - "The login session has expired. Please start a new login flow.", - }, -}; +// These codes show the server's error_message when there is one, since it says +// how the flow ended (e.g. a person was asked and didn't finish in time). +const PREFER_SERVER_MESSAGE = new Set(["captcha_blocked"]); -export function errorDisplayForCode(errorCode?: string) { - return errorCode ? ERROR_DISPLAY[errorCode] : undefined; +export function errorDisplayForCode(l: Localizer, errorCode?: string) { + if ( + !errorCode || + !Object.prototype.hasOwnProperty.call(l.errorCodeMessages, errorCode) + ) { + return undefined; + } + return l.errorCodeMessages[errorCode as ErrorCode]; } function extractErrorText(raw: string): string { @@ -134,13 +52,15 @@ export function StepError({ const siteName = extractDomainName(targetDomain); const [showDetails, setShowDetails] = useState(false); - const display = errorDisplayForCode(errorCode); + const display = errorDisplayForCode(l, errorCode); + const preferServerMessage = + errorCode !== undefined && PREFER_SERVER_MESSAGE.has(errorCode); const title = display?.title ?? l.errorTitle; const rawDetails = errorMessage?.trim() ? extractErrorText(errorMessage) : undefined; const description = - (display?.preferServerMessage ? rawDetails : undefined) ?? + (preferServerMessage ? rawDetails : undefined) ?? display?.description ?? l.errorGenericMessage; const hasDetails = rawDetails && rawDetails !== description; diff --git a/packages/managed-auth-react/src/index.ts b/packages/managed-auth-react/src/index.ts index 4154619..b580972 100644 --- a/packages/managed-auth-react/src/index.ts +++ b/packages/managed-auth-react/src/index.ts @@ -14,8 +14,19 @@ export type { KernelLogoColor, } from "./appearance/types"; -export type { Localization, Localizer } from "./localization"; -export { DEFAULT_LOCALIZATION, LocalizationProvider } from "./localization"; +export type { + ErrorCode, + ErrorCodeMessage, + Localization, + Localizer, + SupportedLocale, +} from "./localization"; +export { + DEFAULT_LOCALIZATION, + LOCALIZATIONS, + LocalizationProvider, + matchLocale, +} from "./localization"; export { AppearanceProvider } from "./appearance/context"; /** diff --git a/packages/managed-auth-react/src/localization/context.tsx b/packages/managed-auth-react/src/localization/context.tsx index 94f3c68..a5d5073 100644 --- a/packages/managed-auth-react/src/localization/context.tsx +++ b/packages/managed-auth-react/src/localization/context.tsx @@ -22,6 +22,10 @@ export function LocalizationProvider({ ...DEFAULT_LOCALIZATION.mfaTypeLabels, ...(localization.mfaTypeLabels ?? {}), }, + errorCodeMessages: { + ...DEFAULT_LOCALIZATION.errorCodeMessages, + ...(localization.errorCodeMessages ?? {}), + }, }; }, [localization]); return ( diff --git a/packages/managed-auth-react/src/localization/defaults.ts b/packages/managed-auth-react/src/localization/defaults.ts index 0ac347c..7e94a02 100644 --- a/packages/managed-auth-react/src/localization/defaults.ts +++ b/packages/managed-auth-react/src/localization/defaults.ts @@ -69,6 +69,92 @@ export const DEFAULT_LOCALIZATION: Localizer = { errorShowDetails: "Show details", errorHideDetails: "Hide details", errorCloseHint: "You can now close this window", + errorCodeMessages: { + domain_not_allowed: { + title: "Domain not allowed", + description: + "The login flow redirected to a domain that isn't configured. Update the allowed_domains setting to include it.", + }, + login_form_not_found: { + title: "Login form not found", + description: + "We couldn't find a login form on this page. The website may have changed its layout, or the login URL might be incorrect.", + }, + credentials_invalid: { + title: "Invalid credentials", + description: "The username or password was not accepted by the website.", + }, + totp_required: { + title: "Authenticator code required", + description: "An authenticator code is required.", + }, + sms_code_required: { + title: "SMS code required", + description: "A code sent by SMS is required.", + }, + email_code_required: { + title: "Email code required", + description: "A code sent by email is required.", + }, + account_choice_required: { + title: "Account selection required", + description: + "An account or identity must be selected before login can continue.", + }, + customer_input_required: { + title: "Additional input required", + description: + "Additional information is required before login can continue.", + }, + external_action_required: { + title: "External action required", + description: + "An external action is required to continue. Check your authenticator app, email, or phone for a verification request.", + }, + totp_code_rejected: { + title: "Authenticator code rejected", + description: + "The website rejected the authenticator code. Try a fresh code, or reconnect the account if generated codes keep failing across new code windows.", + }, + bot_detected: { + title: "Verification required", + description: + "This website detected automated access and blocked the login.", + }, + captcha_blocked: { + title: "Verification required", + description: "A CAPTCHA blocked the login.", + }, + stuck_in_loop: { + title: "Login couldn't complete", + description: + "We got stuck trying to complete the login. This can happen with unusual login flows.", + }, + max_attempts_reached: { + title: "Login couldn't complete", + description: + "We weren't able to complete the login after several attempts.", + }, + website_error: { + title: "Website error", + description: + "The website returned an error during login. The site may be experiencing issues.", + }, + navigation_confused: { + title: "Login couldn't complete", + description: + "We got confused navigating this website. This sometimes happens with complex login flows.", + }, + browser_error: { + title: "Browser error", + description: "There was an issue with the browser. Please try again.", + }, + session_expired: { + title: "Session expired", + description: + "The login session has expired. Please start a new login flow.", + }, + }, expiredTitle: "Session Expired", expiredDescription: "This authentication session has expired. Please start a new session.", @@ -88,4 +174,5 @@ export const DEFAULT_LOCALIZATION: Localizer = { humanInterventionLiveViewUnsupported: "Your browser can't show the login browser. Try a different browser.", humanInterventionRetry: "Try again", + poweredBy: "Powered by", }; diff --git a/packages/managed-auth-react/src/localization/index.ts b/packages/managed-auth-react/src/localization/index.ts index 24b02f7..f8223e3 100644 --- a/packages/managed-auth-react/src/localization/index.ts +++ b/packages/managed-auth-react/src/localization/index.ts @@ -1,3 +1,10 @@ -export type { Localization, Localizer } from "./types"; +export type { + ErrorCode, + ErrorCodeMessage, + Localization, + Localizer, +} from "./types"; export { DEFAULT_LOCALIZATION } from "./defaults"; export { LocalizationProvider, useLocalization } from "./context"; +export { LOCALIZATIONS, matchLocale } from "./locales"; +export type { SupportedLocale } from "./locales"; diff --git a/packages/managed-auth-react/src/localization/locales/da.ts b/packages/managed-auth-react/src/localization/locales/da.ts new file mode 100644 index 0000000..f99ebba --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/da.ts @@ -0,0 +1,175 @@ +import type { Localizer } from "../types"; + +export const da: Localizer = { + primeTitle: (site) => `Log ind på ${site}`, + primeSubtitle: (site) => + `Indtast dine loginoplysninger til ${site} for at fortsætte`, + primeContinueButton: "Fortsæt", + primeLoadingButton: "Indlæser...", + primeLoadingTitle: "Forbereder sikkert login", + primeLoadingSubtitle: "Indlæser forbindelsesoplysninger...", + securityEncryption: "Dine loginoplysninger er end-to-end-krypteret", + securityNoThirdParty: "Deles aldrig med nogen, heller ikke med en LLM", + legalPrefix: "Ved at fortsætte accepterer du Kernels", + legalPrivacyPolicy: "privatlivspolitik", + legalTermsOfService: "servicevilkår", + legalConjunction: "og", + discoveringMessage: "Undersøger, hvad login kræver...", + waitingForFormMessage: "Venter på loginformularen...", + submittingMessage: "Logger ind...", + loadingDiscoverySteps: [ + "Går til loginsiden...", + "Analyserer formularens struktur...", + "Finder de påkrævede felter...", + ], + loadingAuthSteps: [ + "Indtaster loginoplysninger...", + "Sender loginformularen...", + "Bekræfter login...", + ], + loadingTimeHint: "Det kan tage 15-30 sekunder...", + loginTitle: (site) => `Log ind på ${site}`, + ssoLoginTitle: (provider) => `Log ind med ${provider}`, + ssoLoginSubtitle: (site) => `til ${site}`, + mfaSelectTitle: "Vælg bekræftelsesmetode", + mfaSelectSubtitle: "Vælg, hvordan du vil modtage din bekræftelseskode", + signInSelectTitle: "Vælg en mulighed", + signInSelectSubtitle: "Vælg, hvilken mulighed du vil fortsætte med", + accountSelectTitle: "Vælg en konto", + accountSelectSubtitle: "Vælg, hvilken konto du vil fortsætte med", + submitButton: "Fortsæt", + submittingButton: "Logger ind...", + ssoButtonLabel: (provider) => `Log ind med ${provider}`, + orDivider: "eller", + passwordShow: "Vis adgangskode", + passwordHide: "Skjul adgangskode", + fieldRejectedNotice: + "Den gemte værdi blev afvist. Indtast en ny for at fortsætte.", + credentialSafetyNotice: + "Dine loginoplysninger krypteres og sendes direkte fra din browser. De deles aldrig med nogen, heller ikke med en LLM.", + mfaTypeLabels: { + sms: "Sms", + call: "Telefonopkald", + email: "E-mail", + totp: "Godkendelsesapp", + push: "Pushnotifikation", + password: "Adgangskode", + passkey: "Adgangsnøgle", + switch: "Brug en anden metode", + other: "Andet", + }, + successTitle: "Du er logget ind", + successDescription: (site) => `Din ${site}-konto er nu forbundet`, + successCloseHint: "Du kan nu lukke dette vindue", + errorTitle: "Login mislykkedes", + errorGenericMessage: + "Der opstod et uventet problem, da vi forsøgte at logge dig ind.", + errorCodeLabel: "Fejlkode", + errorShowDetails: "Vis detaljer", + errorHideDetails: "Skjul detaljer", + errorCloseHint: "Du kan nu lukke dette vindue", + errorCodeMessages: { + domain_not_allowed: { + title: "Domænet er ikke tilladt", + description: + "Login omdirigerede til et domæne, der ikke er konfigureret. Tilføj det til indstillingen allowed_domains.", + }, + login_form_not_found: { + title: "Loginformularen blev ikke fundet", + description: + "Vi kunne ikke finde en loginformular på denne side. Websitet kan have ændret layout, eller login-adressen kan være forkert.", + }, + credentials_invalid: { + title: "Ugyldige loginoplysninger", + description: "Websitet accepterede ikke brugernavnet eller adgangskoden.", + }, + totp_required: { + title: "Godkendelseskode påkrævet", + description: "Der kræves en kode fra en godkendelsesapp.", + }, + sms_code_required: { + title: "Sms-kode påkrævet", + description: "Der kræves en kode sendt via sms.", + }, + email_code_required: { + title: "E-mailkode påkrævet", + description: "Der kræves en kode sendt via e-mail.", + }, + account_choice_required: { + title: "Valg af konto påkrævet", + description: + "Der skal vælges en konto eller identitet, før login kan fortsætte.", + }, + customer_input_required: { + title: "Flere oplysninger påkrævet", + description: "Der kræves flere oplysninger, før login kan fortsætte.", + }, + external_action_required: { + title: "Ekstern handling påkrævet", + description: + "Der kræves en ekstern handling for at fortsætte. Tjek din godkendelsesapp, e-mail eller telefon for en anmodning om bekræftelse.", + }, + totp_code_rejected: { + title: "Godkendelseskoden blev afvist", + description: + "Websitet afviste godkendelseskoden. Prøv en ny kode, eller forbind kontoen igen, hvis genererede koder bliver ved med at fejle i nye tidsintervaller.", + }, + bot_detected: { + title: "Bekræftelse påkrævet", + description: + "Websitet registrerede automatiseret adgang og blokerede login.", + }, + captcha_blocked: { + title: "Bekræftelse påkrævet", + description: "En CAPTCHA blokerede login.", + }, + stuck_in_loop: { + title: "Login kunne ikke gennemføres", + description: + "Vi sad fast, da vi forsøgte at gennemføre login. Det kan ske med usædvanlige loginforløb.", + }, + max_attempts_reached: { + title: "Login kunne ikke gennemføres", + description: "Vi kunne ikke gennemføre login efter flere forsøg.", + }, + website_error: { + title: "Fejl på websitet", + description: + "Websitet returnerede en fejl under login. Websitet har muligvis problemer.", + }, + navigation_confused: { + title: "Login kunne ikke gennemføres", + description: + "Vi kunne ikke finde rundt på dette website. Det sker nogle gange med komplekse loginforløb.", + }, + browser_error: { + title: "Browserfejl", + description: "Der opstod et problem med browseren. Prøv igen.", + }, + session_expired: { + title: "Sessionen er udløbet", + description: "Loginsessionen er udløbet. Start et nyt login.", + }, + }, + expiredTitle: "Sessionen er udløbet", + expiredDescription: + "Denne godkendelsessession er udløbet. Start en ny session.", + externalActionTitle: "Handling påkrævet", + externalActionFallbackMessage: "Gennemfør bekræftelsen på din enhed", + externalActionWaiting: "Venter på din bekræftelse...", + humanInterventionTitle: "Menneskelig bekræftelse påkrævet", + humanInterventionMessage: (site) => + `Gennemfør kontrollen på ${site} ovenfor, og fortsæt derefter. Vi fortsætter med at logge dig ind bagefter.`, + humanInterventionDone: "Fortsæt", + humanInterventionLiveViewTitle: "Loginbrowser", + humanInterventionLiveViewUnavailable: + "Loginbrowseren er ikke tilgængelig lige nu.", + humanInterventionLiveViewFailed: + "Kunne ikke oprette forbindelse til loginbrowseren.", + humanInterventionLiveViewGaveUp: + "Kunne ikke oprette forbindelse til loginbrowseren. Genindlæs siden for at prøve igen.", + humanInterventionLiveViewUnsupported: + "Din browser kan ikke vise loginbrowseren. Prøv en anden browser.", + humanInterventionRetry: "Prøv igen", + poweredBy: "Leveret af", +}; diff --git a/packages/managed-auth-react/src/localization/locales/de.ts b/packages/managed-auth-react/src/localization/locales/de.ts new file mode 100644 index 0000000..0fd8e0e --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/de.ts @@ -0,0 +1,182 @@ +import type { Localizer } from "../types"; + +export const de: Localizer = { + primeTitle: (site) => `Bei ${site} anmelden`, + primeSubtitle: (site) => + `Geben Sie Ihre Zugangsdaten für ${site} ein, um fortzufahren`, + primeContinueButton: "Weiter", + primeLoadingButton: "Wird geladen...", + primeLoadingTitle: "Sichere Anmeldung wird vorbereitet", + primeLoadingSubtitle: "Verbindungsdetails werden geladen...", + securityEncryption: "Ihre Zugangsdaten sind Ende-zu-Ende-verschlüsselt", + securityNoThirdParty: "Niemals an Dritte oder ein LLM weitergegeben", + legalPrefix: "Indem Sie fortfahren, akzeptieren Sie Kernels", + legalPrivacyPolicy: "Datenschutzerklärung", + legalTermsOfService: "Nutzungsbedingungen", + legalConjunction: "und", + discoveringMessage: "Anmeldeanforderungen werden ermittelt...", + waitingForFormMessage: "Warten auf das Anmeldeformular...", + submittingMessage: "Anmeldung läuft...", + loadingDiscoverySteps: [ + "Anmeldeseite wird aufgerufen...", + "Formularaufbau wird analysiert...", + "Pflichtfelder werden ermittelt...", + ], + loadingAuthSteps: [ + "Zugangsdaten werden eingegeben...", + "Anmeldeformular wird gesendet...", + "Anmeldung wird überprüft...", + ], + loadingTimeHint: "Dies kann 15-30 Sekunden dauern...", + loginTitle: (site) => `Bei ${site} anmelden`, + ssoLoginTitle: (provider) => `Mit ${provider} anmelden`, + ssoLoginSubtitle: (site) => `für ${site}`, + mfaSelectTitle: "Bestätigungsmethode wählen", + mfaSelectSubtitle: + "Wählen Sie, wie Sie Ihren Bestätigungscode erhalten möchten", + signInSelectTitle: "Option wählen", + signInSelectSubtitle: "Wählen Sie, mit welcher Option Sie fortfahren möchten", + accountSelectTitle: "Konto wählen", + accountSelectSubtitle: "Wählen Sie, mit welchem Konto Sie fortfahren möchten", + submitButton: "Weiter", + submittingButton: "Anmeldung läuft...", + ssoButtonLabel: (provider) => `Mit ${provider} anmelden`, + orDivider: "oder", + passwordShow: "Passwort anzeigen", + passwordHide: "Passwort verbergen", + fieldRejectedNotice: + "Der gespeicherte Wert wurde abgelehnt. Geben Sie einen neuen ein, um fortzufahren.", + credentialSafetyNotice: + "Ihre Zugangsdaten werden verschlüsselt und direkt von Ihrem Browser gesendet. Sie werden niemals an Dritte oder ein LLM weitergegeben.", + mfaTypeLabels: { + sms: "SMS", + call: "Anruf", + email: "E-Mail", + totp: "Authenticator-App", + push: "Push-Benachrichtigung", + password: "Passwort", + passkey: "Passkey", + switch: "Andere Methode verwenden", + other: "Andere", + }, + successTitle: "Erfolgreich angemeldet", + successDescription: (site) => `Ihr ${site}-Konto ist jetzt verbunden`, + successCloseHint: "Sie können dieses Fenster jetzt schließen", + errorTitle: "Anmeldung fehlgeschlagen", + errorGenericMessage: + "Bei Ihrer Anmeldung ist ein unerwartetes Problem aufgetreten.", + errorCodeLabel: "Fehlercode", + errorShowDetails: "Details anzeigen", + errorHideDetails: "Details ausblenden", + errorCloseHint: "Sie können dieses Fenster jetzt schließen", + errorCodeMessages: { + domain_not_allowed: { + title: "Domain nicht zulässig", + description: + "Der Anmeldevorgang wurde auf eine nicht konfigurierte Domain weitergeleitet. Fügen Sie sie der Einstellung allowed_domains hinzu.", + }, + login_form_not_found: { + title: "Anmeldeformular nicht gefunden", + description: + "Auf dieser Seite wurde kein Anmeldeformular gefunden. Möglicherweise wurde das Layout der Website geändert oder die Anmelde-URL ist falsch.", + }, + credentials_invalid: { + title: "Ungültige Zugangsdaten", + description: + "Die Website hat den Benutzernamen oder das Passwort nicht akzeptiert.", + }, + totp_required: { + title: "Authenticator-Code erforderlich", + description: "Ein Authenticator-Code ist erforderlich.", + }, + sms_code_required: { + title: "SMS-Code erforderlich", + description: "Ein per SMS gesendeter Code ist erforderlich.", + }, + email_code_required: { + title: "E-Mail-Code erforderlich", + description: "Ein per E-Mail gesendeter Code ist erforderlich.", + }, + account_choice_required: { + title: "Kontoauswahl erforderlich", + description: + "Bevor die Anmeldung fortgesetzt werden kann, muss ein Konto oder eine Identität ausgewählt werden.", + }, + customer_input_required: { + title: "Weitere Angaben erforderlich", + description: + "Bevor die Anmeldung fortgesetzt werden kann, sind weitere Angaben erforderlich.", + }, + external_action_required: { + title: "Externe Aktion erforderlich", + description: + "Zum Fortfahren ist eine externe Aktion erforderlich. Prüfen Sie Ihre Authenticator-App, Ihre E-Mails oder Ihr Telefon auf eine Bestätigungsanfrage.", + }, + totp_code_rejected: { + title: "Authenticator-Code abgelehnt", + description: + "Die Website hat den Authenticator-Code abgelehnt. Versuchen Sie es mit einem neuen Code oder verbinden Sie das Konto erneut, wenn generierte Codes auch in neuen Zeitfenstern weiterhin fehlschlagen.", + }, + bot_detected: { + title: "Überprüfung erforderlich", + description: + "Diese Website hat einen automatisierten Zugriff erkannt und die Anmeldung blockiert.", + }, + captcha_blocked: { + title: "Überprüfung erforderlich", + description: "Ein CAPTCHA hat die Anmeldung blockiert.", + }, + stuck_in_loop: { + title: "Anmeldung konnte nicht abgeschlossen werden", + description: + "Beim Abschließen der Anmeldung sind wir nicht weitergekommen. Das kann bei ungewöhnlichen Anmeldeabläufen passieren.", + }, + max_attempts_reached: { + title: "Anmeldung konnte nicht abgeschlossen werden", + description: + "Die Anmeldung konnte auch nach mehreren Versuchen nicht abgeschlossen werden.", + }, + website_error: { + title: "Website-Fehler", + description: + "Die Website hat während der Anmeldung einen Fehler gemeldet. Möglicherweise hat die Website gerade Probleme.", + }, + navigation_confused: { + title: "Anmeldung konnte nicht abgeschlossen werden", + description: + "Wir konnten uns auf dieser Website nicht zurechtfinden. Das kommt bei komplexen Anmeldeabläufen manchmal vor.", + }, + browser_error: { + title: "Browserfehler", + description: + "Es gab ein Problem mit dem Browser. Bitte versuchen Sie es erneut.", + }, + session_expired: { + title: "Sitzung abgelaufen", + description: + "Die Anmeldesitzung ist abgelaufen. Bitte starten Sie einen neuen Anmeldevorgang.", + }, + }, + expiredTitle: "Sitzung abgelaufen", + expiredDescription: + "Diese Anmeldesitzung ist abgelaufen. Bitte starten Sie eine neue Sitzung.", + externalActionTitle: "Aktion erforderlich", + externalActionFallbackMessage: + "Schließen Sie die Bestätigung auf Ihrem Gerät ab", + externalActionWaiting: "Warten auf Ihre Bestätigung...", + humanInterventionTitle: "Menschliche Überprüfung erforderlich", + humanInterventionMessage: (site) => + `Schließen Sie die Prüfung bei ${site} oben ab und fahren Sie dann fort. Anschließend setzen wir Ihre Anmeldung fort.`, + humanInterventionDone: "Weiter", + humanInterventionLiveViewTitle: "Anmeldebrowser", + humanInterventionLiveViewUnavailable: + "Der Anmeldebrowser ist gerade nicht verfügbar.", + humanInterventionLiveViewFailed: + "Verbindung zum Anmeldebrowser fehlgeschlagen.", + humanInterventionLiveViewGaveUp: + "Verbindung zum Anmeldebrowser fehlgeschlagen. Laden Sie die Seite neu, um es erneut zu versuchen.", + humanInterventionLiveViewUnsupported: + "Ihr Browser kann den Anmeldebrowser nicht anzeigen. Versuchen Sie es mit einem anderen Browser.", + humanInterventionRetry: "Erneut versuchen", + poweredBy: "Bereitgestellt von", +}; diff --git a/packages/managed-auth-react/src/localization/locales/es.ts b/packages/managed-auth-react/src/localization/locales/es.ts new file mode 100644 index 0000000..04bd5ac --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/es.ts @@ -0,0 +1,181 @@ +import type { Localizer } from "../types"; + +export const es: Localizer = { + primeTitle: (site) => `Inicia sesión en ${site}`, + primeSubtitle: (site) => + `Introduce tus credenciales de ${site} para continuar`, + primeContinueButton: "Continuar", + primeLoadingButton: "Cargando...", + primeLoadingTitle: "Preparando el inicio de sesión seguro", + primeLoadingSubtitle: "Cargando los detalles de la conexión...", + securityEncryption: "Tus credenciales están cifradas de extremo a extremo", + securityNoThirdParty: "Nunca se comparten con nadie ni con ningún LLM", + legalPrefix: "Al continuar, aceptas la", + legalPrivacyPolicy: "Política de privacidad", + legalTermsOfService: "Términos del servicio de Kernel", + legalConjunction: "y los", + discoveringMessage: "Detectando los requisitos de inicio de sesión...", + waitingForFormMessage: "Esperando el formulario de inicio de sesión...", + submittingMessage: "Iniciando sesión...", + loadingDiscoverySteps: [ + "Accediendo a la página de inicio de sesión...", + "Analizando la estructura del formulario...", + "Identificando los campos obligatorios...", + ], + loadingAuthSteps: [ + "Introduciendo las credenciales...", + "Enviando el formulario de inicio de sesión...", + "Verificando la autenticación...", + ], + loadingTimeHint: "Esto puede tardar entre 15 y 30 segundos...", + loginTitle: (site) => `Inicia sesión en ${site}`, + ssoLoginTitle: (provider) => `Inicia sesión con ${provider}`, + ssoLoginSubtitle: (site) => `para ${site}`, + mfaSelectTitle: "Elige un método de verificación", + mfaSelectSubtitle: + "Selecciona cómo quieres recibir tu código de verificación", + signInSelectTitle: "Elige una opción", + signInSelectSubtitle: "Selecciona con qué opción quieres continuar", + accountSelectTitle: "Elige una cuenta", + accountSelectSubtitle: "Selecciona con qué cuenta quieres continuar", + submitButton: "Continuar", + submittingButton: "Iniciando sesión...", + ssoButtonLabel: (provider) => `Iniciar sesión con ${provider}`, + orDivider: "o", + passwordShow: "Mostrar contraseña", + passwordHide: "Ocultar contraseña", + fieldRejectedNotice: + "Se ha rechazado el valor guardado. Introduce uno nuevo para continuar.", + credentialSafetyNotice: + "Tus credenciales se cifran y se envían directamente desde tu navegador. Nunca se comparten con nadie ni con ningún LLM.", + mfaTypeLabels: { + sms: "SMS", + call: "Llamada telefónica", + email: "Correo electrónico", + totp: "App de autenticación", + push: "Notificación push", + password: "Contraseña", + passkey: "Llave de acceso", + switch: "Usar otro método", + other: "Otro", + }, + successTitle: "Has iniciado sesión correctamente", + successDescription: (site) => `Tu cuenta de ${site} ya está conectada`, + successCloseHint: "Ya puedes cerrar esta ventana", + errorTitle: "No se ha podido iniciar sesión", + errorGenericMessage: + "Se ha producido un problema inesperado al intentar iniciar tu sesión.", + errorCodeLabel: "Código de error", + errorShowDetails: "Mostrar detalles", + errorHideDetails: "Ocultar detalles", + errorCloseHint: "Ya puedes cerrar esta ventana", + errorCodeMessages: { + domain_not_allowed: { + title: "Dominio no permitido", + description: + "El inicio de sesión redirigió a un dominio que no está configurado. Añádelo a la opción allowed_domains.", + }, + login_form_not_found: { + title: "No se encontró el formulario de inicio de sesión", + description: + "No hemos encontrado ningún formulario de inicio de sesión en esta página. Es posible que el sitio web haya cambiado su diseño o que la URL de inicio de sesión no sea correcta.", + }, + credentials_invalid: { + title: "Credenciales no válidas", + description: + "El sitio web no aceptó el nombre de usuario o la contraseña.", + }, + totp_required: { + title: "Se requiere un código de autenticación", + description: "Se requiere un código de la app de autenticación.", + }, + sms_code_required: { + title: "Se requiere un código SMS", + description: "Se requiere un código enviado por SMS.", + }, + email_code_required: { + title: "Se requiere un código por correo", + description: "Se requiere un código enviado por correo electrónico.", + }, + account_choice_required: { + title: "Se requiere seleccionar una cuenta", + description: + "Hay que seleccionar una cuenta o identidad para continuar con el inicio de sesión.", + }, + customer_input_required: { + title: "Se requiere información adicional", + description: + "Se necesita información adicional para continuar con el inicio de sesión.", + }, + external_action_required: { + title: "Se requiere una acción externa", + description: + "Se necesita una acción externa para continuar. Revisa tu app de autenticación, tu correo o tu teléfono por si tienes una solicitud de verificación.", + }, + totp_code_rejected: { + title: "Código de autenticación rechazado", + description: + "El sitio web rechazó el código de autenticación. Prueba con un código nuevo o vuelve a conectar la cuenta si los códigos generados siguen fallando en distintos intervalos.", + }, + bot_detected: { + title: "Se requiere verificación", + description: + "Este sitio web detectó un acceso automatizado y bloqueó el inicio de sesión.", + }, + captcha_blocked: { + title: "Se requiere verificación", + description: "Un CAPTCHA bloqueó el inicio de sesión.", + }, + stuck_in_loop: { + title: "No se pudo completar el inicio de sesión", + description: + "Nos hemos quedado atascados al intentar completar el inicio de sesión. Puede ocurrir con procesos de inicio de sesión poco habituales.", + }, + max_attempts_reached: { + title: "No se pudo completar el inicio de sesión", + description: + "No hemos podido completar el inicio de sesión tras varios intentos.", + }, + website_error: { + title: "Error del sitio web", + description: + "El sitio web devolvió un error durante el inicio de sesión. Puede que esté teniendo problemas.", + }, + navigation_confused: { + title: "No se pudo completar el inicio de sesión", + description: + "No hemos conseguido navegar correctamente por este sitio web. A veces ocurre con procesos de inicio de sesión complejos.", + }, + browser_error: { + title: "Error del navegador", + description: + "Se ha producido un problema con el navegador. Inténtalo de nuevo.", + }, + session_expired: { + title: "Sesión caducada", + description: + "La sesión de inicio de sesión ha caducado. Vuelve a iniciar el proceso.", + }, + }, + expiredTitle: "Sesión caducada", + expiredDescription: + "Esta sesión de autenticación ha caducado. Inicia una nueva sesión.", + externalActionTitle: "Acción necesaria", + externalActionFallbackMessage: "Completa la verificación en tu dispositivo", + externalActionWaiting: "Esperando tu confirmación...", + humanInterventionTitle: "Se requiere verificación humana", + humanInterventionMessage: (site) => + `Completa la comprobación de ${site} que aparece arriba y luego continúa. Después seguiremos con tu inicio de sesión.`, + humanInterventionDone: "Continuar", + humanInterventionLiveViewTitle: "Navegador de inicio de sesión", + humanInterventionLiveViewUnavailable: + "El navegador de inicio de sesión no está disponible en este momento.", + humanInterventionLiveViewFailed: + "No se ha podido conectar con el navegador de inicio de sesión.", + humanInterventionLiveViewGaveUp: + "No se ha podido conectar con el navegador de inicio de sesión. Vuelve a cargar esta página para intentarlo de nuevo.", + humanInterventionLiveViewUnsupported: + "Tu navegador no puede mostrar el navegador de inicio de sesión. Prueba con otro navegador.", + humanInterventionRetry: "Reintentar", + poweredBy: "Con la tecnología de", +}; diff --git a/packages/managed-auth-react/src/localization/locales/fi.ts b/packages/managed-auth-react/src/localization/locales/fi.ts new file mode 100644 index 0000000..a72d3ba --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/fi.ts @@ -0,0 +1,176 @@ +import type { Localizer } from "../types"; + +export const fi: Localizer = { + primeTitle: (site) => `Kirjaudu palveluun ${site}`, + primeSubtitle: (site) => `Jatka antamalla palvelun ${site} kirjautumistiedot`, + primeContinueButton: "Jatka", + primeLoadingButton: "Ladataan...", + primeLoadingTitle: "Valmistellaan suojattua kirjautumista", + primeLoadingSubtitle: "Ladataan yhteyden tietoja...", + securityEncryption: "Kirjautumistietosi salataan päästä päähän", + securityNoThirdParty: + "Tietoja ei koskaan jaeta kenellekään eikä millekään LLM:lle", + legalPrefix: "Jatkamalla hyväksyt Kernelin", + legalPrivacyPolicy: "tietosuojakäytännön", + legalTermsOfService: "käyttöehdot", + legalConjunction: "ja", + discoveringMessage: "Selvitetään kirjautumisen vaatimuksia...", + waitingForFormMessage: "Odotetaan kirjautumislomaketta...", + submittingMessage: "Kirjaudutaan...", + loadingDiscoverySteps: [ + "Siirrytään kirjautumissivulle...", + "Analysoidaan lomakkeen rakennetta...", + "Tunnistetaan pakollisia kenttiä...", + ], + loadingAuthSteps: [ + "Syötetään kirjautumistietoja...", + "Lähetetään kirjautumislomaketta...", + "Vahvistetaan kirjautumista...", + ], + loadingTimeHint: "Tämä voi kestää 15-30 sekuntia...", + loginTitle: (site) => `Kirjaudu palveluun ${site}`, + ssoLoginTitle: (provider) => `Kirjaudu palvelulla ${provider}`, + ssoLoginSubtitle: (site) => `palveluun ${site}`, + mfaSelectTitle: "Valitse vahvistustapa", + mfaSelectSubtitle: "Valitse, miten haluat saada vahvistuskoodin", + signInSelectTitle: "Valitse vaihtoehto", + signInSelectSubtitle: "Valitse, millä vaihtoehdolla haluat jatkaa", + accountSelectTitle: "Valitse tili", + accountSelectSubtitle: "Valitse, millä tilillä haluat jatkaa", + submitButton: "Jatka", + submittingButton: "Kirjaudutaan...", + ssoButtonLabel: (provider) => `Kirjaudu palvelulla ${provider}`, + orDivider: "tai", + passwordShow: "Näytä salasana", + passwordHide: "Piilota salasana", + fieldRejectedNotice: + "Tallennettua arvoa ei hyväksytty. Jatka antamalla uusi arvo.", + credentialSafetyNotice: + "Kirjautumistietosi salataan ja lähetetään suoraan selaimestasi. Niitä ei koskaan jaeta kenellekään eikä millekään LLM:lle.", + mfaTypeLabels: { + sms: "Tekstiviesti", + call: "Puhelu", + email: "Sähköposti", + totp: "Todennussovellus", + push: "Push-ilmoitus", + password: "Salasana", + passkey: "Pääsyavain", + switch: "Käytä toista tapaa", + other: "Muu", + }, + successTitle: "Kirjautuminen onnistui", + successDescription: (site) => `${site}-tilisi on nyt yhdistetty`, + successCloseHint: "Voit nyt sulkea tämän ikkunan", + errorTitle: "Kirjautuminen epäonnistui", + errorGenericMessage: "Kirjautumisessa tapahtui odottamaton virhe.", + errorCodeLabel: "Virhekoodi", + errorShowDetails: "Näytä tiedot", + errorHideDetails: "Piilota tiedot", + errorCloseHint: "Voit nyt sulkea tämän ikkunan", + errorCodeMessages: { + domain_not_allowed: { + title: "Verkkotunnus ei ole sallittu", + description: + "Kirjautuminen ohjautui verkkotunnukseen, jota ei ole määritetty. Lisää se allowed_domains-asetukseen.", + }, + login_form_not_found: { + title: "Kirjautumislomaketta ei löytynyt", + description: + "Tältä sivulta ei löytynyt kirjautumislomaketta. Sivuston ulkoasu on voinut muuttua, tai kirjautumisosoite voi olla väärä.", + }, + credentials_invalid: { + title: "Virheelliset kirjautumistiedot", + description: "Sivusto ei hyväksynyt käyttäjänimeä tai salasanaa.", + }, + totp_required: { + title: "Todennuskoodi vaaditaan", + description: "Todennussovelluksen koodi vaaditaan.", + }, + sms_code_required: { + title: "Tekstiviestikoodi vaaditaan", + description: "Tekstiviestillä lähetetty koodi vaaditaan.", + }, + email_code_required: { + title: "Sähköpostikoodi vaaditaan", + description: "Sähköpostilla lähetetty koodi vaaditaan.", + }, + account_choice_required: { + title: "Tilin valinta vaaditaan", + description: + "Tili tai identiteetti on valittava, ennen kuin kirjautumista voidaan jatkaa.", + }, + customer_input_required: { + title: "Lisätietoja vaaditaan", + description: + "Lisätietoja tarvitaan, ennen kuin kirjautumista voidaan jatkaa.", + }, + external_action_required: { + title: "Ulkoinen toimenpide vaaditaan", + description: + "Jatkaminen edellyttää ulkoista toimenpidettä. Tarkista, onko todennussovelluksessasi, sähköpostissasi tai puhelimessasi vahvistuspyyntö.", + }, + totp_code_rejected: { + title: "Todennuskoodi hylättiin", + description: + "Sivusto hylkäsi todennuskoodin. Kokeile uutta koodia tai yhdistä tili uudelleen, jos luodut koodit epäonnistuvat jatkuvasti uusissakin aikaikkunoissa.", + }, + bot_detected: { + title: "Vahvistus vaaditaan", + description: + "Sivusto havaitsi automatisoidun käytön ja esti kirjautumisen.", + }, + captcha_blocked: { + title: "Vahvistus vaaditaan", + description: "CAPTCHA esti kirjautumisen.", + }, + stuck_in_loop: { + title: "Kirjautumista ei voitu suorittaa loppuun", + description: + "Jäimme jumiin yrittäessämme suorittaa kirjautumisen loppuun. Näin voi käydä epätavallisissa kirjautumistavoissa.", + }, + max_attempts_reached: { + title: "Kirjautumista ei voitu suorittaa loppuun", + description: + "Kirjautumista ei saatu suoritettua loppuun useista yrityksistä huolimatta.", + }, + website_error: { + title: "Sivustovirhe", + description: + "Sivusto palautti virheen kirjautumisen aikana. Sivustolla voi olla ongelmia.", + }, + navigation_confused: { + title: "Kirjautumista ei voitu suorittaa loppuun", + description: + "Emme löytäneet oikeaa reittiä tällä sivustolla. Näin käy joskus monimutkaisissa kirjautumistavoissa.", + }, + browser_error: { + title: "Selainvirhe", + description: "Selaimessa tapahtui virhe. Yritä uudelleen.", + }, + session_expired: { + title: "Istunto vanhentui", + description: + "Kirjautumisistunto on vanhentunut. Aloita kirjautuminen uudelleen.", + }, + }, + expiredTitle: "Istunto vanhentui", + expiredDescription: + "Tämä todennusistunto on vanhentunut. Aloita uusi istunto.", + externalActionTitle: "Toimenpide vaaditaan", + externalActionFallbackMessage: "Suorita vahvistus loppuun laitteellasi", + externalActionWaiting: "Odotetaan vahvistustasi...", + humanInterventionTitle: "Ihmisen vahvistus vaaditaan", + humanInterventionMessage: (site) => + `Suorita yllä oleva palvelun ${site} tarkistus ja jatka sitten. Jatkamme kirjautumista sen jälkeen.`, + humanInterventionDone: "Jatka", + humanInterventionLiveViewTitle: "Kirjautumisselain", + humanInterventionLiveViewUnavailable: + "Kirjautumisselain ei ole juuri nyt käytettävissä.", + humanInterventionLiveViewFailed: "Kirjautumisselaimeen ei saatu yhteyttä.", + humanInterventionLiveViewGaveUp: + "Kirjautumisselaimeen ei saatu yhteyttä. Yritä uudelleen lataamalla sivu uudelleen.", + humanInterventionLiveViewUnsupported: + "Selaimesi ei pysty näyttämään kirjautumisselainta. Kokeile toista selainta.", + humanInterventionRetry: "Yritä uudelleen", + poweredBy: "Palvelun tarjoaa", +}; diff --git a/packages/managed-auth-react/src/localization/locales/fr.ts b/packages/managed-auth-react/src/localization/locales/fr.ts new file mode 100644 index 0000000..88d0e77 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/fr.ts @@ -0,0 +1,179 @@ +import type { Localizer } from "../types"; + +export const fr: Localizer = { + primeTitle: (site) => `Se connecter à ${site}`, + primeSubtitle: (site) => `Saisissez vos identifiants ${site} pour continuer`, + primeContinueButton: "Continuer", + primeLoadingButton: "Chargement...", + primeLoadingTitle: "Préparation de la connexion sécurisée", + primeLoadingSubtitle: "Chargement des détails de connexion...", + securityEncryption: "Vos identifiants sont chiffrés de bout en bout", + securityNoThirdParty: "Jamais partagés avec qui que ce soit ni avec un LLM", + legalPrefix: "En continuant, vous acceptez la", + legalPrivacyPolicy: "Politique de confidentialité", + legalTermsOfService: "Conditions d’utilisation de Kernel", + legalConjunction: "et les", + discoveringMessage: "Analyse des exigences de connexion...", + waitingForFormMessage: "En attente du formulaire de connexion...", + submittingMessage: "Connexion en cours...", + loadingDiscoverySteps: [ + "Accès à la page de connexion...", + "Analyse de la structure du formulaire...", + "Identification des champs requis...", + ], + loadingAuthSteps: [ + "Saisie des identifiants...", + "Envoi du formulaire de connexion...", + "Vérification de l’authentification...", + ], + loadingTimeHint: "Cela peut prendre 15 à 30 secondes...", + loginTitle: (site) => `Se connecter à ${site}`, + ssoLoginTitle: (provider) => `Se connecter avec ${provider}`, + ssoLoginSubtitle: (site) => `pour ${site}`, + mfaSelectTitle: "Choisissez une méthode de vérification", + mfaSelectSubtitle: "Choisissez comment recevoir votre code de vérification", + signInSelectTitle: "Choisissez une option", + signInSelectSubtitle: "Choisissez l’option avec laquelle continuer", + accountSelectTitle: "Choisissez un compte", + accountSelectSubtitle: "Choisissez le compte avec lequel continuer", + submitButton: "Continuer", + submittingButton: "Connexion en cours...", + ssoButtonLabel: (provider) => `Se connecter avec ${provider}`, + orDivider: "ou", + passwordShow: "Afficher le mot de passe", + passwordHide: "Masquer le mot de passe", + fieldRejectedNotice: + "La valeur enregistrée a été refusée. Saisissez-en une nouvelle pour continuer.", + credentialSafetyNotice: + "Vos identifiants sont chiffrés et envoyés directement depuis votre navigateur. Ils ne sont jamais partagés avec qui que ce soit ni avec un LLM.", + mfaTypeLabels: { + sms: "SMS", + call: "Appel téléphonique", + email: "E-mail", + totp: "Application d’authentification", + push: "Notification push", + password: "Mot de passe", + passkey: "Clé d’accès", + switch: "Utiliser une autre méthode", + other: "Autre", + }, + successTitle: "Connexion réussie", + successDescription: (site) => `Votre compte ${site} est maintenant connecté`, + successCloseHint: "Vous pouvez maintenant fermer cette fenêtre", + errorTitle: "Échec de la connexion", + errorGenericMessage: + "Un problème inattendu est survenu lors de votre connexion.", + errorCodeLabel: "Code d’erreur", + errorShowDetails: "Afficher les détails", + errorHideDetails: "Masquer les détails", + errorCloseHint: "Vous pouvez maintenant fermer cette fenêtre", + errorCodeMessages: { + domain_not_allowed: { + title: "Domaine non autorisé", + description: + "La connexion a redirigé vers un domaine non configuré. Ajoutez-le au paramètre allowed_domains.", + }, + login_form_not_found: { + title: "Formulaire de connexion introuvable", + description: + "Aucun formulaire de connexion n’a été trouvé sur cette page. Le site a peut-être changé de mise en page, ou l’URL de connexion est peut-être incorrecte.", + }, + credentials_invalid: { + title: "Identifiants invalides", + description: + "Le site n’a pas accepté le nom d’utilisateur ou le mot de passe.", + }, + totp_required: { + title: "Code d’authentification requis", + description: "Un code d’application d’authentification est requis.", + }, + sms_code_required: { + title: "Code SMS requis", + description: "Un code envoyé par SMS est requis.", + }, + email_code_required: { + title: "Code e-mail requis", + description: "Un code envoyé par e-mail est requis.", + }, + account_choice_required: { + title: "Sélection du compte requise", + description: + "Un compte ou une identité doit être sélectionné avant de poursuivre la connexion.", + }, + customer_input_required: { + title: "Informations supplémentaires requises", + description: + "Des informations supplémentaires sont nécessaires avant de poursuivre la connexion.", + }, + external_action_required: { + title: "Action externe requise", + description: + "Une action externe est nécessaire pour continuer. Vérifiez votre application d’authentification, vos e-mails ou votre téléphone pour une demande de vérification.", + }, + totp_code_rejected: { + title: "Code d’authentification refusé", + description: + "Le site a refusé le code d’authentification. Essayez un nouveau code, ou reconnectez le compte si les codes générés continuent d’échouer sur plusieurs périodes.", + }, + bot_detected: { + title: "Vérification requise", + description: + "Ce site a détecté un accès automatisé et a bloqué la connexion.", + }, + captcha_blocked: { + title: "Vérification requise", + description: "Un CAPTCHA a bloqué la connexion.", + }, + stuck_in_loop: { + title: "La connexion n’a pas pu aboutir", + description: + "Nous sommes restés bloqués en essayant de finaliser la connexion. Cela peut arriver avec des processus de connexion inhabituels.", + }, + max_attempts_reached: { + title: "La connexion n’a pas pu aboutir", + description: + "Nous n’avons pas pu finaliser la connexion après plusieurs tentatives.", + }, + website_error: { + title: "Erreur du site", + description: + "Le site a renvoyé une erreur pendant la connexion. Il rencontre peut-être des problèmes.", + }, + navigation_confused: { + title: "La connexion n’a pas pu aboutir", + description: + "Nous n’avons pas réussi à naviguer sur ce site. Cela arrive parfois avec des processus de connexion complexes.", + }, + browser_error: { + title: "Erreur du navigateur", + description: + "Un problème est survenu avec le navigateur. Veuillez réessayer.", + }, + session_expired: { + title: "Session expirée", + description: + "La session de connexion a expiré. Veuillez recommencer la connexion.", + }, + }, + expiredTitle: "Session expirée", + expiredDescription: + "Cette session d’authentification a expiré. Veuillez démarrer une nouvelle session.", + externalActionTitle: "Action requise", + externalActionFallbackMessage: "Terminez la vérification sur votre appareil", + externalActionWaiting: "En attente de votre confirmation...", + humanInterventionTitle: "Vérification humaine requise", + humanInterventionMessage: (site) => + `Effectuez la vérification de ${site} ci-dessus, puis continuez. Nous reprendrons ensuite votre connexion.`, + humanInterventionDone: "Continuer", + humanInterventionLiveViewTitle: "Navigateur de connexion", + humanInterventionLiveViewUnavailable: + "Le navigateur de connexion n’est pas disponible pour le moment.", + humanInterventionLiveViewFailed: + "Impossible de se connecter au navigateur de connexion.", + humanInterventionLiveViewGaveUp: + "Impossible de se connecter au navigateur de connexion. Rechargez cette page pour réessayer.", + humanInterventionLiveViewUnsupported: + "Votre navigateur ne peut pas afficher le navigateur de connexion. Essayez un autre navigateur.", + humanInterventionRetry: "Réessayer", + poweredBy: "Propulsé par", +}; diff --git a/packages/managed-auth-react/src/localization/locales/index.test.ts b/packages/managed-auth-react/src/localization/locales/index.test.ts new file mode 100644 index 0000000..2216417 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/index.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, test } from "bun:test"; +import { LOCALIZATIONS, matchLocale } from "."; + +describe("matchLocale", () => { + test("returns the first preference with a built-in localization", () => { + expect(matchLocale(["sv-SE", "en-US"])).toBe("sv"); + expect(matchLocale(["en-GB", "de"])).toBe("en"); + }); + + test("skips preferences without a built-in localization", () => { + expect(matchLocale(["ja-JP", "pt-BR", "de-AT"])).toBe("de"); + }); + + test("matches regardless of case, separator, and whitespace", () => { + expect(matchLocale([" FR_ca "])).toBe("fr"); + }); + + test("maps generic Norwegian to Bokmål", () => { + expect(matchLocale(["no"])).toBe("nb"); + expect(matchLocale(["nb-NO"])).toBe("nb"); + }); + + test("returns undefined when nothing matches", () => { + expect(matchLocale([])).toBeUndefined(); + expect(matchLocale(["*", "ja"])).toBeUndefined(); + expect(matchLocale(["constructor", "toString"])).toBeUndefined(); + }); +}); + +describe("LOCALIZATIONS", () => { + test("every localization interpolates the site and provider names", () => { + for (const [locale, l] of Object.entries(LOCALIZATIONS)) { + const rendered = [ + l.primeTitle("Zalando"), + l.primeSubtitle("Zalando"), + l.loginTitle("Zalando"), + l.ssoLoginSubtitle("Zalando"), + l.successDescription("Zalando"), + l.humanInterventionMessage("Zalando"), + l.ssoLoginTitle("Zalando"), + l.ssoButtonLabel("Zalando"), + ]; + for (const text of rendered) { + expect(text, locale).toContain("Zalando"); + } + } + }); +}); diff --git a/packages/managed-auth-react/src/localization/locales/index.ts b/packages/managed-auth-react/src/localization/locales/index.ts new file mode 100644 index 0000000..3acf106 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/index.ts @@ -0,0 +1,47 @@ +import { DEFAULT_LOCALIZATION } from "../defaults"; +import type { Localizer } from "../types"; +import { da } from "./da"; +import { de } from "./de"; +import { es } from "./es"; +import { fi } from "./fi"; +import { fr } from "./fr"; +import { it } from "./it"; +import { nb } from "./nb"; +import { nl } from "./nl"; +import { pl } from "./pl"; +import { sv } from "./sv"; + +/** Built-in localizations, keyed by language subtag. */ +export const LOCALIZATIONS = { + en: DEFAULT_LOCALIZATION, + da, + de, + es, + fi, + fr, + it, + nb, + nl, + pl, + sv, +} satisfies Record; + +export type SupportedLocale = keyof typeof LOCALIZATIONS; + +/** + * Returns the first entry in `preferred` (BCP 47 tags, most preferred first) + * with a built-in localization, matching on the language subtag. + */ +export function matchLocale( + preferred: readonly string[], +): SupportedLocale | undefined { + for (const tag of preferred) { + const language = tag.trim().toLowerCase().split(/[-_]/)[0]; + // Browsers send "no" for Norwegian; Bokmål is its written standard. + const locale = language === "no" ? "nb" : language; + if (Object.prototype.hasOwnProperty.call(LOCALIZATIONS, locale)) { + return locale as SupportedLocale; + } + } + return undefined; +} diff --git a/packages/managed-auth-react/src/localization/locales/it.ts b/packages/managed-auth-react/src/localization/locales/it.ts new file mode 100644 index 0000000..336ff84 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/it.ts @@ -0,0 +1,177 @@ +import type { Localizer } from "../types"; + +export const it: Localizer = { + primeTitle: (site) => `Accedi a ${site}`, + primeSubtitle: (site) => + `Inserisci le tue credenziali di ${site} per continuare`, + primeContinueButton: "Continua", + primeLoadingButton: "Caricamento...", + primeLoadingTitle: "Preparazione dell'accesso sicuro", + primeLoadingSubtitle: "Caricamento dei dettagli di connessione...", + securityEncryption: "Le tue credenziali sono crittografate end-to-end", + securityNoThirdParty: "Mai condivise con nessuno né con alcun LLM", + legalPrefix: "Continuando accetti i documenti di Kernel:", + legalPrivacyPolicy: "Informativa sulla privacy", + legalTermsOfService: "Termini di servizio", + legalConjunction: "e", + discoveringMessage: "Rilevamento dei requisiti di accesso...", + waitingForFormMessage: "In attesa del modulo di accesso...", + submittingMessage: "Accesso in corso...", + loadingDiscoverySteps: [ + "Apertura della pagina di accesso...", + "Analisi della struttura del modulo...", + "Individuazione dei campi obbligatori...", + ], + loadingAuthSteps: [ + "Inserimento delle credenziali...", + "Invio del modulo di accesso...", + "Verifica dell'autenticazione...", + ], + loadingTimeHint: "Potrebbero volerci 15-30 secondi...", + loginTitle: (site) => `Accedi a ${site}`, + ssoLoginTitle: (provider) => `Accedi con ${provider}`, + ssoLoginSubtitle: (site) => `per ${site}`, + mfaSelectTitle: "Scegli un metodo di verifica", + mfaSelectSubtitle: "Seleziona come vuoi ricevere il codice di verifica", + signInSelectTitle: "Scegli un'opzione", + signInSelectSubtitle: "Seleziona l'opzione con cui continuare", + accountSelectTitle: "Scegli un account", + accountSelectSubtitle: "Seleziona l'account con cui continuare", + submitButton: "Continua", + submittingButton: "Accesso in corso...", + ssoButtonLabel: (provider) => `Accedi con ${provider}`, + orDivider: "oppure", + passwordShow: "Mostra password", + passwordHide: "Nascondi password", + fieldRejectedNotice: + "Il valore salvato è stato rifiutato. Inseriscine uno nuovo per continuare.", + credentialSafetyNotice: + "Le tue credenziali sono crittografate e inviate direttamente dal tuo browser. Non vengono mai condivise con nessuno né con alcun LLM.", + mfaTypeLabels: { + sms: "SMS", + call: "Chiamata", + email: "Email", + totp: "App di autenticazione", + push: "Notifica push", + password: "Password", + passkey: "Passkey", + switch: "Usa un altro metodo", + other: "Altro", + }, + successTitle: "Accesso effettuato", + successDescription: (site) => `Il tuo account ${site} è ora collegato`, + successCloseHint: "Ora puoi chiudere questa finestra", + errorTitle: "Accesso non riuscito", + errorGenericMessage: + "Si è verificato un problema imprevisto durante l'accesso.", + errorCodeLabel: "Codice errore", + errorShowDetails: "Mostra dettagli", + errorHideDetails: "Nascondi dettagli", + errorCloseHint: "Ora puoi chiudere questa finestra", + errorCodeMessages: { + domain_not_allowed: { + title: "Dominio non consentito", + description: + "L'accesso ha reindirizzato a un dominio non configurato. Aggiungilo all'impostazione allowed_domains.", + }, + login_form_not_found: { + title: "Modulo di accesso non trovato", + description: + "Non abbiamo trovato un modulo di accesso in questa pagina. Il sito potrebbe aver cambiato layout, oppure l'URL di accesso potrebbe essere errato.", + }, + credentials_invalid: { + title: "Credenziali non valide", + description: "Il sito non ha accettato il nome utente o la password.", + }, + totp_required: { + title: "Codice di autenticazione richiesto", + description: "È richiesto un codice dell'app di autenticazione.", + }, + sms_code_required: { + title: "Codice SMS richiesto", + description: "È richiesto un codice inviato via SMS.", + }, + email_code_required: { + title: "Codice email richiesto", + description: "È richiesto un codice inviato via email.", + }, + account_choice_required: { + title: "Selezione dell'account richiesta", + description: + "Per continuare l'accesso è necessario selezionare un account o un'identità.", + }, + customer_input_required: { + title: "Informazioni aggiuntive richieste", + description: + "Per continuare l'accesso sono necessarie altre informazioni.", + }, + external_action_required: { + title: "Azione esterna richiesta", + description: + "Per continuare è necessaria un'azione esterna. Controlla l'app di autenticazione, l'email o il telefono per una richiesta di verifica.", + }, + totp_code_rejected: { + title: "Codice di autenticazione rifiutato", + description: + "Il sito ha rifiutato il codice di autenticazione. Prova con un codice nuovo, oppure ricollega l'account se i codici generati continuano a non funzionare anche in intervalli diversi.", + }, + bot_detected: { + title: "Verifica richiesta", + description: + "Questo sito ha rilevato un accesso automatizzato e lo ha bloccato.", + }, + captcha_blocked: { + title: "Verifica richiesta", + description: "Un CAPTCHA ha bloccato l'accesso.", + }, + stuck_in_loop: { + title: "Impossibile completare l'accesso", + description: + "Ci siamo bloccati mentre cercavamo di completare l'accesso. Può succedere con procedure di accesso insolite.", + }, + max_attempts_reached: { + title: "Impossibile completare l'accesso", + description: + "Non siamo riusciti a completare l'accesso dopo diversi tentativi.", + }, + website_error: { + title: "Errore del sito", + description: + "Il sito ha restituito un errore durante l'accesso. Potrebbe avere dei problemi.", + }, + navigation_confused: { + title: "Impossibile completare l'accesso", + description: + "Non siamo riusciti a orientarci in questo sito. A volte succede con procedure di accesso complesse.", + }, + browser_error: { + title: "Errore del browser", + description: "Si è verificato un problema con il browser. Riprova.", + }, + session_expired: { + title: "Sessione scaduta", + description: "La sessione di accesso è scaduta. Ricomincia l'accesso.", + }, + }, + expiredTitle: "Sessione scaduta", + expiredDescription: + "Questa sessione di autenticazione è scaduta. Avvia una nuova sessione.", + externalActionTitle: "Azione richiesta", + externalActionFallbackMessage: "Completa la verifica sul tuo dispositivo", + externalActionWaiting: "In attesa della tua conferma...", + humanInterventionTitle: "Verifica umana richiesta", + humanInterventionMessage: (site) => + `Completa la verifica di ${site} qui sopra, poi continua. Dopo riprenderemo il tuo accesso.`, + humanInterventionDone: "Continua", + humanInterventionLiveViewTitle: "Browser di accesso", + humanInterventionLiveViewUnavailable: + "Il browser di accesso non è disponibile al momento.", + humanInterventionLiveViewFailed: + "Impossibile connettersi al browser di accesso.", + humanInterventionLiveViewGaveUp: + "Impossibile connettersi al browser di accesso. Ricarica la pagina per riprovare.", + humanInterventionLiveViewUnsupported: + "Il tuo browser non può mostrare il browser di accesso. Prova con un altro browser.", + humanInterventionRetry: "Riprova", + poweredBy: "Con tecnologia", +}; diff --git a/packages/managed-auth-react/src/localization/locales/nb.ts b/packages/managed-auth-react/src/localization/locales/nb.ts new file mode 100644 index 0000000..db1a31a --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/nb.ts @@ -0,0 +1,174 @@ +import type { Localizer } from "../types"; + +export const nb: Localizer = { + primeTitle: (site) => `Logg på ${site}`, + primeSubtitle: (site) => + `Skriv inn påloggingsinformasjonen din for ${site} for å fortsette`, + primeContinueButton: "Fortsett", + primeLoadingButton: "Laster inn...", + primeLoadingTitle: "Forbereder sikker pålogging", + primeLoadingSubtitle: "Laster inn tilkoblingsdetaljer...", + securityEncryption: "Påloggingsinformasjonen din er ende-til-ende-kryptert", + securityNoThirdParty: "Deles aldri med noen, heller ikke med en LLM", + legalPrefix: "Ved å fortsette godtar du Kernels", + legalPrivacyPolicy: "personvernerklæring", + legalTermsOfService: "vilkår for bruk", + legalConjunction: "og", + discoveringMessage: "Finner ut hva påloggingen krever...", + waitingForFormMessage: "Venter på påloggingsskjemaet...", + submittingMessage: "Logger på...", + loadingDiscoverySteps: [ + "Går til påloggingssiden...", + "Analyserer skjemaets struktur...", + "Finner obligatoriske felt...", + ], + loadingAuthSteps: [ + "Fyller inn påloggingsinformasjon...", + "Sender påloggingsskjemaet...", + "Bekrefter påloggingen...", + ], + loadingTimeHint: "Dette kan ta 15-30 sekunder...", + loginTitle: (site) => `Logg på ${site}`, + ssoLoginTitle: (provider) => `Logg på med ${provider}`, + ssoLoginSubtitle: (site) => `for ${site}`, + mfaSelectTitle: "Velg bekreftelsesmetode", + mfaSelectSubtitle: "Velg hvordan du vil motta bekreftelseskoden", + signInSelectTitle: "Velg et alternativ", + signInSelectSubtitle: "Velg hvilket alternativ du vil fortsette med", + accountSelectTitle: "Velg en konto", + accountSelectSubtitle: "Velg hvilken konto du vil fortsette med", + submitButton: "Fortsett", + submittingButton: "Logger på...", + ssoButtonLabel: (provider) => `Logg på med ${provider}`, + orDivider: "eller", + passwordShow: "Vis passord", + passwordHide: "Skjul passord", + fieldRejectedNotice: + "Den lagrede verdien ble avvist. Skriv inn en ny for å fortsette.", + credentialSafetyNotice: + "Påloggingsinformasjonen din krypteres og sendes direkte fra nettleseren din. Den deles aldri med noen, heller ikke med en LLM.", + mfaTypeLabels: { + sms: "SMS", + call: "Telefonsamtale", + email: "E-post", + totp: "Autentiseringsapp", + push: "Push-varsel", + password: "Passord", + passkey: "Tilgangsnøkkel", + switch: "Bruk en annen metode", + other: "Annet", + }, + successTitle: "Du er logget på", + successDescription: (site) => `${site}-kontoen din er nå tilkoblet`, + successCloseHint: "Du kan nå lukke dette vinduet", + errorTitle: "Påloggingen mislyktes", + errorGenericMessage: + "Det oppstod et uventet problem da vi prøvde å logge deg på.", + errorCodeLabel: "Feilkode", + errorShowDetails: "Vis detaljer", + errorHideDetails: "Skjul detaljer", + errorCloseHint: "Du kan nå lukke dette vinduet", + errorCodeMessages: { + domain_not_allowed: { + title: "Domenet er ikke tillatt", + description: + "Påloggingen ble videresendt til et domene som ikke er konfigurert. Legg det til i innstillingen allowed_domains.", + }, + login_form_not_found: { + title: "Fant ikke påloggingsskjemaet", + description: + "Vi fant ikke noe påloggingsskjema på denne siden. Nettstedet kan ha endret oppsett, eller påloggingsadressen kan være feil.", + }, + credentials_invalid: { + title: "Ugyldig påloggingsinformasjon", + description: "Nettstedet godtok ikke brukernavnet eller passordet.", + }, + totp_required: { + title: "Autentiseringskode kreves", + description: "Det kreves en kode fra en autentiseringsapp.", + }, + sms_code_required: { + title: "SMS-kode kreves", + description: "Det kreves en kode sendt på SMS.", + }, + email_code_required: { + title: "E-postkode kreves", + description: "Det kreves en kode sendt på e-post.", + }, + account_choice_required: { + title: "Kontovalg kreves", + description: + "En konto eller identitet må velges før påloggingen kan fortsette.", + }, + customer_input_required: { + title: "Mer informasjon kreves", + description: "Det trengs mer informasjon før påloggingen kan fortsette.", + }, + external_action_required: { + title: "Ekstern handling kreves", + description: + "Det kreves en ekstern handling for å fortsette. Sjekk autentiseringsappen, e-posten eller telefonen din for en bekreftelsesforespørsel.", + }, + totp_code_rejected: { + title: "Autentiseringskoden ble avvist", + description: + "Nettstedet avviste autentiseringskoden. Prøv en ny kode, eller koble til kontoen på nytt hvis genererte koder fortsetter å mislykkes i nye tidsvinduer.", + }, + bot_detected: { + title: "Bekreftelse kreves", + description: + "Nettstedet oppdaget automatisert tilgang og blokkerte påloggingen.", + }, + captcha_blocked: { + title: "Bekreftelse kreves", + description: "En CAPTCHA blokkerte påloggingen.", + }, + stuck_in_loop: { + title: "Påloggingen kunne ikke fullføres", + description: + "Vi kom oss ikke videre da vi prøvde å fullføre påloggingen. Dette kan skje med uvanlige påloggingsflyter.", + }, + max_attempts_reached: { + title: "Påloggingen kunne ikke fullføres", + description: "Vi klarte ikke å fullføre påloggingen etter flere forsøk.", + }, + website_error: { + title: "Feil på nettstedet", + description: + "Nettstedet returnerte en feil under påloggingen. Nettstedet kan ha problemer.", + }, + navigation_confused: { + title: "Påloggingen kunne ikke fullføres", + description: + "Vi fant ikke frem på dette nettstedet. Det skjer noen ganger med komplekse påloggingsflyter.", + }, + browser_error: { + title: "Nettleserfeil", + description: "Det oppstod et problem med nettleseren. Prøv igjen.", + }, + session_expired: { + title: "Økten er utløpt", + description: "Påloggingsøkten er utløpt. Start en ny pålogging.", + }, + }, + expiredTitle: "Økten er utløpt", + expiredDescription: "Denne påloggingsøkten er utløpt. Start en ny økt.", + externalActionTitle: "Handling kreves", + externalActionFallbackMessage: "Fullfør bekreftelsen på enheten din", + externalActionWaiting: "Venter på bekreftelsen din...", + humanInterventionTitle: "Menneskelig bekreftelse kreves", + humanInterventionMessage: (site) => + `Fullfør kontrollen på ${site} ovenfor, og fortsett deretter. Vi fortsetter påloggingen etterpå.`, + humanInterventionDone: "Fortsett", + humanInterventionLiveViewTitle: "Påloggingsnettleser", + humanInterventionLiveViewUnavailable: + "Påloggingsnettleseren er ikke tilgjengelig akkurat nå.", + humanInterventionLiveViewFailed: + "Kunne ikke koble til påloggingsnettleseren.", + humanInterventionLiveViewGaveUp: + "Kunne ikke koble til påloggingsnettleseren. Last inn siden på nytt for å prøve igjen.", + humanInterventionLiveViewUnsupported: + "Nettleseren din kan ikke vise påloggingsnettleseren. Prøv en annen nettleser.", + humanInterventionRetry: "Prøv igjen", + poweredBy: "Levert av", +}; diff --git a/packages/managed-auth-react/src/localization/locales/nl.ts b/packages/managed-auth-react/src/localization/locales/nl.ts new file mode 100644 index 0000000..9be7453 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/nl.ts @@ -0,0 +1,179 @@ +import type { Localizer } from "../types"; + +export const nl: Localizer = { + primeTitle: (site) => `Inloggen bij ${site}`, + primeSubtitle: (site) => + `Voer je inloggegevens voor ${site} in om verder te gaan`, + primeContinueButton: "Doorgaan", + primeLoadingButton: "Laden...", + primeLoadingTitle: "Veilig inloggen voorbereiden", + primeLoadingSubtitle: "Verbindingsgegevens laden...", + securityEncryption: "Je inloggegevens zijn end-to-end versleuteld", + securityNoThirdParty: "Nooit gedeeld met iemand of met een LLM", + legalPrefix: "Door verder te gaan, ga je akkoord met het", + legalPrivacyPolicy: "Privacybeleid", + legalTermsOfService: "Servicevoorwaarden van Kernel", + legalConjunction: "en de", + discoveringMessage: "Inlogvereisten bepalen...", + waitingForFormMessage: "Wachten op inlogformulier...", + submittingMessage: "Inloggen...", + loadingDiscoverySteps: [ + "Naar de inlogpagina gaan...", + "Formulierstructuur analyseren...", + "Verplichte velden bepalen...", + ], + loadingAuthSteps: [ + "Inloggegevens invoeren...", + "Inlogformulier verzenden...", + "Authenticatie controleren...", + ], + loadingTimeHint: "Dit kan 15-30 seconden duren...", + loginTitle: (site) => `Inloggen bij ${site}`, + ssoLoginTitle: (provider) => `Inloggen met ${provider}`, + ssoLoginSubtitle: (site) => `voor ${site}`, + mfaSelectTitle: "Kies een verificatiemethode", + mfaSelectSubtitle: "Kies hoe je je verificatiecode wilt ontvangen", + signInSelectTitle: "Kies een optie", + signInSelectSubtitle: "Kies met welke optie je verder wilt gaan", + accountSelectTitle: "Kies een account", + accountSelectSubtitle: "Kies met welk account je verder wilt gaan", + submitButton: "Doorgaan", + submittingButton: "Inloggen...", + ssoButtonLabel: (provider) => `Inloggen met ${provider}`, + orDivider: "of", + passwordShow: "Wachtwoord tonen", + passwordHide: "Wachtwoord verbergen", + fieldRejectedNotice: + "De opgeslagen waarde is geweigerd. Voer een nieuwe in om verder te gaan.", + credentialSafetyNotice: + "Je inloggegevens worden versleuteld en rechtstreeks vanuit je browser verzonden. Ze worden nooit gedeeld met iemand of met een LLM.", + mfaTypeLabels: { + sms: "Sms", + call: "Telefoongesprek", + email: "E-mail", + totp: "Authenticator-app", + push: "Pushmelding", + password: "Wachtwoord", + passkey: "Passkey", + switch: "Andere methode gebruiken", + other: "Overig", + }, + successTitle: "Ingelogd", + successDescription: (site) => `Je ${site}-account is nu gekoppeld`, + successCloseHint: "Je kunt dit venster nu sluiten", + errorTitle: "Inloggen mislukt", + errorGenericMessage: + "Er is een onverwacht probleem opgetreden bij het inloggen.", + errorCodeLabel: "Foutcode", + errorShowDetails: "Details tonen", + errorHideDetails: "Details verbergen", + errorCloseHint: "Je kunt dit venster nu sluiten", + errorCodeMessages: { + domain_not_allowed: { + title: "Domein niet toegestaan", + description: + "Het inloggen is doorgestuurd naar een domein dat niet is geconfigureerd. Voeg het toe aan de instelling allowed_domains.", + }, + login_form_not_found: { + title: "Inlogformulier niet gevonden", + description: + "We konden geen inlogformulier vinden op deze pagina. Mogelijk is de indeling van de website gewijzigd of klopt de inlog-URL niet.", + }, + credentials_invalid: { + title: "Ongeldige inloggegevens", + description: + "De website heeft de gebruikersnaam of het wachtwoord niet geaccepteerd.", + }, + totp_required: { + title: "Authenticatorcode vereist", + description: "Er is een code uit een authenticator-app vereist.", + }, + sms_code_required: { + title: "Sms-code vereist", + description: "Er is een code vereist die per sms is verzonden.", + }, + email_code_required: { + title: "E-mailcode vereist", + description: "Er is een code vereist die per e-mail is verzonden.", + }, + account_choice_required: { + title: "Accountkeuze vereist", + description: + "Er moet een account of identiteit worden gekozen voordat het inloggen verder kan gaan.", + }, + customer_input_required: { + title: "Aanvullende gegevens vereist", + description: + "Er zijn aanvullende gegevens nodig voordat het inloggen verder kan gaan.", + }, + external_action_required: { + title: "Externe actie vereist", + description: + "Er is een externe actie nodig om verder te gaan. Controleer je authenticator-app, e-mail of telefoon op een verificatieverzoek.", + }, + totp_code_rejected: { + title: "Authenticatorcode geweigerd", + description: + "De website heeft de authenticatorcode geweigerd. Probeer een nieuwe code, of koppel het account opnieuw als gegenereerde codes ook in nieuwe tijdvensters blijven mislukken.", + }, + bot_detected: { + title: "Verificatie vereist", + description: + "Deze website heeft geautomatiseerde toegang gedetecteerd en het inloggen geblokkeerd.", + }, + captcha_blocked: { + title: "Verificatie vereist", + description: "Een CAPTCHA heeft het inloggen geblokkeerd.", + }, + stuck_in_loop: { + title: "Inloggen kon niet worden voltooid", + description: + "We liepen vast bij het voltooien van het inloggen. Dit kan gebeuren bij ongebruikelijke inlogprocessen.", + }, + max_attempts_reached: { + title: "Inloggen kon niet worden voltooid", + description: + "Het is ons na meerdere pogingen niet gelukt om in te loggen.", + }, + website_error: { + title: "Websitefout", + description: + "De website gaf een fout tijdens het inloggen. Mogelijk heeft de website problemen.", + }, + navigation_confused: { + title: "Inloggen kon niet worden voltooid", + description: + "We konden onze weg niet vinden op deze website. Dit gebeurt soms bij complexe inlogprocessen.", + }, + browser_error: { + title: "Browserfout", + description: + "Er is een probleem met de browser opgetreden. Probeer het opnieuw.", + }, + session_expired: { + title: "Sessie verlopen", + description: "De inlogsessie is verlopen. Begin opnieuw met inloggen.", + }, + }, + expiredTitle: "Sessie verlopen", + expiredDescription: + "Deze verificatiesessie is verlopen. Start een nieuwe sessie.", + externalActionTitle: "Actie vereist", + externalActionFallbackMessage: "Voltooi de verificatie op je apparaat", + externalActionWaiting: "Wachten op je bevestiging...", + humanInterventionTitle: "Menselijke verificatie vereist", + humanInterventionMessage: (site) => + `Voltooi de controle van ${site} hierboven en ga daarna verder. Daarna gaan we verder met inloggen.`, + humanInterventionDone: "Doorgaan", + humanInterventionLiveViewTitle: "Inlogbrowser", + humanInterventionLiveViewUnavailable: + "De inlogbrowser is op dit moment niet beschikbaar.", + humanInterventionLiveViewFailed: + "Kan geen verbinding maken met de inlogbrowser.", + humanInterventionLiveViewGaveUp: + "Kan geen verbinding maken met de inlogbrowser. Laad deze pagina opnieuw om het nog eens te proberen.", + humanInterventionLiveViewUnsupported: + "Je browser kan de inlogbrowser niet weergeven. Probeer een andere browser.", + humanInterventionRetry: "Opnieuw proberen", + poweredBy: "Mogelijk gemaakt door", +}; diff --git a/packages/managed-auth-react/src/localization/locales/pl.ts b/packages/managed-auth-react/src/localization/locales/pl.ts new file mode 100644 index 0000000..2f0ed22 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/pl.ts @@ -0,0 +1,176 @@ +import type { Localizer } from "../types"; + +export const pl: Localizer = { + primeTitle: (site) => `Zaloguj się do serwisu ${site}`, + primeSubtitle: (site) => + `Podaj dane logowania do serwisu ${site}, aby kontynuować`, + primeContinueButton: "Dalej", + primeLoadingButton: "Ładowanie...", + primeLoadingTitle: "Przygotowywanie bezpiecznego logowania", + primeLoadingSubtitle: "Ładowanie szczegółów połączenia...", + securityEncryption: "Twoje dane logowania są szyfrowane metodą end-to-end", + securityNoThirdParty: "Nigdy nie są nikomu udostępniane, w tym żadnemu LLM", + legalPrefix: "Kontynuując, akceptujesz dokumenty Kernel:", + legalPrivacyPolicy: "Politykę prywatności", + legalTermsOfService: "Warunki korzystania z usługi", + legalConjunction: "oraz", + discoveringMessage: "Ustalanie wymagań logowania...", + waitingForFormMessage: "Oczekiwanie na formularz logowania...", + submittingMessage: "Logowanie...", + loadingDiscoverySteps: [ + "Przechodzenie do strony logowania...", + "Analizowanie struktury formularza...", + "Rozpoznawanie wymaganych pól...", + ], + loadingAuthSteps: [ + "Wpisywanie danych logowania...", + "Wysyłanie formularza logowania...", + "Weryfikowanie logowania...", + ], + loadingTimeHint: "Może to potrwać 15-30 sekund...", + loginTitle: (site) => `Zaloguj się do serwisu ${site}`, + ssoLoginTitle: (provider) => `Zaloguj się przez ${provider}`, + ssoLoginSubtitle: (site) => `w serwisie ${site}`, + mfaSelectTitle: "Wybierz metodę weryfikacji", + mfaSelectSubtitle: "Wybierz, jak chcesz otrzymać kod weryfikacyjny", + signInSelectTitle: "Wybierz opcję", + signInSelectSubtitle: "Wybierz opcję, aby kontynuować", + accountSelectTitle: "Wybierz konto", + accountSelectSubtitle: "Wybierz konto, aby kontynuować", + submitButton: "Dalej", + submittingButton: "Logowanie...", + ssoButtonLabel: (provider) => `Zaloguj się przez ${provider}`, + orDivider: "lub", + passwordShow: "Pokaż hasło", + passwordHide: "Ukryj hasło", + fieldRejectedNotice: + "Zapisana wartość została odrzucona. Wpisz nową, aby kontynuować.", + credentialSafetyNotice: + "Twoje dane logowania są szyfrowane i wysyłane bezpośrednio z Twojej przeglądarki. Nigdy nie są nikomu udostępniane, w tym żadnemu LLM.", + mfaTypeLabels: { + sms: "SMS", + call: "Połączenie telefoniczne", + email: "E-mail", + totp: "Aplikacja uwierzytelniająca", + push: "Powiadomienie push", + password: "Hasło", + passkey: "Klucz dostępu", + switch: "Użyj innej metody", + other: "Inne", + }, + successTitle: "Zalogowano", + successDescription: (site) => + `Twoje konto w serwisie ${site} jest teraz połączone`, + successCloseHint: "Możesz już zamknąć to okno", + errorTitle: "Logowanie nie powiodło się", + errorGenericMessage: "Podczas logowania wystąpił nieoczekiwany problem.", + errorCodeLabel: "Kod błędu", + errorShowDetails: "Pokaż szczegóły", + errorHideDetails: "Ukryj szczegóły", + errorCloseHint: "Możesz już zamknąć to okno", + errorCodeMessages: { + domain_not_allowed: { + title: "Niedozwolona domena", + description: + "Logowanie przekierowało do domeny, która nie jest skonfigurowana. Dodaj ją do ustawienia allowed_domains.", + }, + login_form_not_found: { + title: "Nie znaleziono formularza logowania", + description: + "Na tej stronie nie znaleźliśmy formularza logowania. Układ strony mógł się zmienić albo adres logowania może być nieprawidłowy.", + }, + credentials_invalid: { + title: "Nieprawidłowe dane logowania", + description: "Strona nie zaakceptowała nazwy użytkownika lub hasła.", + }, + totp_required: { + title: "Wymagany kod uwierzytelniający", + description: "Wymagany jest kod z aplikacji uwierzytelniającej.", + }, + sms_code_required: { + title: "Wymagany kod SMS", + description: "Wymagany jest kod wysłany SMS-em.", + }, + email_code_required: { + title: "Wymagany kod z e-maila", + description: "Wymagany jest kod wysłany e-mailem.", + }, + account_choice_required: { + title: "Wymagany wybór konta", + description: + "Przed kontynuowaniem logowania trzeba wybrać konto lub tożsamość.", + }, + customer_input_required: { + title: "Wymagane dodatkowe informacje", + description: + "Przed kontynuowaniem logowania potrzebne są dodatkowe informacje.", + }, + external_action_required: { + title: "Wymagane działanie zewnętrzne", + description: + "Aby kontynuować, wymagane jest działanie zewnętrzne. Sprawdź, czy w aplikacji uwierzytelniającej, poczcie e-mail lub telefonie czeka prośba o weryfikację.", + }, + totp_code_rejected: { + title: "Kod uwierzytelniający odrzucony", + description: + "Strona odrzuciła kod uwierzytelniający. Spróbuj nowego kodu albo połącz konto ponownie, jeśli wygenerowane kody wciąż nie działają w kolejnych przedziałach czasu.", + }, + bot_detected: { + title: "Wymagana weryfikacja", + description: + "Ta strona wykryła automatyczny dostęp i zablokowała logowanie.", + }, + captcha_blocked: { + title: "Wymagana weryfikacja", + description: "Logowanie zostało zablokowane przez CAPTCHA.", + }, + stuck_in_loop: { + title: "Nie udało się dokończyć logowania", + description: + "Utknęliśmy, próbując dokończyć logowanie. Może się to zdarzyć przy nietypowych procesach logowania.", + }, + max_attempts_reached: { + title: "Nie udało się dokończyć logowania", + description: "Nie udało się dokończyć logowania mimo kilku prób.", + }, + website_error: { + title: "Błąd strony", + description: + "Strona zwróciła błąd podczas logowania. Mogą na niej występować problemy.", + }, + navigation_confused: { + title: "Nie udało się dokończyć logowania", + description: + "Nie udało nam się poruszać po tej stronie. Czasem zdarza się to przy złożonych procesach logowania.", + }, + browser_error: { + title: "Błąd przeglądarki", + description: "Wystąpił problem z przeglądarką. Spróbuj ponownie.", + }, + session_expired: { + title: "Sesja wygasła", + description: "Sesja logowania wygasła. Rozpocznij logowanie od nowa.", + }, + }, + expiredTitle: "Sesja wygasła", + expiredDescription: + "Ta sesja uwierzytelniania wygasła. Rozpocznij nową sesję.", + externalActionTitle: "Wymagane działanie", + externalActionFallbackMessage: "Dokończ weryfikację na swoim urządzeniu", + externalActionWaiting: "Oczekiwanie na Twoje potwierdzenie...", + humanInterventionTitle: "Wymagana weryfikacja przez człowieka", + humanInterventionMessage: (site) => + `Dokończ weryfikację w serwisie ${site} powyżej, a następnie kontynuuj. Potem dokończymy logowanie.`, + humanInterventionDone: "Dalej", + humanInterventionLiveViewTitle: "Przeglądarka logowania", + humanInterventionLiveViewUnavailable: + "Przeglądarka logowania jest teraz niedostępna.", + humanInterventionLiveViewFailed: + "Nie udało się połączyć z przeglądarką logowania.", + humanInterventionLiveViewGaveUp: + "Nie udało się połączyć z przeglądarką logowania. Odśwież stronę, aby spróbować ponownie.", + humanInterventionLiveViewUnsupported: + "Twoja przeglądarka nie może wyświetlić przeglądarki logowania. Spróbuj użyć innej przeglądarki.", + humanInterventionRetry: "Spróbuj ponownie", + poweredBy: "Obsługiwane przez", +}; diff --git a/packages/managed-auth-react/src/localization/locales/sv.ts b/packages/managed-auth-react/src/localization/locales/sv.ts new file mode 100644 index 0000000..9fe1647 --- /dev/null +++ b/packages/managed-auth-react/src/localization/locales/sv.ts @@ -0,0 +1,175 @@ +import type { Localizer } from "../types"; + +export const sv: Localizer = { + primeTitle: (site) => `Logga in på ${site}`, + primeSubtitle: (site) => + `Ange dina inloggningsuppgifter för ${site} för att fortsätta`, + primeContinueButton: "Fortsätt", + primeLoadingButton: "Laddar...", + primeLoadingTitle: "Förbereder säker inloggning", + primeLoadingSubtitle: "Laddar anslutningsuppgifter...", + securityEncryption: "Dina inloggningsuppgifter är end-to-end-krypterade", + securityNoThirdParty: "Delas aldrig med någon, inte heller med någon LLM", + legalPrefix: "Genom att fortsätta godkänner du Kernels", + legalPrivacyPolicy: "integritetspolicy", + legalTermsOfService: "användarvillkor", + legalConjunction: "och", + discoveringMessage: "Tar reda på vad inloggningen kräver...", + waitingForFormMessage: "Väntar på inloggningsformuläret...", + submittingMessage: "Loggar in...", + loadingDiscoverySteps: [ + "Går till inloggningssidan...", + "Analyserar formulärets struktur...", + "Identifierar obligatoriska fält...", + ], + loadingAuthSteps: [ + "Fyller i inloggningsuppgifter...", + "Skickar inloggningsformuläret...", + "Verifierar inloggningen...", + ], + loadingTimeHint: "Det kan ta 15-30 sekunder...", + loginTitle: (site) => `Logga in på ${site}`, + ssoLoginTitle: (provider) => `Logga in med ${provider}`, + ssoLoginSubtitle: (site) => `för ${site}`, + mfaSelectTitle: "Välj verifieringsmetod", + mfaSelectSubtitle: "Välj hur du vill få din verifieringskod", + signInSelectTitle: "Välj ett alternativ", + signInSelectSubtitle: "Välj vilket alternativ du vill fortsätta med", + accountSelectTitle: "Välj ett konto", + accountSelectSubtitle: "Välj vilket konto du vill fortsätta med", + submitButton: "Fortsätt", + submittingButton: "Loggar in...", + ssoButtonLabel: (provider) => `Logga in med ${provider}`, + orDivider: "eller", + passwordShow: "Visa lösenord", + passwordHide: "Dölj lösenord", + fieldRejectedNotice: + "Det sparade värdet godkändes inte. Ange ett nytt för att fortsätta.", + credentialSafetyNotice: + "Dina inloggningsuppgifter krypteras och skickas direkt från din webbläsare. De delas aldrig med någon, inte heller med någon LLM.", + mfaTypeLabels: { + sms: "Sms", + call: "Telefonsamtal", + email: "E-post", + totp: "Autentiseringsapp", + push: "Pushnotis", + password: "Lösenord", + passkey: "Lösennyckel", + switch: "Använd en annan metod", + other: "Annat", + }, + successTitle: "Du är inloggad", + successDescription: (site) => `Ditt ${site}-konto är nu anslutet`, + successCloseHint: "Du kan stänga det här fönstret nu", + errorTitle: "Inloggningen misslyckades", + errorGenericMessage: + "Ett oväntat problem uppstod när vi försökte logga in dig.", + errorCodeLabel: "Felkod", + errorShowDetails: "Visa detaljer", + errorHideDetails: "Dölj detaljer", + errorCloseHint: "Du kan stänga det här fönstret nu", + errorCodeMessages: { + domain_not_allowed: { + title: "Domänen är inte tillåten", + description: + "Inloggningen omdirigerades till en domän som inte är konfigurerad. Lägg till den i inställningen allowed_domains.", + }, + login_form_not_found: { + title: "Inloggningsformuläret hittades inte", + description: + "Vi hittade inget inloggningsformulär på den här sidan. Webbplatsen kan ha ändrat layout, eller så kan inloggningsadressen vara fel.", + }, + credentials_invalid: { + title: "Ogiltiga inloggningsuppgifter", + description: "Webbplatsen godkände inte användarnamnet eller lösenordet.", + }, + totp_required: { + title: "Autentiseringskod krävs", + description: "En kod från en autentiseringsapp krävs.", + }, + sms_code_required: { + title: "Sms-kod krävs", + description: "En kod som skickats via sms krävs.", + }, + email_code_required: { + title: "E-postkod krävs", + description: "En kod som skickats via e-post krävs.", + }, + account_choice_required: { + title: "Kontoval krävs", + description: + "Ett konto eller en identitet måste väljas innan inloggningen kan fortsätta.", + }, + customer_input_required: { + title: "Mer information krävs", + description: "Mer information behövs innan inloggningen kan fortsätta.", + }, + external_action_required: { + title: "Extern åtgärd krävs", + description: + "En extern åtgärd krävs för att fortsätta. Se efter om du har fått en verifieringsbegäran i din autentiseringsapp, e-post eller telefon.", + }, + totp_code_rejected: { + title: "Autentiseringskoden godkändes inte", + description: + "Webbplatsen godkände inte autentiseringskoden. Prova en ny kod, eller anslut kontot igen om genererade koder fortsätter att misslyckas i nya tidsintervall.", + }, + bot_detected: { + title: "Verifiering krävs", + description: + "Webbplatsen upptäckte automatiserad åtkomst och blockerade inloggningen.", + }, + captcha_blocked: { + title: "Verifiering krävs", + description: "En CAPTCHA blockerade inloggningen.", + }, + stuck_in_loop: { + title: "Inloggningen kunde inte slutföras", + description: + "Vi fastnade när vi försökte slutföra inloggningen. Det kan hända med ovanliga inloggningsflöden.", + }, + max_attempts_reached: { + title: "Inloggningen kunde inte slutföras", + description: "Vi lyckades inte slutföra inloggningen efter flera försök.", + }, + website_error: { + title: "Fel på webbplatsen", + description: + "Webbplatsen returnerade ett fel under inloggningen. Webbplatsen kan ha problem just nu.", + }, + navigation_confused: { + title: "Inloggningen kunde inte slutföras", + description: + "Vi hittade inte rätt på den här webbplatsen. Det händer ibland med komplexa inloggningsflöden.", + }, + browser_error: { + title: "Webbläsarfel", + description: "Det uppstod ett problem med webbläsaren. Försök igen.", + }, + session_expired: { + title: "Sessionen har gått ut", + description: "Inloggningssessionen har gått ut. Starta en ny inloggning.", + }, + }, + expiredTitle: "Sessionen har gått ut", + expiredDescription: + "Den här inloggningssessionen har gått ut. Starta en ny session.", + externalActionTitle: "Åtgärd krävs", + externalActionFallbackMessage: "Slutför verifieringen på din enhet", + externalActionWaiting: "Väntar på din bekräftelse...", + humanInterventionTitle: "Mänsklig verifiering krävs", + humanInterventionMessage: (site) => + `Slutför kontrollen på ${site} ovan och fortsätt sedan. Vi fortsätter logga in dig efteråt.`, + humanInterventionDone: "Fortsätt", + humanInterventionLiveViewTitle: "Inloggningswebbläsare", + humanInterventionLiveViewUnavailable: + "Inloggningswebbläsaren är inte tillgänglig just nu.", + humanInterventionLiveViewFailed: + "Det gick inte att ansluta till inloggningswebbläsaren.", + humanInterventionLiveViewGaveUp: + "Det gick inte att ansluta till inloggningswebbläsaren. Ladda om sidan för att försöka igen.", + humanInterventionLiveViewUnsupported: + "Din webbläsare kan inte visa inloggningswebbläsaren. Prova en annan webbläsare.", + humanInterventionRetry: "Försök igen", + poweredBy: "Drivs av", +}; diff --git a/packages/managed-auth-react/src/localization/types.ts b/packages/managed-auth-react/src/localization/types.ts index 49edaa1..5cb3fbd 100644 --- a/packages/managed-auth-react/src/localization/types.ts +++ b/packages/managed-auth-react/src/localization/types.ts @@ -56,6 +56,8 @@ export interface Localization { errorShowDetails?: string; errorHideDetails?: string; errorCloseHint?: string; + /** Title and description per server error code. */ + errorCodeMessages?: Partial>; /** Expired step. */ expiredTitle?: string; expiredDescription?: string; @@ -73,6 +75,39 @@ export interface Localization { humanInterventionLiveViewGaveUp?: string; humanInterventionLiveViewUnsupported?: string; humanInterventionRetry?: string; + /** Shell footer. */ + poweredBy?: string; } -export type Localizer = Required; +export interface ErrorCodeMessage { + title: string; + description: string; +} + +/** Server error codes with dedicated copy on the error step. */ +export type ErrorCode = + | "domain_not_allowed" + | "login_form_not_found" + | "credentials_invalid" + | "totp_required" + | "sms_code_required" + | "email_code_required" + | "account_choice_required" + | "customer_input_required" + | "external_action_required" + | "totp_code_rejected" + | "bot_detected" + | "captcha_blocked" + | "stuck_in_loop" + | "max_attempts_reached" + | "website_error" + | "navigation_confused" + | "browser_error" + | "session_expired"; + +export type Localizer = Required< + Omit +> & { + mfaTypeLabels: Record; + errorCodeMessages: Record; +};