diff --git a/web/default/public/locales/en/translation.json b/web/default/public/locales/en/translation.json index f4d74933..fc90bb0e 100644 --- a/web/default/public/locales/en/translation.json +++ b/web/default/public/locales/en/translation.json @@ -429,5 +429,173 @@ "value": "Value" } } + }, + "setting": { + "title": "System Settings", + "tabs": { + "personal": "Personal Settings", + "operation": "Operation Settings", + "system": "System Settings", + "other": "Other Settings" + }, + "personal": { + "general": { + "title": "General Settings", + "system_token_notice": "Note: The token generated here is for system management, not for requesting OpenAI related services.", + "buttons": { + "update_profile": "Update Profile", + "generate_token": "Generate System Token", + "copy_invite": "Copy Invite Link", + "delete_account": "Delete Account" + } + }, + "binding": { + "title": "Account Binding", + "buttons": { + "bind_wechat": "Bind WeChat Account", + "bind_github": "Bind GitHub Account", + "bind_email": "Bind Email Address", + "bind_lark": "Bind Lark Account" + }, + "wechat": { + "title": "WeChat Binding", + "description": "Scan QR code to follow the official account, enter 'verification code' to get the code (valid for 3 minutes)", + "verification_code": "Verification Code", + "bind": "Bind" + }, + "email": { + "title": "Bind Email Address", + "email_placeholder": "Enter email address", + "code_placeholder": "Verification code", + "get_code": "Get Code", + "get_code_retry": "Resend({{countdown}})", + "bind": "Confirm Binding", + "cancel": "Cancel" + } + }, + "delete_account": { + "title": "Dangerous Operation", + "warning": "You are deleting your account. All data will be cleared and cannot be recovered", + "confirm_placeholder": "Enter your username {{username}} to confirm deletion", + "buttons": { + "confirm": "Confirm Delete", + "cancel": "Cancel" + } + } + }, + "system": { + "general": { + "title": "General Settings", + "server_address": "Server Address", + "server_address_placeholder": "e.g.: https://yourdomain.com", + "buttons": { + "update": "Update Server Address" + } + }, + "login": { + "title": "Login & Registration Settings", + "password_login": "Allow Password Login", + "password_register": "Allow Password Registration", + "email_verification": "Require Email Verification for Password Registration", + "github_oauth": "Allow GitHub OAuth Login & Registration", + "wechat_login": "Allow WeChat Login & Registration", + "registration": "Allow New User Registration (When disabled, new users cannot register by any means)", + "turnstile": "Enable Turnstile User Verification" + }, + "email_restriction": { + "title": "Email Domain Whitelist", + "subtitle": "Used to prevent malicious users from batch registering using temporary emails", + "enable": "Enable Email Domain Whitelist", + "allowed_domains": "Allowed Email Domains", + "add_domain": "Add New Allowed Email Domain", + "add_domain_placeholder": "Enter new allowed email domain", + "buttons": { + "fill": "Fill", + "save": "Save Email Domain Whitelist Settings" + } + }, + "smtp": { + "title": "SMTP Configuration", + "subtitle": "Used to support system email sending", + "server": "SMTP Server Address", + "server_placeholder": "e.g.: smtp.gmail.com", + "port": "SMTP Port", + "port_placeholder": "Default: 587", + "account": "SMTP Account", + "account_placeholder": "Usually your email address", + "from": "SMTP Sender Email", + "from_placeholder": "Usually same as email address", + "token": "SMTP Access Token", + "token_placeholder": "Sensitive information will not be sent to frontend", + "buttons": { + "save": "Save SMTP Settings" + } + }, + "github": { + "title": "GitHub OAuth App Configuration", + "subtitle": "Used to support GitHub login and registration", + "manage_link": "Click here", + "manage_text": "to manage your GitHub OAuth Apps", + "url_notice": "Set Homepage URL to {{server_url}}, and Authorization callback URL to {{callback_url}}", + "client_id": "GitHub Client ID", + "client_id_placeholder": "Enter your registered GitHub OAuth APP ID", + "client_secret": "GitHub Client Secret", + "client_secret_placeholder": "Sensitive information will not be sent to frontend", + "buttons": { + "save": "Save GitHub OAuth Settings" + } + }, + "lark": { + "title": "Lark OAuth Configuration", + "subtitle": "Used to support Lark login and registration", + "manage_link": "Click here", + "manage_text": "to manage your Lark applications", + "url_notice": "Set Homepage URL to {{server_url}}, and Redirect URL to {{callback_url}}", + "client_id": "App ID", + "client_id_placeholder": "Enter App ID", + "client_secret": "App Secret", + "client_secret_placeholder": "Sensitive information will not be sent to frontend", + "buttons": { + "save": "Save Lark OAuth Settings" + } + }, + "wechat": { + "title": "WeChat Server Configuration", + "subtitle": "Used to support WeChat login and registration", + "learn_more": "Learn about WeChat Server", + "server_address": "WeChat Server Address", + "server_address_placeholder": "e.g.: https://yourdomain.com", + "token": "WeChat Server Access Token", + "token_placeholder": "Sensitive information will not be sent to frontend", + "qrcode": "WeChat Official Account QR Code Image URL", + "qrcode_placeholder": "Enter an image URL", + "buttons": { + "save": "Save WeChat Server Settings" + } + }, + "turnstile": { + "title": "Turnstile Configuration", + "subtitle": "Used to support user verification", + "manage_link": "Click here", + "manage_text": "to manage your Turnstile Sites, Invisible Widget Type recommended", + "site_key": "Turnstile Site Key", + "site_key_placeholder": "Enter your registered Turnstile Site Key", + "secret_key": "Turnstile Secret Key", + "secret_key_placeholder": "Sensitive information will not be sent to frontend", + "buttons": { + "save": "Save Turnstile Settings" + } + }, + "password_login": { + "warning": { + "title": "Warning", + "content": "Disabling password login will prevent all users (including administrators) who haven't bound other login methods from logging in via password. Confirm disable?", + "buttons": { + "confirm": "Confirm", + "cancel": "Cancel" + } + } + } + } } } diff --git a/web/default/public/locales/zh/translation.json b/web/default/public/locales/zh/translation.json index d3b80c26..ea38680c 100644 --- a/web/default/public/locales/zh/translation.json +++ b/web/default/public/locales/zh/translation.json @@ -429,5 +429,173 @@ "value": "数值" } } + }, + "setting": { + "title": "系统设置", + "tabs": { + "personal": "个人设置", + "operation": "运营设置", + "system": "系统设置", + "other": "其他设置" + }, + "personal": { + "general": { + "title": "通用设置", + "system_token_notice": "注意,此处生成的令牌用于系统管理,而非用于请求 OpenAI 相关的服务,请知悉。", + "buttons": { + "update_profile": "更新个人信息", + "generate_token": "生成系统访问令牌", + "copy_invite": "复制邀请链接", + "delete_account": "删除个人账户" + } + }, + "binding": { + "title": "账号绑定", + "buttons": { + "bind_wechat": "绑定微信账号", + "bind_github": "绑定 GitHub 账号", + "bind_email": "绑定邮箱地址", + "bind_lark": "绑定飞书账号" + }, + "wechat": { + "title": "微信绑定", + "description": "微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)", + "verification_code": "验证码", + "bind": "绑定" + }, + "email": { + "title": "绑定邮箱地址", + "email_placeholder": "输入邮箱地址", + "code_placeholder": "验证码", + "get_code": "获取验证码", + "get_code_retry": "重新发送({{countdown}})", + "bind": "确认绑定", + "cancel": "取消" + } + }, + "delete_account": { + "title": "危险操作", + "warning": "您正在删除自己的帐户,将清空所有数据且不可恢复", + "confirm_placeholder": "输入你的账户名 {{username}} 以确认删除", + "buttons": { + "confirm": "确认删除", + "cancel": "取消" + } + } + }, + "system": { + "general": { + "title": "通用设置", + "server_address": "服务器地址", + "server_address_placeholder": "例如:https://yourdomain.com", + "buttons": { + "update": "更新服务器地址" + } + }, + "login": { + "title": "配置登录注册", + "password_login": "允许通过密码进行登录", + "password_register": "允许通过密码进行注册", + "email_verification": "通过密码注册时需要进行邮箱验证", + "github_oauth": "允许通过 GitHub 账户登录 & 注册", + "wechat_login": "允许通过微信登录 & 注册", + "registration": "允许新用户注册(此项为否时,新用户将无法以任何方式进行注册)", + "turnstile": "启用 Turnstile 用户校验" + }, + "email_restriction": { + "title": "配置邮箱域名白名单", + "subtitle": "用以防止恶意用户利用临时邮箱批量注册", + "enable": "启用邮箱域名白名单", + "allowed_domains": "允许的邮箱域名", + "add_domain": "添加新的允许的邮箱域名", + "add_domain_placeholder": "输入新的允许的邮箱域名", + "buttons": { + "fill": "填入", + "save": "保存邮箱域名白名单设置" + } + }, + "smtp": { + "title": "配置 SMTP", + "subtitle": "用以支持系统的邮件发送", + "server": "SMTP 服务器地址", + "server_placeholder": "例如:smtp.qq.com", + "port": "SMTP 端口", + "port_placeholder": "默认: 587", + "account": "SMTP 账户", + "account_placeholder": "通常是邮箱地址", + "from": "SMTP 发送者邮箱", + "from_placeholder": "通常和邮箱地址保持一致", + "token": "SMTP 访问凭证", + "token_placeholder": "敏感信息不会发送到前端显示", + "buttons": { + "save": "保存 SMTP 设置" + } + }, + "github": { + "title": "配置 GitHub OAuth App", + "subtitle": "用以支持通过 GitHub 进行登录注册", + "manage_link": "点击此处", + "manage_text": "管理你的 GitHub OAuth App", + "url_notice": "Homepage URL 填 {{server_url}},Authorization callback URL 填 {{callback_url}}", + "client_id": "GitHub Client ID", + "client_id_placeholder": "输入你注册的 GitHub OAuth APP 的 ID", + "client_secret": "GitHub Client Secret", + "client_secret_placeholder": "敏感信息不会发送到前端显示", + "buttons": { + "save": "保存 GitHub OAuth 设置" + } + }, + "lark": { + "title": "配置飞书授权登录", + "subtitle": "用以支持通过飞书进行登录注册", + "manage_link": "点击此处", + "manage_text": "管理你的飞书应用", + "url_notice": "主页链接填 {{server_url}},重定向 URL 填 {{callback_url}}", + "client_id": "App ID", + "client_id_placeholder": "输入 App ID", + "client_secret": "App Secret", + "client_secret_placeholder": "敏感信息不会发送到前端显示", + "buttons": { + "save": "保存飞书 OAuth 设置" + } + }, + "wechat": { + "title": "配置 WeChat Server", + "subtitle": "用以支持通过微信进行登录注册", + "learn_more": "了解 WeChat Server", + "server_address": "WeChat Server 服务器地址", + "server_address_placeholder": "例如:https://yourdomain.com", + "token": "WeChat Server 访问凭证", + "token_placeholder": "敏感信息不会发送到前端显示", + "qrcode": "微信公众号二维码图片链接", + "qrcode_placeholder": "输入一个图片链接", + "buttons": { + "save": "保存 WeChat Server 设置" + } + }, + "turnstile": { + "title": "配置 Turnstile", + "subtitle": "用以支持用户校验", + "manage_link": "点击此处", + "manage_text": "管理你的 Turnstile Sites,推荐选择 Invisible Widget Type", + "site_key": "Turnstile Site Key", + "site_key_placeholder": "输入你注册的 Turnstile Site Key", + "secret_key": "Turnstile Secret Key", + "secret_key_placeholder": "敏感信息不会发送到前端显示", + "buttons": { + "save": "保存 Turnstile 设置" + } + }, + "password_login": { + "warning": { + "title": "警告", + "content": "取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?", + "buttons": { + "confirm": "确定", + "cancel": "取消" + } + } + } + } } } diff --git a/web/default/src/components/PersonalSetting.js b/web/default/src/components/PersonalSetting.js index 0c968462..d60b6bb0 100644 --- a/web/default/src/components/PersonalSetting.js +++ b/web/default/src/components/PersonalSetting.js @@ -1,4 +1,5 @@ import React, { useContext, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Button, Divider, Form, Header, Image, Message, Modal } from 'semantic-ui-react'; import { Link, useNavigate } from 'react-router-dom'; import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers'; @@ -7,6 +8,7 @@ import { UserContext } from '../context/User'; import { onGitHubOAuthClicked, onLarkOAuthClicked } from './utils'; const PersonalSetting = () => { + const { t } = useTranslation(); const [userState, userDispatch] = useContext(UserContext); let navigate = useNavigate(); @@ -169,18 +171,24 @@ const PersonalSetting = () => { return (
-
通用设置
+
{t('setting.personal.general.title')}
- 注意,此处生成的令牌用于系统管理,而非用于请求 OpenAI 相关的服务,请知悉。 + {t('setting.personal.general.system_token_notice')} + + - - + }}> + {t('setting.personal.general.buttons.delete_account')} + {systemToken && ( { /> )} -
账号绑定
- { - status.wechat_login && ( - - ) - } +
{t('setting.personal.binding.title')}
+ {status.wechat_login && ( + + )} setShowWeChatBindModal(false)} onOpen={() => setShowWeChatBindModal(true)} @@ -223,41 +225,35 @@ const PersonalSetting = () => {
-

- 微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效) -

