mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
i18n: login page
This commit is contained in:
parent
2d20892994
commit
d6dc1f9719
|
|
@ -45,6 +45,9 @@
|
|||
"html-webpack-plugin": "4.0.0-beta.5",
|
||||
"http-proxy-middleware": "^0.20.0",
|
||||
"husky": "^4.2.5",
|
||||
"i18next": "^21.6.16",
|
||||
"i18next-browser-languagedetector": "^6.1.4",
|
||||
"i18next-http-backend": "^1.4.0",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"is-wsl": "^1.1.0",
|
||||
|
|
@ -76,6 +79,7 @@
|
|||
"react-dom": "^16.12.0",
|
||||
"react-highlight-words": "^0.18.0",
|
||||
"react-hotkeys": "^2.0.0",
|
||||
"react-i18next": "^11.16.7",
|
||||
"react-lazy-load-image-component": "^1.3.2",
|
||||
"react-load-script": "^0.0.6",
|
||||
"react-monaco-editor": "^0.36.0",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"login": {
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"captcha": "CAPTCHA",
|
||||
"signIn": "Sign in",
|
||||
"signUp": "Sign up",
|
||||
"signUpAccount": "Sign up",
|
||||
"useFIDO2": "Use Hardware Authenticator",
|
||||
"usePassword": "Use Password",
|
||||
"forgetPassword": "Forgot password?",
|
||||
"2FA": "2FA Verification",
|
||||
"input2FACode": "Please enter the six-digit 2FA verification code",
|
||||
"browserNotSupport": "Not supported by current browser or environment",
|
||||
"success": "Sign in successful",
|
||||
"title": "Sign in {{title}}",
|
||||
"continue": "Continue"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"pageNotFound": "Page not found",
|
||||
"unknownError": "Unknown error",
|
||||
"errLoadingSiteConfig": "Unable to load site configuration: ",
|
||||
"newVersionRefresh": "A new version of the current page is available and ready to be refreshed.",
|
||||
"errorDetails": "Error details",
|
||||
"renderError": "There is an error in the page rendering, please try refreshing this page.",
|
||||
"errors": {
|
||||
"40020": "Wrong password or email address",
|
||||
"40017": "This account has been blocked",
|
||||
"40018": "This account is not activated",
|
||||
"40019": "This feature is not enabled",
|
||||
"40001": "Wrong format of input parameters ({{message}})",
|
||||
"40021": "User not found",
|
||||
"40022": "Verification code not correct",
|
||||
"40023": "Login session not exist"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"login": {
|
||||
"email": "电子邮箱",
|
||||
"password": "密码",
|
||||
"captcha": "验证码",
|
||||
"signIn": "登录",
|
||||
"signUp": "注册",
|
||||
"signUpAccount": "注册账号",
|
||||
"useFIDO2": "使用外部验证器登录",
|
||||
"usePassword": "使用密码登录",
|
||||
"forgetPassword": "忘记密码",
|
||||
"2FA": "二步验证",
|
||||
"input2FACode": "请输入六位二步验证代码",
|
||||
"browserNotSupport": "当前浏览器或环境不支持",
|
||||
"success": "登录成功",
|
||||
"title": "登录 {{title}}",
|
||||
"continue": "下一步"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"pageNotFound": "页面不存在",
|
||||
"unknownError": "未知错误",
|
||||
"errLoadingSiteConfig": "无法加载站点配置:",
|
||||
"errorDetails": "错误详情",
|
||||
"newVersionRefresh": "当前页面有新版本可用,准备刷新。",
|
||||
"renderError": "页面渲染出现错误,请尝试刷新此页面。",
|
||||
"errors": {
|
||||
"40020": "用户邮箱或密码错误",
|
||||
"40017": "该账号已被封禁",
|
||||
"40018": "该账号未激活",
|
||||
"40019": "此功能未启用",
|
||||
"40001": "输入参数格式有误 ({{message}})",
|
||||
"40021": "用户不存在",
|
||||
"40022": "验证代码不正确",
|
||||
"40023": "登录会话不存在"
|
||||
}
|
||||
}
|
||||
23
src/App.js
23
src/App.js
|
|
@ -33,6 +33,7 @@ import PageLoading from "./component/Placeholder/PageLoading";
|
|||
import CodeViewer from "./component/Viewer/Code";
|
||||
import MusicPlayer from "./component/FileManager/MusicPlayer";
|
||||
import EpubViewer from "./component/Viewer/Epub";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const PDFViewer = React.lazy(() =>
|
||||
import(/* webpackChunkName: "pdf" */ "./component/Viewer/PDF")
|
||||
|
|
@ -42,6 +43,7 @@ export default function App() {
|
|||
const themeConfig = useSelector((state) => state.siteConfig.theme);
|
||||
const isLogin = useSelector((state) => state.viewUpdate.isLogin);
|
||||
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||
const { t } = useTranslation();
|
||||
|
||||
const theme = React.useMemo(() => {
|
||||
themeConfig.palette.type = prefersDarkMode ? "dark" : "light";
|
||||
|
|
@ -61,6 +63,13 @@ export default function App() {
|
|||
: themeConfig.palette.primary.main,
|
||||
},
|
||||
},
|
||||
overrides: {
|
||||
MuiButton: {
|
||||
root: {
|
||||
textTransform: "none",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
changeThemeColor(
|
||||
themeConfig.palette.type === "dark"
|
||||
|
|
@ -164,11 +173,19 @@ export default function App() {
|
|||
<Tasks />
|
||||
</AuthRoute>
|
||||
|
||||
<NoAuthRoute exact path={`${path}login`} isLogin={isLogin}>
|
||||
<NoAuthRoute
|
||||
exact
|
||||
path={`${path}login`}
|
||||
isLogin={isLogin}
|
||||
>
|
||||
<LoginForm />
|
||||
</NoAuthRoute>
|
||||
|
||||
<NoAuthRoute exact path={`${path}signup`} isLogin={isLogin}>
|
||||
<NoAuthRoute
|
||||
exact
|
||||
path={`${path}signup`}
|
||||
isLogin={isLogin}
|
||||
>
|
||||
<Register />
|
||||
</NoAuthRoute>
|
||||
|
||||
|
|
@ -215,7 +232,7 @@ export default function App() {
|
|||
</Route>
|
||||
|
||||
<Route path="*">
|
||||
<NotFound msg={"页面不存在"} />
|
||||
<NotFound msg={t("pageNotFound", { ns: "common" })} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ export const ICPFooter = () => {
|
|||
}
|
||||
return (
|
||||
<div className={classes.icp}>
|
||||
{`备案号: `}
|
||||
<Link
|
||||
href="https://beian.miit.gov.cn/"
|
||||
rel="noopener noreferrer"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {
|
|||
Paper,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { Link as RouterLink, useHistory } from "react-router-dom";
|
||||
import API from "../../middleware/Api";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import { bufferDecode, bufferEncode } from "../../utils/index";
|
||||
|
|
@ -22,7 +22,12 @@ import VpnIcon from "@material-ui/icons/VpnKeyOutlined";
|
|||
import { useLocation } from "react-router";
|
||||
import { ICPFooter } from "../Common/ICPFooter";
|
||||
import { useCaptcha } from "../../hooks/useCaptcha";
|
||||
import { applyThemes, setSessionStatus, toggleSnackbar } from "../../redux/explorer";
|
||||
import {
|
||||
applyThemes,
|
||||
setSessionStatus,
|
||||
toggleSnackbar,
|
||||
} from "../../redux/explorer";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
layout: {
|
||||
|
|
@ -87,6 +92,8 @@ function useQuery() {
|
|||
}
|
||||
|
||||
function LoginForm() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [email, setEmail] = useState("");
|
||||
const [pwd, setPwd] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
|
@ -95,7 +102,9 @@ function LoginForm() {
|
|||
const [faCode, setFACode] = useState("");
|
||||
|
||||
const loginCaptcha = useSelector((state) => state.siteConfig.loginCaptcha);
|
||||
const registerEnabled = useSelector((state) => state.siteConfig.registerEnabled);
|
||||
const registerEnabled = useSelector(
|
||||
(state) => state.siteConfig.registerEnabled
|
||||
);
|
||||
const title = useSelector((state) => state.siteConfig.title);
|
||||
const authn = useSelector((state) => state.siteConfig.authn);
|
||||
|
||||
|
|
@ -143,7 +152,7 @@ function LoginForm() {
|
|||
SetSessionStatus(true);
|
||||
|
||||
history.push("/home");
|
||||
ToggleSnackbar("top", "right", "登录成功", "success");
|
||||
ToggleSnackbar("top", "right", t("login.success"), "success");
|
||||
|
||||
localStorage.removeItem("siteConfigCache");
|
||||
};
|
||||
|
|
@ -151,7 +160,12 @@ function LoginForm() {
|
|||
const authnLogin = (e) => {
|
||||
e.preventDefault();
|
||||
if (!navigator.credentials) {
|
||||
ToggleSnackbar("top", "right", "当前浏览器或环境不支持", "warning");
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
t("login.browserNotSupport"),
|
||||
"warning"
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -261,13 +275,13 @@ function LoginForm() {
|
|||
<LockOutlinedIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
登录 {title}
|
||||
{t("login.title", { title })}
|
||||
</Typography>
|
||||
{!useAuthn && (
|
||||
<form className={classes.form} onSubmit={login}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">
|
||||
电子邮箱
|
||||
{t("login.email")}
|
||||
</InputLabel>
|
||||
<Input
|
||||
id="email"
|
||||
|
|
@ -283,7 +297,7 @@ function LoginForm() {
|
|||
</FormControl>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="password">
|
||||
密码
|
||||
{t("login.password")}
|
||||
</InputLabel>
|
||||
<Input
|
||||
name="password"
|
||||
|
|
@ -307,7 +321,7 @@ function LoginForm() {
|
|||
}
|
||||
className={classes.submit}
|
||||
>
|
||||
登录
|
||||
{t("login.signIn")}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
|
|
@ -315,7 +329,7 @@ function LoginForm() {
|
|||
<form className={classes.form}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="email">
|
||||
电子邮箱
|
||||
{t("login.email")}
|
||||
</InputLabel>
|
||||
<Input
|
||||
id="email"
|
||||
|
|
@ -338,17 +352,23 @@ function LoginForm() {
|
|||
onClick={authnLogin}
|
||||
className={classes.submit}
|
||||
>
|
||||
下一步
|
||||
{t("login.continue")}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
<Divider />
|
||||
<div className={classes.link}>
|
||||
<div>
|
||||
<Link href={"/forget"}>忘记密码</Link>
|
||||
<Link component={RouterLink} to={"/forget"}>
|
||||
{t("login.forgetPassword")}
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
{ registerEnabled && <Link href={"/signup"}>注册账号</Link> }
|
||||
{registerEnabled && (
|
||||
<Link component={RouterLink} to={"/signup"}>
|
||||
{t("login.signUpAccount")}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -368,7 +388,7 @@ function LoginForm() {
|
|||
marginRight: 8,
|
||||
}}
|
||||
/>
|
||||
使用外部验证器登录
|
||||
{t("login.useFIDO2")}
|
||||
</>
|
||||
)}
|
||||
{useAuthn && (
|
||||
|
|
@ -378,7 +398,7 @@ function LoginForm() {
|
|||
marginRight: 8,
|
||||
}}
|
||||
/>
|
||||
使用密码登录
|
||||
{t("login.usePassword")}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
|
|
@ -392,12 +412,12 @@ function LoginForm() {
|
|||
<VpnIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
二步验证
|
||||
{t("login.2FA")}
|
||||
</Typography>
|
||||
<form className={classes.form} onSubmit={twoFALogin}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="code">
|
||||
请输入六位二步验证代码
|
||||
{t("login.input2FACode")}
|
||||
</InputLabel>
|
||||
<Input
|
||||
id="code"
|
||||
|
|
@ -419,7 +439,7 @@ function LoginForm() {
|
|||
disabled={loading}
|
||||
className={classes.submit}
|
||||
>
|
||||
继续登录
|
||||
{t("login.continue")}
|
||||
</Button>{" "}
|
||||
</form>{" "}
|
||||
<Divider />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import { withStyles } from "@material-ui/core";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
const styles = {
|
||||
h1: {
|
||||
|
|
@ -18,7 +19,6 @@ class ErrorBoundary extends React.Component {
|
|||
}
|
||||
|
||||
static getDerivedStateFromError() {
|
||||
// 更新 state 使下一次渲染能够显示降级后的 UI
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
|
|
@ -30,20 +30,17 @@ class ErrorBoundary extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { classes, t } = this.props;
|
||||
if (this.state.hasError) {
|
||||
// 你可以自定义降级后的 UI 并渲染
|
||||
return (
|
||||
<>
|
||||
<h1 className={classes.h1}>:(</h1>
|
||||
<h2 className={classes.h2}>
|
||||
页面渲染出现错误,请尝试刷新此页面。
|
||||
</h2>
|
||||
<h2 className={classes.h2}>{t("renderError")}</h2>
|
||||
{this.state.error &&
|
||||
this.state.errorInfo &&
|
||||
this.state.errorInfo.componentStack && (
|
||||
<details>
|
||||
<summary>错误详情</summary>
|
||||
<summary>{t("errorDetails")}</summary>
|
||||
<pre>
|
||||
<code>{this.state.error.toString()}</code>
|
||||
</pre>
|
||||
|
|
@ -62,4 +59,4 @@ class ErrorBoundary extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles)(ErrorBoundary);
|
||||
export default withTranslation(["common"])(withStyles(styles)(ErrorBoundary));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
|
||||
import Backend from "i18next-http-backend";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
|
||||
i18n.use(Backend)
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: "en-US",
|
||||
debug: true,
|
||||
ns: ["common", "application"],
|
||||
load: "currentOnly",
|
||||
defaultNS: "application",
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
||||
34
src/index.js
34
src/index.js
|
|
@ -11,16 +11,16 @@ import { UpdateSiteConfig } from "./middleware/Init";
|
|||
import ErrorBoundary from "./component/Placeholder/ErrorBoundary";
|
||||
import { createBrowserHistory } from "history";
|
||||
import { ConnectedRouter, routerMiddleware } from "connected-react-router";
|
||||
import i18next from "./i18n";
|
||||
|
||||
const Admin = React.lazy(() => import("./Admin"));
|
||||
|
||||
if (window.location.hash !== "") {
|
||||
window.location.href = window.location.hash.split("#")[1];
|
||||
}
|
||||
|
||||
serviceWorker.register({
|
||||
onUpdate: (registration) => {
|
||||
alert("当前页面有新版本可用,准备刷新。");
|
||||
alert(i18next.t("newVersionRefresh", { ns: "common" }));
|
||||
if (registration && registration.waiting) {
|
||||
registration.waiting.postMessage({ type: "SKIP_WAITING" });
|
||||
}
|
||||
|
|
@ -41,21 +41,21 @@ const store = createStore(cloureveApp(history), reduxEnhance);
|
|||
UpdateSiteConfig(store);
|
||||
|
||||
ReactDOM.render(
|
||||
<ErrorBoundary>
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}>
|
||||
<Switch>
|
||||
<Route path="/admin">
|
||||
<Suspense fallback={"Loading..."}>
|
||||
<Suspense fallback={"Loading..."}>
|
||||
<ErrorBoundary>
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}>
|
||||
<Switch>
|
||||
<Route path="/admin">
|
||||
<Admin />
|
||||
</Suspense>
|
||||
</Route>
|
||||
<Route exact path="">
|
||||
<App />
|
||||
</Route>
|
||||
</Switch>
|
||||
</ConnectedRouter>
|
||||
</Provider>
|
||||
</ErrorBoundary>,
|
||||
</Route>
|
||||
<Route exact path="">
|
||||
<App />
|
||||
</Route>
|
||||
</Switch>
|
||||
</ConnectedRouter>
|
||||
</Provider>
|
||||
</ErrorBoundary>
|
||||
</Suspense>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import axios from "axios";
|
||||
import Auth from "./Auth";
|
||||
import i18next from "../i18n";
|
||||
|
||||
export const baseURL = "/api/v3";
|
||||
|
||||
|
|
@ -34,7 +35,16 @@ class AppError extends Error {
|
|||
constructor(message: string | undefined, public code: any, error: any) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message || "未知错误";
|
||||
if (i18next.exists(`errors.${code}`, { ns: "common" })) {
|
||||
this.message = i18next.t(`errors.${code}`, {
|
||||
ns: "common",
|
||||
message,
|
||||
});
|
||||
} else {
|
||||
this.message =
|
||||
message || i18next.t("unknownError", { ns: "common" });
|
||||
}
|
||||
|
||||
this.message += error ? " " + error : "";
|
||||
this.stack = new Error().stack;
|
||||
}
|
||||
|
|
@ -49,13 +59,13 @@ instance.interceptors.response.use(
|
|||
response.rawData.code !== 0 &&
|
||||
response.rawData.code !== 203
|
||||
) {
|
||||
// 登录过期
|
||||
// Login expired
|
||||
if (response.rawData.code === 401) {
|
||||
Auth.signout();
|
||||
window.location.href = "/login";
|
||||
}
|
||||
|
||||
// 非管理员
|
||||
// Non-admin
|
||||
if (response.rawData.code === 40008) {
|
||||
window.location.href = "/home";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
setSiteConfig,
|
||||
toggleSnackbar,
|
||||
} from "../redux/explorer";
|
||||
import i18next from "../i18n";
|
||||
|
||||
const initUserConfig = (siteConfig) => {
|
||||
if (siteConfig.user !== undefined && !siteConfig.user.anonymous) {
|
||||
|
|
@ -81,7 +82,8 @@ export async function UpdateSiteConfig(store) {
|
|||
toggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"无法加载站点配置:" + error.message,
|
||||
i18next.t("errLoadingSiteConfig", { ns: "common" }) +
|
||||
error.message,
|
||||
"error"
|
||||
)
|
||||
);
|
||||
|
|
|
|||
83
yarn.lock
83
yarn.lock
|
|
@ -1173,6 +1173,13 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.14.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.17.2":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.16.7", "@babel/template@^7.4.0", "@babel/template@^7.6.0", "@babel/template@^7.8.6":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
|
||||
|
|
@ -3599,6 +3606,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
|
|||
safe-buffer "^5.0.1"
|
||||
sha.js "^2.4.8"
|
||||
|
||||
cross-fetch@3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f"
|
||||
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
|
||||
dependencies:
|
||||
node-fetch "2.6.7"
|
||||
|
||||
cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
|
|
@ -5642,7 +5656,7 @@ html-entities@^1.3.1:
|
|||
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc"
|
||||
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
|
||||
|
||||
html-escaper@^2.0.0:
|
||||
html-escaper@^2.0.0, html-escaper@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
|
||||
integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
|
||||
|
|
@ -5660,6 +5674,13 @@ html-minifier@^3.5.20:
|
|||
relateurl "0.2.x"
|
||||
uglify-js "3.4.x"
|
||||
|
||||
html-parse-stringify@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2"
|
||||
integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==
|
||||
dependencies:
|
||||
void-elements "3.1.0"
|
||||
|
||||
html-webpack-plugin@4.0.0-beta.5:
|
||||
version "4.0.0-beta.5"
|
||||
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.5.tgz#2c53083c1151bfec20479b1f8aaf0039e77b5513"
|
||||
|
|
@ -5777,6 +5798,27 @@ hyphenate-style-name@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
|
||||
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
|
||||
|
||||
i18next-browser-languagedetector@^6.1.4:
|
||||
version "6.1.4"
|
||||
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.4.tgz#7b087c5edb6f6acd38ef54ede2160ab9cde0108f"
|
||||
integrity sha512-wukWnFeU7rKIWT66VU5i8I+3Zc4wReGcuDK2+kuFhtoxBRGWGdvYI9UQmqNL/yQH1KogWwh+xGEaIPH8V/i2Zg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.6"
|
||||
|
||||
i18next-http-backend@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/i18next-http-backend/-/i18next-http-backend-1.4.0.tgz#e6abef0615316e00837798d2385c13395096f963"
|
||||
integrity sha512-wsvx7E/CT1pHmBM99Vu57YLJpsrHbVjxGxf25EIJ/6oTjsvCkZZ6c3SA4TejcK5jIHfv9oLxQX8l+DFKZHZ0Gg==
|
||||
dependencies:
|
||||
cross-fetch "3.1.5"
|
||||
|
||||
i18next@^21.6.16:
|
||||
version "21.6.16"
|
||||
resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.6.16.tgz#8cff8c3ba2ffaf8438a8c83fe284083f15cf3941"
|
||||
integrity sha512-xJlzrVxG9CyAGsbMP1aKuiNr1Ed2m36KiTB7hjGMG2Zo4idfw3p9THUEu+GjBwIgEZ7F11ZbCzJcfv4uyfKNuw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.17.2"
|
||||
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
|
|
@ -7806,6 +7848,13 @@ node-ensure@^0.0.0:
|
|||
resolved "https://registry.yarnpkg.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
|
||||
integrity sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc=
|
||||
|
||||
node-fetch@2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-forge@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
|
||||
|
|
@ -9564,6 +9613,15 @@ react-hotkeys@^2.0.0:
|
|||
dependencies:
|
||||
prop-types "^15.6.1"
|
||||
|
||||
react-i18next@^11.16.7:
|
||||
version "11.16.7"
|
||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.16.7.tgz#8d0680b7f4c8e43f59996336b7183ad576a28df7"
|
||||
integrity sha512-7yotILJLnKfvUfrl/nt9eK9vFpVFjZPLWAwBzWL6XppSZZEvlmlKk0GBGDCAPfLfs8oND7WAbry8wGzdoiW5Nw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.14.5"
|
||||
html-escaper "^2.0.2"
|
||||
html-parse-stringify "^3.0.1"
|
||||
|
||||
react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.4:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
|
|
@ -11252,6 +11310,11 @@ tr46@^1.0.1:
|
|||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
|
||||
|
||||
ts-pnp@1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.4.tgz#ae27126960ebaefb874c6d7fa4729729ab200d90"
|
||||
|
|
@ -11596,6 +11659,11 @@ vm-browserify@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
||||
void-elements@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
|
||||
integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=
|
||||
|
||||
w3c-hr-time@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
|
||||
|
|
@ -11644,6 +11712,11 @@ wbuf@^1.1.0, wbuf@^1.7.3:
|
|||
dependencies:
|
||||
minimalistic-assert "^1.0.0"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
|
||||
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
|
|
@ -11785,6 +11858,14 @@ whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0:
|
|||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
|
||||
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
|
||||
|
||||
whatwg-url@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||
integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
|
||||
dependencies:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
|
||||
whatwg-url@^6.4.1:
|
||||
version "6.5.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
|
||||
|
|
|
|||
Loading…
Reference in New Issue