From 52af5c467c3c3639ed3ced231745f3f51cc6da4e Mon Sep 17 00:00:00 2001 From: WittF Date: Fri, 20 Jun 2025 14:03:03 +0800 Subject: [PATCH] feat(captcha): add i18n support for Cap Captcha (#263) --- public/locales/en-US/common.json | 7 +++++++ public/locales/ja-JP/common.json | 7 +++++++ public/locales/zh-CN/common.json | 7 +++++++ public/locales/zh-TW/common.json | 7 +++++++ src/component/Common/Captcha/CapCaptcha.tsx | 11 +++++++++-- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/public/locales/en-US/common.json b/public/locales/en-US/common.json index da1bbb2..1c72b22 100644 --- a/public/locales/en-US/common.json +++ b/public/locales/en-US/common.json @@ -28,6 +28,13 @@ "rowsPerPage": "Rows per page", "custom": "Custom", "enter": "Enter", + "captcha": { + "cap": { + "human": "I'm a human", + "verifying": "Verifying...", + "verified": "You're a human" + } + }, "errors": { "401": "Please login.", "403": "You are not allowed to perform this action.", diff --git a/public/locales/ja-JP/common.json b/public/locales/ja-JP/common.json index 4d12cf6..d233e54 100644 --- a/public/locales/ja-JP/common.json +++ b/public/locales/ja-JP/common.json @@ -28,6 +28,13 @@ "rowsPerPage": "1ページあたりの行数", "custom": "カスタム", "enter": "入力", + "captcha": { + "cap": { + "human": "私は人間です", + "verifying": "検証中…", + "verified": "検証が完了しました" + } + }, "errors": { "401": "ログインしてください", "403": "この操作を実行する権限がありません", diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json index 0452017..010b2bf 100644 --- a/public/locales/zh-CN/common.json +++ b/public/locales/zh-CN/common.json @@ -28,6 +28,13 @@ "rowsPerPage": "每页行数", "custom": "自定义", "enter": "输入", + "captcha": { + "cap": { + "human": "我是人类", + "verifying": "验证中…", + "verified": "您通过了验证" + } + }, "errors": { "401": "请先登录", "403": "你没有权限执行此操作", diff --git a/public/locales/zh-TW/common.json b/public/locales/zh-TW/common.json index aad1ec3..0863347 100644 --- a/public/locales/zh-TW/common.json +++ b/public/locales/zh-TW/common.json @@ -28,6 +28,13 @@ "rowsPerPage": "每頁行數", "custom": "自定義", "enter": "輸入", + "captcha": { + "cap": { + "human": "我是人類", + "verifying": "驗證中…", + "verified": "您已通過驗證" + } + }, "errors": { "401": "請先登入", "403": "你沒有許可權執行此操作", diff --git a/src/component/Common/Captcha/CapCaptcha.tsx b/src/component/Common/Captcha/CapCaptcha.tsx index c3894da..82099f6 100644 --- a/src/component/Common/Captcha/CapCaptcha.tsx +++ b/src/component/Common/Captcha/CapCaptcha.tsx @@ -1,4 +1,5 @@ import React, { useEffect, useRef } from "react"; +import { useTranslation } from "react-i18next"; import { useAppSelector } from "../../../redux/hooks.ts"; import { CaptchaParams } from "./Captcha.tsx"; import { Box, useTheme } from "@mui/material"; @@ -17,6 +18,7 @@ const CapCaptcha = ({ onStateChange, generation, fullWidth, ...rest }: CapProps const onStateChangeRef = useRef(onStateChange); const scriptLoadedRef = useRef(false); const theme = useTheme(); + const { t } = useTranslation("common"); const capInstanceURL = useAppSelector( (state) => state.siteConfig.basic.config.captcha_cap_instance_url, @@ -92,6 +94,11 @@ const CapCaptcha = ({ onStateChange, generation, fullWidth, ...rest }: CapProps widget.setAttribute("data-cap-api-endpoint", `${capInstanceURL.replace(/\/$/, "")}/${capKeyID}/api/`); widget.id = "cap-widget"; + // Set internationalization attributes (Cap official i18n format) + widget.setAttribute("data-cap-i18n-initial-state", t("captcha.cap.human")); + widget.setAttribute("data-cap-i18n-verifying-label", t("captcha.cap.verifying")); + widget.setAttribute("data-cap-i18n-solved-label", t("captcha.cap.verified")); + captchaRef.current.appendChild(widget); widget.addEventListener("solve", (e: any) => { @@ -114,7 +121,7 @@ const CapCaptcha = ({ onStateChange, generation, fullWidth, ...rest }: CapProps if (generation > 0) { createWidget(); } - }, [generation]); + }, [generation, t]); useEffect(() => { if (!capInstanceURL || !capKeyID) { @@ -160,7 +167,7 @@ const CapCaptcha = ({ onStateChange, generation, fullWidth, ...rest }: CapProps captchaRef.current.innerHTML = ""; } }; - }, [capInstanceURL, capKeyID]); + }, [capInstanceURL, capKeyID, t]); if (!capInstanceURL || !capKeyID) { return null;