+

{t('setting.personal.binding.wechat.description')}

- { - status.github_oauth && ( - - ) - } - { - status.lark_client_id && ( - - ) - } - + )} + {status.lark_client_id && ( + + )} + setShowEmailBindModal(false)} @@ -266,57 +262,57 @@ const PersonalSetting = () => { size={'tiny'} style={{ maxWidth: '450px' }} > - 绑定邮箱地址 + {t('setting.personal.binding.email.title')}
- {disableButton ? `重新发送(${countdown})` : '获取验证码'} + {disableButton + ? t('setting.personal.binding.email.get_code_retry', { countdown }) + : t('setting.personal.binding.email.get_code')} } /> - {turnstileEnabled ? ( + {turnstileEnabled && ( { setTurnstileToken(token); }} /> - ) : ( - <> )}
- -
- + +
+
@@ -329,27 +325,27 @@ const PersonalSetting = () => { size={'tiny'} style={{ maxWidth: '450px' }} > - 危险操作 + {t('setting.personal.delete_account.title')} - 您正在删除自己的帐户,将清空所有数据且不可恢复 + {t('setting.personal.delete_account.warning')}
- {turnstileEnabled ? ( + {turnstileEnabled && ( { setTurnstileToken(token); }} /> - ) : ( - <> )}
diff --git a/web/default/src/components/SystemSetting.js b/web/default/src/components/SystemSetting.js index 7eeae92e..69bb3057 100644 --- a/web/default/src/components/SystemSetting.js +++ b/web/default/src/components/SystemSetting.js @@ -1,8 +1,10 @@ import React, { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Button, Divider, Form, Grid, Header, Modal, Message } from 'semantic-ui-react'; import { API, removeTrailingSlash, showError } from '../helpers'; const SystemSetting = () => { + const { t } = useTranslation(); let [inputs, setInputs] = useState({ PasswordLoginEnabled: '', PasswordRegisterEnabled: '', @@ -260,42 +262,43 @@ const SystemSetting = () => {
-
通用设置
+
{t('setting.system.general.title')}
- 更新服务器地址 + {t('setting.system.general.buttons.update')} -
配置登录注册
+
{t('setting.system.login.title')}
- { - showPasswordWarningModal && + {showPasswordWarningModal && ( setShowPasswordWarningModal(false)} size={'tiny'} style={{ maxWidth: '450px' }} > - 警告 + {t('setting.system.password_login.warning.title')} -

取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?

+

{t('setting.system.password_login.warning.content')}

- +
- } + )} @@ -336,304 +339,283 @@ const SystemSetting = () => { -
- 配置邮箱域名白名单 - 用以防止恶意用户利用临时邮箱批量注册 -
- +
{t('setting.system.email_restriction.title')}
+ {t('setting.system.email_restriction.subtitle')} + - - + { - submitNewRestrictedDomain(); - }}>填入 - } - onKeyDown={(e) => { - if (e.key === 'Enter') { - submitNewRestrictedDomain(); - } - }} - autoComplete='new-password' - placeholder='输入新的允许的邮箱域名' + label={t('setting.system.email_restriction.add_domain')} + placeholder={t('setting.system.email_restriction.add_domain_placeholder')} value={restrictedDomainInput} onChange={(e, { value }) => { setRestrictedDomainInput(value); }} + action={ + + } /> - 保存邮箱域名白名单设置 + item.value)} + options={EmailDomainWhitelist} + onAddItem={(e, { value }) => { + setEmailDomainWhitelist([...EmailDomainWhitelist, { + key: value, + text: value, + value: value + }]); + }} + onChange={(e, { value }) => { + let newEmailDomainWhitelist = []; + value.forEach((item) => { + newEmailDomainWhitelist.push({ + key: item, + text: item, + value: item + }); + }); + setEmailDomainWhitelist(newEmailDomainWhitelist); + }} + /> + + {t('setting.system.email_restriction.buttons.save')} + + -
- 配置 SMTP - 用以支持系统的邮件发送 -
+
{t('setting.system.smtp.title')}
+ {t('setting.system.smtp.subtitle')} - 保存 SMTP 设置 + + {t('setting.system.smtp.buttons.save')} + + -
- 配置 GitHub OAuth App - - 用以支持通过 GitHub 进行登录注册, - - 点击此处 - - 管理你的 GitHub OAuth App - -
+
{t('setting.system.github.title')}
- Homepage URL 填 {inputs.ServerAddress} - ,Authorization callback URL 填{' '} - {`${inputs.ServerAddress}/oauth/github`} + {t('setting.system.github.subtitle')} + + {t('setting.system.github.manage_link')} + + {t('setting.system.github.manage_text')} + + + {t('setting.system.github.url_notice', { + server_url: originInputs.ServerAddress, + callback_url: `${originInputs.ServerAddress}/oauth/github` + })} - 保存 GitHub OAuth 设置 + {t('setting.system.github.buttons.save')} +
- 配置飞书授权登录 + {t('setting.system.lark.title')} - 用以支持通过飞书进行登录注册, + {t('setting.system.lark.subtitle')} - 点击此处 + {t('setting.system.lark.manage_link')} - 管理你的飞书应用 + {t('setting.system.lark.manage_text')}
- 主页链接填 {inputs.ServerAddress} - ,重定向 URL 填{' '} - {`${inputs.ServerAddress}/oauth/lark`} + {t('setting.system.lark.url_notice', { + server_url: inputs.ServerAddress, + callback_url: `${inputs.ServerAddress}/oauth/lark` + })} - 保存飞书 OAuth 设置 + {t('setting.system.lark.buttons.save')} +
- 配置 WeChat Server + {t('setting.system.wechat.title')} - 用以支持通过微信进行登录注册, + {t('setting.system.wechat.subtitle')} - 点击此处 + {t('setting.system.wechat.learn_more')} - 了解 WeChat Server
- 保存 WeChat Server 设置 + {t('setting.system.wechat.buttons.save')} +
- 配置 Message Pusher + {t('setting.system.turnstile.title')} - 用以推送报警信息, - - 点击此处 - - 了解 Message Pusher - -
- - - - - - 保存 Message Pusher 设置 - - -
- 配置 Turnstile - - 用以支持用户校验, + {t('setting.system.turnstile.subtitle')} - 点击此处 + {t('setting.system.turnstile.manage_link')} - 管理你的 Turnstile Sites,推荐选择 Invisible Widget Type + {t('setting.system.turnstile.manage_text')}
- 保存 Turnstile 设置 + {t('setting.system.turnstile.buttons.save')}
diff --git a/web/default/src/pages/Setting/index.js b/web/default/src/pages/Setting/index.js index d33b0903..52c438f3 100644 --- a/web/default/src/pages/Setting/index.js +++ b/web/default/src/pages/Setting/index.js @@ -1,4 +1,5 @@ import React from 'react'; +import { useTranslation } from 'react-i18next'; import { Card, Tab } from 'semantic-ui-react'; import SystemSetting from '../../components/SystemSetting'; import { isRoot } from '../../helpers'; @@ -7,9 +8,11 @@ import PersonalSetting from '../../components/PersonalSetting'; import OperationSetting from '../../components/OperationSetting'; const Setting = () => { + const { t } = useTranslation(); + let panes = [ { - menuItem: '个人设置', + menuItem: t('setting.tabs.personal'), render: () => ( @@ -20,7 +23,7 @@ const Setting = () => { if (isRoot()) { panes.push({ - menuItem: '运营设置', + menuItem: t('setting.tabs.operation'), render: () => ( @@ -28,7 +31,7 @@ const Setting = () => { ), }); panes.push({ - menuItem: '系统设置', + menuItem: t('setting.tabs.system'), render: () => ( @@ -36,7 +39,7 @@ const Setting = () => { ), }); panes.push({ - menuItem: '其他设置', + menuItem: t('setting.tabs.other'), render: () => ( @@ -49,12 +52,12 @@ const Setting = () => {
- 系统设置 + {t('setting.title')}