From cd21aa1c56396d780edf5cae8089605ccd323c0f Mon Sep 17 00:00:00 2001 From: CalciumIon <1808837298@qq.com> Date: Thu, 12 Dec 2024 23:32:55 +0800 Subject: [PATCH 1/2] feat: init i18n --- web/package.json | 5 +- web/pnpm-lock.yaml | 58 ++ web/src/i18n/i18n.js | 22 + web/src/i18n/locales/en.json | 1183 ++++++++++++++++++++++++++++++++++ web/src/index.js | 1 + web/vite.config.js | 2 + 6 files changed, 1270 insertions(+), 1 deletion(-) create mode 100644 web/src/i18n/i18n.js create mode 100644 web/src/i18n/locales/en.json diff --git a/web/package.json b/web/package.json index 7c32b5d9..edb0ccf5 100644 --- a/web/package.json +++ b/web/package.json @@ -23,7 +23,10 @@ "react-turnstile": "^1.0.5", "semantic-ui-offline": "^2.5.0", "semantic-ui-react": "^2.1.3", - "sse": "github:mpetazzoni/sse.js" + "sse": "github:mpetazzoni/sse.js", + "i18next": "^23.16.8", + "react-i18next": "^13.0.0", + "i18next-browser-languagedetector": "^7.2.0" }, "scripts": { "dev": "vite", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 852b35d0..5da07e60 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -32,6 +32,12 @@ importers: history: specifier: ^5.3.0 version: 5.3.0 + i18next: + specifier: ^23.16.8 + version: 23.16.8 + i18next-browser-languagedetector: + specifier: ^7.2.0 + version: 7.2.2 marked: specifier: ^4.1.1 version: 4.3.0 @@ -47,6 +53,9 @@ importers: react-fireworks: specifier: ^1.0.4 version: 1.0.4 + react-i18next: + specifier: ^13.0.0 + version: 13.5.0(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-router-dom: specifier: ^6.3.0 version: 6.28.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1071,6 +1080,15 @@ packages: history@5.3.0: resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==} + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + + i18next-browser-languagedetector@7.2.2: + resolution: {integrity: sha512-6b7r75uIJDWCcCflmbof+sJ94k9UQO4X0YR62oUfqGI/GjCLVzlCwu8TFdRZIqVLzWbzNcmkmhfqKEr4TLz4HQ==} + + i18next@23.16.8: + resolution: {integrity: sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -1487,6 +1505,19 @@ packages: react-fireworks@1.0.4: resolution: {integrity: sha512-jj1a+HTicB4pR6g2lqhVyAox0GTE0TOrZK2XaJFRYOwltgQWeYErZxnvU9+zH/blY+Hpmu9IKyb39OD3KcCMJw==} + react-i18next@13.5.0: + resolution: {integrity: sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==} + peerDependencies: + i18next: '>= 23.2.3' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -1812,6 +1843,10 @@ packages: terser: optional: true + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} @@ -2935,6 +2970,18 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + + i18next-browser-languagedetector@7.2.2: + dependencies: + '@babel/runtime': 7.26.0 + + i18next@23.16.8: + dependencies: + '@babel/runtime': 7.26.0 + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -3611,6 +3658,15 @@ snapshots: react-fireworks@1.0.4: {} + react-i18next@13.5.0(i18next@23.16.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@babel/runtime': 7.26.0 + html-parse-stringify: 3.0.1 + i18next: 23.16.8 + react: 18.3.1 + optionalDependencies: + react-dom: 18.3.1(react@18.3.1) + react-is@16.13.1: {} react-is@18.3.1: {} @@ -3998,6 +4054,8 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + void-elements@3.1.0: {} + warning@4.0.3: dependencies: loose-envify: 1.4.0 diff --git a/web/src/i18n/i18n.js b/web/src/i18n/i18n.js new file mode 100644 index 00000000..1c26fa4c --- /dev/null +++ b/web/src/i18n/i18n.js @@ -0,0 +1,22 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; + +import enTranslation from './locales/en.json'; + +i18n + .use(LanguageDetector) + .use(initReactI18next) + .init({ + resources: { + en: { + translation: enTranslation + } + }, + fallbackLng: 'en', + interpolation: { + escapeValue: false + } + }); + +export default i18n; \ No newline at end of file diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json new file mode 100644 index 00000000..921c2252 --- /dev/null +++ b/web/src/i18n/locales/en.json @@ -0,0 +1,1183 @@ +{ + "主页": "Home", + "$%.6f 额度": "$%.6f quota", + "%d 点额度": "%d point quota", + "尚未实现": "Not yet implemented", + "余额不足": "Insufficient balance", + "危险操作": "Hazardous operations", + "输入你的账户名": "Enter your account name", + "确认删除": "Confirm Delete", + "确认绑定": "Confirm Binding", + "您正在删除自己的帐户,将清空所有数据且不可恢复": "You are deleting your account, all data will be cleared and unrecoverable.", + "通道「%s」(#%d)已被禁用": "Channel %s (#%d) has been disabled", + "通道「%s」(#%d)已被禁用,原因:%s": "Channel %s (#%d) has been disabled, reason: %s", + "测试已在运行中": "Test is already running", + "响应时间 %.2fs 超过阈值 %.2fs": "Response time %.2fs exceeds threshold %.2fs", + "通道测试完成": "Channel test completed", + "通道测试完成,如果没有收到禁用通知,说明所有通道都正常": "Channel test completed, if you have not received the disable notification, it means that all channels are normal", + "无法连接至 GitHub 服务器,请稍后重试!": "Unable to connect to GitHub server, please try again later!", + "返回值非法,用户字段为空,请稍后重试!": "The return value is illegal, the user field is empty, please try again later!", + "管理员未开启通过 GitHub 登录以及注册": "The administrator did not turn on login and registration via GitHub", + "管理员关闭了新用户注册": "The administrator has turned off new user registration", + "用户已被封禁": "User has been banned", + "该 GitHub 账户已被绑定": "The GitHub account has been bound", + "邮箱地址已被占用": "Email address is occupied", + "%s邮箱验证邮件": "%s Email verification email", + "
您好,你正在进行%s邮箱验证。
": "Hello, you are verifying %s email.
", + "您的验证码为: %s
": "Your verification code is: %s
", + "验证码 %d 分钟内有效,如果不是本人操作,请忽略。
": "The verification code is valid within %d minutes. If it is not your operation, please ignore it.
", + "无效的参数": "Invalid parameter", + "该邮箱地址未注册": "The email address is not registered", + "%s密码重置": "%s Password reset", + "您好,你正在进行%s密码重置。
": "Hello, you are resetting %s password.
", + "点击此处进行密码重置。
": "Click here to reset your password.
", + "重置链接 %d 分钟内有效,如果不是本人操作,请忽略。
": "The reset link is valid within %d minutes. If it is not your operation, please ignore it.
", + "重置链接非法或已过期": "Reset link is illegal or expired", + "无法启用 GitHub OAuth,请先填入 GitHub Client ID 以及 GitHub Client Secret!": "Unable to enable GitHub OAuth, please fill in GitHub Client ID and GitHub Client Secret first!", + "无法启用微信登录,请先填入微信登录相关配置信息!": "Unable to enable WeChat login, please fill in the relevant configuration information for WeChat login first!", + "无法启用 Turnstile 校验,请先填入 Turnstile 校验相关配置信息!": "Unable to enable Turnstile verification, please fill in the relevant configuration information for Turnstile verification first!", + "兑换码名称长度必须在1-20之间": "The length of the redemption code name must be between 1-20", + "兑换码个数必须大于0": "The number of redemption codes must be greater than 0", + "一次兑换码批量生成的个数不能大于 100": "The number of redemption codes generated in a batch cannot be greater than 100", + "通过令牌「%s」使用模型 %s 消耗 %s(模型倍率 %.2f,分组折扣 %.2f)": "Using model %s with token %s consumes %s (model rate %.2f, group rate %.2f)", + "当前分组上游负载已饱和,请稍后再试": "The current group load is saturated, please try again later", + "令牌名称过长": "Token name is too long", + "令牌已过期,无法启用,请先修改令牌过期时间,或者设置为永不过期": "The token has expired and cannot be enabled. Please modify the expiration time of the token, or set it to never expire.", + "令牌可用额度已用尽,无法启用,请先修改令牌剩余额度,或者设置为无限额度": "The available quota of the token has been used up and cannot be enabled. Please modify the remaining quota of the token, or set it to unlimited quota", + "管理员关闭了密码登录": "The administrator has turned off password login", + "无法保存会话信息,请重试": "Unable to save session information, please try again", + "管理员关闭了通过密码进行注册,请使用第三方账户验证的形式进行注册": "The administrator has turned off registration via password. Please use the form of third-party account verification to register", + "输入不合法 ": "Input is illegal ", + "管理员开启了邮箱验证,请输入邮箱地址和验证码": "The administrator has turned on email verification, please enter the email address and verification code", + "验证码错误或已过期": "Verification code error or expired", + "无权获取同级或更高等级用户的信息": "No permission to get information of users at the same level or higher", + "请重试,系统生成的 UUID 竟然重复了!": "Please try again, the system-generated UUID is actually duplicated!", + "输入不合法": "Input is illegal", + "无权更新同权限等级或更高权限等级的用户信息": "No permission to update user information with the same permission level or higher permission level", + "管理员将用户额度从 %s修改为 %s": "The administrator changed the user quota from %s to %s", + "无权删除同权限等级或更高权限等级的用户": "No permission to delete users with the same permission level or higher permission level", + "无法创建权限大于等于自己的用户": "Unable to create users with permissions greater than or equal to your own", + "用户不存在": "User does not exist", + "无法禁用超级管理员用户": "Unable to disable super administrator user", + "无法删除超级管理员用户": "Unable to delete super administrator user", + "普通管理员用户无法提升其他用户为管理员": "Ordinary administrator users cannot promote other users to administrators", + "该用户已经是管理员": "The user is already an administrator", + "无法降级超级管理员用户": "Unable to downgrade super administrator user", + "该用户已经是普通用户": "The user is already an ordinary user", + "管理员未开启通过微信登录以及注册": "The administrator has not enabled login and registration via WeChat", + "该微信账号已被绑定": "The WeChat account has been bound", + "无权进行此操作,未登录且未提供 access token": "No permission to perform this operation, not logged in and no access token provided", + "无权进行此操作,access token 无效": "No permission to perform this operation, access token is invalid", + "无权进行此操作,权限不足": "No permission to perform this operation, insufficient permissions", + "普通用户不支持指定渠道": "Ordinary users do not support specifying channels", + "无效的渠道 ID": "Invalid channel ID", + "该渠道已被禁用": "The channel has been disabled", + "无效的请求": "Invalid request", + "无可用渠道": "No available channels", + "Turnstile token 为空": "Turnstile token is empty", + "Turnstile 校验失败,请刷新重试!": "Turnstile verification failed, please refresh and try again!", + "id 为空!": "id is empty!", + "未提供兑换码": "No redemption code provided", + "无效的 user id": "Invalid user id", + "无效的兑换码": "Invalid redemption code", + "该兑换码已被使用": "The redemption code has been used", + "通过兑换码充值 %s": "Recharge %s through redemption code", + "未提供令牌": "No token provided", + "该令牌状态不可用": "The token status is not available", + "该令牌已过期": "The token has expired", + "该令牌额度已用尽": "The token quota has been used up", + "无效的令牌": "Invalid token", + "id 或 userId 为空!": "id or userId is empty!", + "quota 不能为负数!": "quota cannot be negative!", + "令牌额度不足": "Insufficient token quota", + "用户额度不足": "Insufficient user quota", + "您的额度即将用尽": "Your quota is about to run out", + "您的额度已用尽": "Your quota has been used up", + "%s,当前剩余额度为 %d,为了不影响您的使用,请及时充值。