chore: update part of i18n

This commit is contained in:
Steven 2023-08-18 09:00:42 +08:00
parent d939bb8250
commit bafb17015c
11 changed files with 64 additions and 26 deletions

View File

@ -1,4 +1,5 @@
import { Button, Link, Modal, ModalDialog } from "@mui/joy"; import { Button, Link, Modal, ModalDialog } from "@mui/joy";
import { useTranslation } from "react-i18next";
import Icon from "./Icon"; import Icon from "./Icon";
interface Props { interface Props {
@ -7,12 +8,13 @@ interface Props {
const AboutDialog: React.FC<Props> = (props: Props) => { const AboutDialog: React.FC<Props> = (props: Props) => {
const { onClose } = props; const { onClose } = props;
const { t } = useTranslation();
return ( return (
<Modal open={true}> <Modal open={true}>
<ModalDialog> <ModalDialog>
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="text-lg font-medium">About</span> <span className="text-lg font-medium">{t("common.about")}</span>
<Button variant="plain" onClick={onClose}> <Button variant="plain" onClick={onClose}>
<Icon.X className="w-5 h-auto text-gray-600" /> <Icon.X className="w-5 h-auto text-gray-600" />
</Button> </Button>

View File

@ -1,4 +1,5 @@
import { Button, Modal, ModalDialog } from "@mui/joy"; import { Button, Modal, ModalDialog } from "@mui/joy";
import { useTranslation } from "react-i18next";
import AnalyticsView from "./AnalyticsView"; import AnalyticsView from "./AnalyticsView";
import Icon from "./Icon"; import Icon from "./Icon";
@ -9,12 +10,13 @@ interface Props {
const AnalyticsDialog: React.FC<Props> = (props: Props) => { const AnalyticsDialog: React.FC<Props> = (props: Props) => {
const { shortcutId, onClose } = props; const { shortcutId, onClose } = props;
const { t } = useTranslation();
return ( return (
<Modal open={true}> <Modal open={true}>
<ModalDialog> <ModalDialog>
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="text-lg font-medium">Analytics</span> <span className="text-lg font-medium">{t("analytics.self")}</span>
<Button variant="plain" onClick={onClose}> <Button variant="plain" onClick={onClose}>
<Icon.X className="w-5 h-auto text-gray-600" /> <Icon.X className="w-5 h-auto text-gray-600" />
</Button> </Button>

View File

@ -1,5 +1,6 @@
import classNames from "classnames"; import classNames from "classnames";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import * as api from "../helpers/api"; import * as api from "../helpers/api";
import Icon from "./Icon"; import Icon from "./Icon";
@ -10,6 +11,7 @@ interface Props {
const AnalyticsView: React.FC<Props> = (props: Props) => { const AnalyticsView: React.FC<Props> = (props: Props) => {
const { shortcutId, className } = props; const { shortcutId, className } = props;
const { t } = useTranslation();
const [analytics, setAnalytics] = useState<AnalysisData | null>(null); const [analytics, setAnalytics] = useState<AnalysisData | null>(null);
const [selectedDeviceTab, setSelectedDeviceTab] = useState<"os" | "browser">("browser"); const [selectedDeviceTab, setSelectedDeviceTab] = useState<"os" | "browser">("browser");
@ -24,12 +26,12 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
{analytics ? ( {analytics ? (
<> <>
<div className="w-full"> <div className="w-full">
<p className="w-full h-8 px-2">Top Sources</p> <p className="w-full h-8 px-2">{t("analytics.top-sources")}</p>
<div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg"> <div className="w-full mt-1 overflow-hidden shadow ring-1 ring-black ring-opacity-5 rounded-lg">
<div className="w-full divide-y divide-gray-300"> <div className="w-full divide-y divide-gray-300">
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="py-2 px-2 text-left font-semibold text-sm text-gray-500">Source</span> <span className="py-2 px-2 text-left font-semibold text-sm text-gray-500">{t("analytics.source")}</span>
<span className="py-2 pr-2 text-right font-semibold text-sm text-gray-500">Visitors</span> <span className="py-2 pr-2 text-right font-semibold text-sm text-gray-500">{t("analytics.visitors")}</span>
</div> </div>
<div className="w-full divide-y divide-gray-200"> <div className="w-full divide-y divide-gray-200">
{analytics.referenceData.map((reference) => ( {analytics.referenceData.map((reference) => (
@ -53,7 +55,7 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
<div className="w-full"> <div className="w-full">
<div className="w-full h-8 px-2 flex flex-row justify-between items-center"> <div className="w-full h-8 px-2 flex flex-row justify-between items-center">
<span>Devices</span> <span>{t("analytics.devices")}</span>
<div> <div>
<button <button
className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${ className={`whitespace-nowrap border-b-2 px-1 text-sm font-medium ${
@ -63,7 +65,7 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
}`} }`}
onClick={() => setSelectedDeviceTab("browser")} onClick={() => setSelectedDeviceTab("browser")}
> >
Browser {t("analytics.browser")}
</button> </button>
<span className="text-gray-200 font-mono mx-1">/</span> <span className="text-gray-200 font-mono mx-1">/</span>
<button <button
@ -83,8 +85,8 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
{selectedDeviceTab === "browser" ? ( {selectedDeviceTab === "browser" ? (
<div className="w-full divide-y divide-gray-300"> <div className="w-full divide-y divide-gray-300">
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">Browsers</span> <span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">{t("analytics.browsers")}</span>
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">Visitors</span> <span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">{t("analytics.visitors")}</span>
</div> </div>
<div className="w-full divide-y divide-gray-200"> <div className="w-full divide-y divide-gray-200">
{analytics.browserData.map((reference) => ( {analytics.browserData.map((reference) => (
@ -98,8 +100,8 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
) : ( ) : (
<div className="w-full divide-y divide-gray-300"> <div className="w-full divide-y divide-gray-300">
<div className="w-full flex flex-row justify-between items-center"> <div className="w-full flex flex-row justify-between items-center">
<span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">Operating system</span> <span className="py-2 px-2 text-left text-sm font-semibold text-gray-500">{t("analytics.operating-system")}</span>
<span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">Visitors</span> <span className="py-2 pr-2 text-right text-sm font-semibold text-gray-500">{t("analytics.visitors")}</span>
</div> </div>
<div className="w-full divide-y divide-gray-200"> <div className="w-full divide-y divide-gray-200">
{analytics.deviceData.map((device) => ( {analytics.deviceData.map((device) => (
@ -117,7 +119,7 @@ const AnalyticsView: React.FC<Props> = (props: Props) => {
) : ( ) : (
<div className="py-12 w-full flex flex-row justify-center items-center opacity-80"> <div className="py-12 w-full flex flex-row justify-center items-center opacity-80">
<Icon.Loader className="mr-2 w-5 h-auto animate-spin" /> <Icon.Loader className="mr-2 w-5 h-auto animate-spin" />
loading {t("common.loading")}
</div> </div>
)} )}
</div> </div>

View File

@ -1,6 +1,7 @@
import { Button, Input, Modal, ModalDialog } from "@mui/joy"; import { Button, Input, Modal, ModalDialog } from "@mui/joy";
import { useState } from "react"; import { useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import useLoading from "../hooks/useLoading"; import useLoading from "../hooks/useLoading";
import useUserStore from "../stores/v1/user"; import useUserStore from "../stores/v1/user";
import Icon from "./Icon"; import Icon from "./Icon";
@ -11,6 +12,7 @@ interface Props {
const ChangePasswordDialog: React.FC<Props> = (props: Props) => { const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
const { onClose } = props; const { onClose } = props;
const { t } = useTranslation();
const userStore = useUserStore(); const userStore = useUserStore();
const [newPassword, setNewPassword] = useState(""); const [newPassword, setNewPassword] = useState("");
const [newPasswordAgain, setNewPasswordAgain] = useState(""); const [newPasswordAgain, setNewPasswordAgain] = useState("");
@ -77,10 +79,10 @@ const ChangePasswordDialog: React.FC<Props> = (props: Props) => {
</div> </div>
<div className="w-full flex flex-row justify-end items-center space-x-2"> <div className="w-full flex flex-row justify-end items-center space-x-2">
<Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}> <Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}>
Cancel {t("common.cancel")}
</Button> </Button>
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}> <Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
Save {t("common.save")}
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -2,6 +2,7 @@ import { Button, Input, Modal, ModalDialog, Radio, RadioGroup } from "@mui/joy";
import axios from "axios"; import axios from "axios";
import { useState } from "react"; import { useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import useLoading from "../hooks/useLoading"; import useLoading from "../hooks/useLoading";
import useUserStore from "../stores/v1/user"; import useUserStore from "../stores/v1/user";
import Icon from "./Icon"; import Icon from "./Icon";
@ -33,6 +34,7 @@ interface State {
const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => { const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
const { onClose, onConfirm } = props; const { onClose, onConfirm } = props;
const { t } = useTranslation();
const currentUser = useUserStore().getCurrentUser(); const currentUser = useUserStore().getCurrentUser();
const [state, setState] = useState({ const [state, setState] = useState({
description: "", description: "",
@ -119,10 +121,10 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
</div> </div>
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2"> <div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}> <Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
Cancel {t("common.cancel")}
</Button> </Button>
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}> <Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
Create {t("common.create")}
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -331,10 +331,10 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2"> <div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}> <Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
Cancel {t("common.cancel")}
</Button> </Button>
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}> <Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
Save {t("common.save")}
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -2,6 +2,7 @@ import { Button, Input, Modal, ModalDialog, Radio, RadioGroup } from "@mui/joy";
import { isUndefined } from "lodash-es"; import { isUndefined } from "lodash-es";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import useLoading from "../hooks/useLoading"; import useLoading from "../hooks/useLoading";
import useUserStore from "../stores/v1/user"; import useUserStore from "../stores/v1/user";
import Icon from "./Icon"; import Icon from "./Icon";
@ -20,6 +21,7 @@ const roles: Role[] = ["USER", "ADMIN"];
const CreateUserDialog: React.FC<Props> = (props: Props) => { const CreateUserDialog: React.FC<Props> = (props: Props) => {
const { onClose, onConfirm, user } = props; const { onClose, onConfirm, user } = props;
const { t } = useTranslation();
const userStore = useUserStore(); const userStore = useUserStore();
const [state, setState] = useState<State>({ const [state, setState] = useState<State>({
userCreate: { userCreate: {
@ -185,10 +187,10 @@ const CreateUserDialog: React.FC<Props> = (props: Props) => {
</div> </div>
<div className="w-full flex flex-row justify-end items-center mt-4 space-x-2"> <div className="w-full flex flex-row justify-end items-center mt-4 space-x-2">
<Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}> <Button color="neutral" variant="plain" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={onClose}>
Cancel {t("common.cancel")}
</Button> </Button>
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}> <Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
Save {t("common.save")}
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
import { Button, Input, Modal, ModalDialog } from "@mui/joy"; import { Button, Input, Modal, ModalDialog } from "@mui/joy";
import { useState } from "react"; import { useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import useLoading from "../hooks/useLoading"; import useLoading from "../hooks/useLoading";
import useUserStore from "../stores/v1/user"; import useUserStore from "../stores/v1/user";
import Icon from "./Icon"; import Icon from "./Icon";
@ -11,6 +12,7 @@ interface Props {
const EditUserinfoDialog: React.FC<Props> = (props: Props) => { const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
const { onClose } = props; const { onClose } = props;
const { t } = useTranslation();
const userStore = useUserStore(); const userStore = useUserStore();
const currentUser = userStore.getCurrentUser(); const currentUser = userStore.getCurrentUser();
const [email, setEmail] = useState(currentUser.email); const [email, setEmail] = useState(currentUser.email);
@ -73,10 +75,10 @@ const EditUserinfoDialog: React.FC<Props> = (props: Props) => {
</div> </div>
<div className="w-full flex flex-row justify-end items-center space-x-2"> <div className="w-full flex flex-row justify-end items-center space-x-2">
<Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}> <Button variant="plain" disabled={requestState.isLoading} onClick={handleCloseBtnClick}>
Cancel {t("common.cancel")}
</Button> </Button>
<Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}> <Button color="primary" disabled={requestState.isLoading} loading={requestState.isLoading} onClick={handleSaveBtnClick}>
Save {t("common.save")}
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -2,6 +2,7 @@ import { Button, Modal, ModalDialog } from "@mui/joy";
import { QRCodeCanvas } from "qrcode.react"; import { QRCodeCanvas } from "qrcode.react";
import { useRef } from "react"; import { useRef } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { useTranslation } from "react-i18next";
import { absolutifyLink } from "../helpers/utils"; import { absolutifyLink } from "../helpers/utils";
import Icon from "./Icon"; import Icon from "./Icon";
@ -12,6 +13,7 @@ interface Props {
const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => { const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
const { shortcut, onClose } = props; const { shortcut, onClose } = props;
const { t } = useTranslation();
const containerRef = useRef<HTMLDivElement | null>(null); const containerRef = useRef<HTMLDivElement | null>(null);
const shortcutLink = absolutifyLink(`/s/${shortcut.name}`); const shortcutLink = absolutifyLink(`/s/${shortcut.name}`);
@ -49,7 +51,7 @@ const GenerateQRCodeDialog: React.FC<Props> = (props: Props) => {
<div className="w-full flex flex-row justify-center items-center px-4"> <div className="w-full flex flex-row justify-center items-center px-4">
<Button className="w-full" color="neutral" onClick={handleDownloadQRCodeClick}> <Button className="w-full" color="neutral" onClick={handleDownloadQRCodeClick}>
<Icon.Download className="w-4 h-auto mr-1" /> <Icon.Download className="w-4 h-auto mr-1" />
Download {t("common.download")}
</Button> </Button>
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
import { useState } from "react"; import { useState } from "react";
import { useTranslation } from "react-i18next";
import { shortcutService } from "../services"; import { shortcutService } from "../services";
import useUserStore from "../stores/v1/user"; import useUserStore from "../stores/v1/user";
import { showCommonDialog } from "./Alert"; import { showCommonDialog } from "./Alert";
@ -14,6 +15,7 @@ interface Props {
const ShortcutActionsDropdown = (props: Props) => { const ShortcutActionsDropdown = (props: Props) => {
const { shortcut } = props; const { shortcut } = props;
const { t } = useTranslation();
const currentUser = useUserStore().getCurrentUser(); const currentUser = useUserStore().getCurrentUser();
const [showEditDialog, setShowEditDialog] = useState<boolean>(false); const [showEditDialog, setShowEditDialog] = useState<boolean>(false);
const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false); const [showQRCodeDialog, setShowQRCodeDialog] = useState<boolean>(false);
@ -42,7 +44,7 @@ const ShortcutActionsDropdown = (props: Props) => {
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
onClick={() => setShowEditDialog(true)} onClick={() => setShowEditDialog(true)}
> >
<Icon.Edit className="w-4 h-auto mr-2" /> Edit <Icon.Edit className="w-4 h-auto mr-2" /> {t("common.edit")}
</button> </button>
)} )}
<button <button
@ -55,7 +57,7 @@ const ShortcutActionsDropdown = (props: Props) => {
className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60" className="w-full px-2 flex flex-row justify-start items-center text-left leading-8 cursor-pointer rounded hover:bg-gray-100 disabled:cursor-not-allowed disabled:bg-gray-100 disabled:opacity-60"
onClick={() => setShowAnalyticsDialog(true)} onClick={() => setShowAnalyticsDialog(true)}
> >
<Icon.BarChart2 className="w-4 h-auto mr-2" /> Analytics <Icon.BarChart2 className="w-4 h-auto mr-2" /> {t("analytics.self")}
</button> </button>
{havePermission && ( {havePermission && (
<button <button
@ -64,7 +66,7 @@ const ShortcutActionsDropdown = (props: Props) => {
handleDeleteShortcutButtonClick(shortcut); handleDeleteShortcutButtonClick(shortcut);
}} }}
> >
<Icon.Trash className="w-4 h-auto mr-2" /> Delete <Icon.Trash className="w-4 h-auto mr-2" /> {t("common.delete")}
</button> </button>
)} )}
</> </>

View File

@ -1,4 +1,24 @@
{ {
"common": {
"about": "About",
"loading": "Loading",
"cancel": "Cancel",
"save": "Save",
"create": "Create",
"download": "Download",
"edit": "Edit",
"delete": "Delete"
},
"analytics": {
"self": "Analytics",
"top-sources": "Top Sources",
"source": "Source",
"visitors": "Visitors",
"devices": "Devices",
"browser": "Browser",
"browsers": "Browsers",
"operating-system": "Operating System"
},
"shortcut": { "shortcut": {
"visibility": { "visibility": {
"private": { "private": {