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;
+};