fix(i18n): localize security challenge

This commit is contained in:
cesnimda
2026-08-29 23:42:13 +02:00
parent cf6509ce13
commit b0cb28a113
4 changed files with 37 additions and 3 deletions
@@ -1,9 +1,11 @@
import { useEffect, useRef } from "react";
import { Box, Typography } from "@mui/material";
import { useI18n } from "../i18n/I18nProvider";
type Props = { siteKey: string; action: "login" | "register"; onToken: (token: string) => void; };
export default function TurnstileWidget({ siteKey, action, onToken }: Props) {
const { language, t } = useI18n();
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
let widgetId: string | undefined;
@@ -11,7 +13,7 @@ export default function TurnstileWidget({ siteKey, action, onToken }: Props) {
const render = () => {
if (cancelled || !ref.current || !(window as any).turnstile) return;
widgetId = (window as any).turnstile.render(ref.current, {
sitekey: siteKey, action, theme: "auto", size: "flexible",
sitekey: siteKey, action, theme: "auto", size: "flexible", language: language === "nb" ? "nb" : "en",
callback: onToken,
"expired-callback": () => onToken(""),
"error-callback": () => onToken(""),
@@ -28,7 +30,7 @@ export default function TurnstileWidget({ siteKey, action, onToken }: Props) {
document.head.appendChild(script);
}
return () => { cancelled = true; if (widgetId && (window as any).turnstile) (window as any).turnstile.remove(widgetId); };
}, [action, onToken, siteKey]);
}, [action, language, onToken, siteKey]);
return <Box><Typography variant="caption" color="text.secondary">Security check</Typography><Box ref={ref} sx={{ minHeight: 65, mt: 0.5 }} /></Box>;
return <Box><Typography variant="caption" color="text.secondary">{t("securityCheck")}</Typography><Box ref={ref} sx={{ minHeight: 65, mt: 0.5 }} /></Box>;
}
+2
View File
@@ -903,6 +903,7 @@ export const translations = {
proFeatureView: "View Pro",
proFeatureDismiss: "Dismiss {title}",
registrationUnavailable: "Registration is currently unavailable.",
securityCheck: "Security check",
dashboardTotalCount: "{count} total",
jobTableSelectJob: "Select {title}",
characterCount: "{count} characters",
@@ -3215,6 +3216,7 @@ export const translations = {
proFeatureView: "Se Pro",
proFeatureDismiss: "Lukk {title}",
registrationUnavailable: "Registrering er ikke tilgjengelig for øyeblikket.",
securityCheck: "Sikkerhetskontroll",
dashboardTotalCount: "{count} totalt",
jobTableSelectJob: "Velg {title}",
characterCount: "{count} tegn",
@@ -0,0 +1,28 @@
import React from "react";
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import TurnstileWidget from "./components/TurnstileWidget";
import { I18nProvider } from "./i18n/I18nProvider";
beforeEach(() => {
window.localStorage.clear();
(window as any).turnstile = { render: jest.fn(() => "widget-1"), remove: jest.fn() };
});
afterEach(() => {
delete (window as any).turnstile;
});
test("renders the security check and provider widget in Bokmål", () => {
window.localStorage.setItem("uiLanguage", "nb-NO");
render(<I18nProvider><TurnstileWidget siteKey="site-key" action="login" onToken={jest.fn()} /></I18nProvider>);
expect(screen.getByText("Sikkerhetskontroll")).toBeInTheDocument();
expect((window as any).turnstile.render).toHaveBeenCalledWith(expect.any(HTMLElement), expect.objectContaining({
sitekey: "site-key",
action: "login",
language: "nb",
}));
});