add i18n support

This commit is contained in:
oupula 2025-09-30 12:40:33 +08:00
parent 789dcb3797
commit 353b58a835
13 changed files with 58 additions and 63 deletions

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{}

View File

@ -18,7 +18,7 @@ import { cx } from "@/cva.config";
import PasteModal from "@/components/popovers/PasteModal"; import PasteModal from "@/components/popovers/PasteModal";
import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index"; import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index";
import MountPopopover from "@/components/popovers/MountPopover"; import MountPopopover from "@/components/popovers/MountPopover";
import {ExtensionPopover} from "@/components/popovers/ExtensionPopover"; import { ExtensionPopover } from "@/components/popovers/ExtensionPopover";
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation"; import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
export default function Actionbar({ export default function Actionbar({

View File

@ -1,5 +1,4 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
CheckCircleIcon, CheckCircleIcon,
ExclamationTriangleIcon, ExclamationTriangleIcon,
@ -58,15 +57,15 @@ const variantConfig = {
buttonTheme: "danger" | "primary" | "blank" | "light" | "lightDanger"; buttonTheme: "danger" | "primary" | "blank" | "light" | "lightDanger";
} }
>; >;
// @ts-ignore
export function ConfirmDialog({ export function ConfirmDialog({
open, open,
onClose, onClose,
title, title,
description, description,
variant = "info", variant = "info",
confirmText = useTranslation('Confirm').toString(), confirmText = 'Confirm',
cancelText = useTranslation('Cancel').toString(), cancelText = 'Cancel',
onConfirm, onConfirm,
isConfirming = false, isConfirming = false,
}: ConfirmDialogProps) { }: ConfirmDialogProps) {

View File

@ -27,7 +27,7 @@ interface NavbarProps {
kvmName?: string; kvmName?: string;
} }
export default function DashboardNavbar({ export default function DashboardNavbar({
primaryLinks = [], primaryLinks = [],
isLoggedIn, isLoggedIn,
showConnectionStatus, showConnectionStatus,

View File

@ -96,19 +96,19 @@ export default function InfoBar() {
{debugMode && ( {debugMode && (
<div className="flex w-[156px] items-center gap-x-1"> <div className="flex w-[156px] items-center gap-x-1">
<span className="text-xs font-semibold">{t('USB_State')}:</span> <span className="text-xs font-semibold">{t('USB_State')}:</span>
<span className="text-xs">{t(usbState.replace(' ','_').toString())}</span> <span className="text-xs">{t(usbState)}</span>
</div> </div>
)} )}
{debugMode && ( {debugMode && (
<div className="flex w-[156px] items-center gap-x-1"> <div className="flex w-[156px] items-center gap-x-1">
<span className="text-xs font-semibold">{t('HDMI_State')}:</span> <span className="text-xs font-semibold">{t('HDMI_State')}:</span>
<span className="text-xs">{t(hdmiState.toString())}</span> <span className="text-xs">{t(hdmiState)}</span>
</div> </div>
)} )}
{debugMode && ( {debugMode && (
<div className="flex w-[168px] items-center gap-x-1"> <div className="flex w-[168px] items-center gap-x-1">
<span className="text-xs font-semibold">{t('HidRPC_State')}:</span> <span className="text-xs font-semibold">{t('HidRPC_State')}:</span>
<span className="text-xs">{t(rpcHidStatus.toString().replace(' ','_'))}</span> <span className="text-xs">{t(rpcHidStatus)}</span>
</div> </div>
)} )}
{isPasteInProgress && ( {isPasteInProgress && (

View File

@ -1,13 +1,15 @@
import StatusCard from "@components/StatusCards";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
import StatusCard from "@components/StatusCards";
const PeerConnectionStatusMap = { const PeerConnectionStatusMap = {
connected: "Connected", connected: "Connected",
connecting: "Connecting", connecting: "Connecting",
disconnected: "Disconnected", disconnected: "Disconnected",
error: "Connection error", error: "Connection_error",
closing: "Closing", closing: "Closing",
failed: "Connection failed", failed: "Connection_failed",
closed: "Closed", closed: "Closed",
new: "Connecting", new: "Connecting",
} as Record<RTCPeerConnectionState | "error" | "closing", string>; } as Record<RTCPeerConnectionState | "error" | "closing", string>;
@ -28,7 +30,8 @@ export default function PeerConnectionStatusCard({
state?: RTCPeerConnectionState | null; state?: RTCPeerConnectionState | null;
title?: string; title?: string;
}) { }) {
if (!state) return <></>; if (!state) return;
// eslint-disable-next-line react-hooks/rules-of-hooks
const { t } = useTranslation(); const { t } = useTranslation();
const StatusCardProps: StatusProps = { const StatusCardProps: StatusProps = {
connected: { connected: {
@ -57,7 +60,7 @@ export default function PeerConnectionStatusCard({
}, },
}; };
const props = StatusCardProps[state]; const props = StatusCardProps[state];
if (!props) return (<div></div>); if (!props) return;
return ( return (
<StatusCard <StatusCard
title={title || "JetKVM Device"} title={title || "JetKVM Device"}

View File

@ -33,7 +33,7 @@ const StatusCardProps: StatusProps = {
iconClassName: "h-5 w-5 text-blue-500", iconClassName: "h-5 w-5 text-blue-500",
statusIndicatorClassName: "bg-slate-300 border-slate-400", statusIndicatorClassName: "bg-slate-300 border-slate-400",
}, },
"not attached": { "not_attached": {
icon: ({ className }) => ( icon: ({ className }) => (
<img className={cx(className)} src={KeyboardAndMouseConnectedIcon} alt="" /> <img className={cx(className)} src={KeyboardAndMouseConnectedIcon} alt="" />
), ),
@ -61,7 +61,7 @@ export default function USBStateStatus({
configured: t('Connected'), configured: t('Connected'),
attached: t('Connecting'), attached: t('Connecting'),
addressed: t('Connecting'), addressed: t('Connecting'),
"not attached": t('Disconnected'), "not_attached": t('Disconnected'),
suspended: t('Low_power_mode'), suspended: t('Low_power_mode'),
}; };
const props = StatusCardProps[state]; const props = StatusCardProps[state];
@ -76,7 +76,7 @@ export default function USBStateStatus({
icon: Icon, icon: Icon,
iconClassName, iconClassName,
statusIndicatorClassName, statusIndicatorClassName,
} = StatusCardProps["not attached"]; } = StatusCardProps["not_attached"];
return ( return (
<StatusCard <StatusCard

View File

@ -171,7 +171,7 @@ export function UsbInfoSetting() {
handleUsbConfigChange(usbConfig); handleUsbConfigChange(usbConfig);
} }
}} }}
options={[...usbConfigs, { value: "custom", label: "Custom" }]} options={[...usbConfigs, { value: "custom", label: t('Custom') }]}
/> />
</SettingsItem> </SettingsItem>
{usbConfigProduct === "custom" && ( {usbConfigProduct === "custom" && (

View File

@ -468,7 +468,7 @@ export interface KeysDownState {
export type USBStates = export type USBStates =
| "configured" | "configured"
| "attached" | "attached"
| "not attached" | "not_attached"
| "suspended" | "suspended"
| "addressed"; | "addressed";
@ -503,7 +503,7 @@ export const useHidStore = create<HidState>(set => ({
setPasteModeEnabled: (enabled: boolean): void => set({ isPasteInProgress: enabled }), setPasteModeEnabled: (enabled: boolean): void => set({ isPasteInProgress: enabled }),
// Add these new properties for USB state // Add these new properties for USB state
usbState: "not attached", usbState: "not_attached",
setUsbState: (state: USBStates) => set({ usbState: state }), setUsbState: (state: USBStates) => set({ usbState: state }),
})); }));

View File

@ -52,7 +52,7 @@ function ConfirmationBox({
<div className="flex flex-col items-start justify-start space-y-4 text-left"> <div className="flex flex-col items-start justify-start space-y-4 text-left">
<div className="text-left"> <div className="text-left">
<p className="text-base font-semibold text-black dark:text-white"> <p className="text-base font-semibold text-black dark:text-white">
{t('重启JetKVM')} {t('Reboot_JetKVM')}
</p> </p>
<p className="text-sm text-slate-600 dark:text-slate-300"> <p className="text-sm text-slate-600 dark:text-slate-300">
{t('Do_you_want_to_proceed_with_rebooting_the_system')} {t('Do_you_want_to_proceed_with_rebooting_the_system')}

View File

@ -12,41 +12,6 @@ import notifications from "@/notifications";
import { SettingsItem } from "./devices.$id.settings"; import { SettingsItem } from "./devices.$id.settings";
const defaultEdid =
"00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b";
const edids = [
{
value: defaultEdid,
label: "JetKVM Default",
},
{
value:
"00FFFFFFFFFFFF00047265058A3F6101101E0104A53420783FC125A8554EA0260D5054BFEF80714F8140818081C081008B009500B300283C80A070B023403020360006442100001A000000FD00304C575716010A202020202020000000FC0042323436574C0A202020202020000000FF0054384E4545303033383532320A01F802031CF14F90020304050607011112131415161F2309070783010000011D8018711C1620582C250006442100009E011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E9600064421000018C344806E70B028401720A80406442100001E00000000000000000000000000000000000000000000000000000096",
label: "Acer B246WL, 1920x1200",
},
{
value:
"00FFFFFFFFFFFF0006B3872401010101021F010380342078EA6DB5A7564EA0250D5054BF6F00714F8180814081C0A9409500B300D1C0283C80A070B023403020360006442100001A000000FD00314B1E5F19000A202020202020000000FC00504132343851560A2020202020000000FF004D314C4D51533035323135370A014D02032AF14B900504030201111213141F230907078301000065030C001000681A00000101314BE6E2006A023A801871382D40582C450006442100001ECD5F80B072B0374088D0360006442100001C011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E960006442100001800000000000000000000000000DC",
label: "ASUS PA248QV, 1920x1200",
},
{
value:
"00FFFFFFFFFFFF0010AC132045393639201E0103803C22782ACD25A3574B9F270D5054A54B00714F8180A9C0D1C00101010101010101023A801871382D40582C450056502100001E000000FF00335335475132330A2020202020000000FC0044454C4C204432373231480A20000000FD00384C1E5311000A202020202020018102031AB14F90050403020716010611121513141F65030C001000023A801871382D40582C450056502100001E011D8018711C1620582C250056502100009E011D007251D01E206E28550056502100001E8C0AD08A20E02D10103E960056502100001800000000000000000000000000000000000000000000000000000000004F",
label: "DELL D2721H, 1920x1080",
},
{
value:
"00ffffffffffff0010ac0100020000000111010380221bff0a00000000000000000000adce0781800101010101010101010101010101000000ff0030303030303030303030303030000000ff0030303030303030303030303030000000fd00384c1f530b000a000000000000000000fc0044454c4c2049445241430a2020000a",
label: "DELL IDRAC EDID, 1280x1024",
},
];
const streamQualityOptions = [
{ value: "1", label: "High" },
{ value: "0.5", label: "Medium" },
{ value: "0.1", label: "Low" },
];
export default function SettingsVideoRoute() { export default function SettingsVideoRoute() {
const { send } = useJsonRpc(); const { send } = useJsonRpc();
const { t } = useTranslation(); const { t } = useTranslation();
@ -55,6 +20,40 @@ export default function SettingsVideoRoute() {
const [edid, setEdid] = useState<string | null>(null); const [edid, setEdid] = useState<string | null>(null);
const [edidLoading, setEdidLoading] = useState(false); const [edidLoading, setEdidLoading] = useState(false);
const defaultEdid =
"00ffffffffffff0052620188008888881c150103800000780a0dc9a05747982712484c00000001010101010101010101010101010101023a801871382d40582c4500c48e2100001e011d007251d01e206e285500c48e2100001e000000fc00543734392d6648443732300a20000000fd00147801ff1d000a202020202020017b";
const edids = [
{
value: defaultEdid,
label: t('JetKVM_Default'),
},
{
value:
"00FFFFFFFFFFFF00047265058A3F6101101E0104A53420783FC125A8554EA0260D5054BFEF80714F8140818081C081008B009500B300283C80A070B023403020360006442100001A000000FD00304C575716010A202020202020000000FC0042323436574C0A202020202020000000FF0054384E4545303033383532320A01F802031CF14F90020304050607011112131415161F2309070783010000011D8018711C1620582C250006442100009E011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E9600064421000018C344806E70B028401720A80406442100001E00000000000000000000000000000000000000000000000000000096",
label: "Acer B246WL, 1920x1200",
},
{
value:
"00FFFFFFFFFFFF0006B3872401010101021F010380342078EA6DB5A7564EA0250D5054BF6F00714F8180814081C0A9409500B300D1C0283C80A070B023403020360006442100001A000000FD00314B1E5F19000A202020202020000000FC00504132343851560A2020202020000000FF004D314C4D51533035323135370A014D02032AF14B900504030201111213141F230907078301000065030C001000681A00000101314BE6E2006A023A801871382D40582C450006442100001ECD5F80B072B0374088D0360006442100001C011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E960006442100001800000000000000000000000000DC",
label: "ASUS PA248QV, 1920x1200",
},
{
value:
"00FFFFFFFFFFFF0010AC132045393639201E0103803C22782ACD25A3574B9F270D5054A54B00714F8180A9C0D1C00101010101010101023A801871382D40582C450056502100001E000000FF00335335475132330A2020202020000000FC0044454C4C204432373231480A20000000FD00384C1E5311000A202020202020018102031AB14F90050403020716010611121513141F65030C001000023A801871382D40582C450056502100001E011D8018711C1620582C250056502100009E011D007251D01E206E28550056502100001E8C0AD08A20E02D10103E960056502100001800000000000000000000000000000000000000000000000000000000004F",
label: "DELL D2721H, 1920x1080",
},
{
value:
"00ffffffffffff0010ac0100020000000111010380221bff0a00000000000000000000adce0781800101010101010101010101010101000000ff0030303030303030303030303030000000ff0030303030303030303030303030000000fd00384c1f530b000a000000000000000000fc0044454c4c2049445241430a2020000a",
label: "DELL IDRAC EDID, 1280x1024",
},
];
const streamQualityOptions = [
{ value: "1", label: t("High") },
{ value: "0.5", label: t('Medium') },
{ value: "0.1", label: t('Low') },
];
// Video enhancement settings from store // Video enhancement settings from store
const { const {
videoSaturation, videoSaturation,

View File

@ -366,11 +366,7 @@ export default function KvmIdRoute() {
const sessionUrl = `${CLOUD_API}/webrtc/session`; const sessionUrl = `${CLOUD_API}/webrtc/session`;
console.log("Trying to get remote session description"); console.log("Trying to get remote session description");
setLoadingMessage( setLoadingMessage(t('Getting_remote_session_description',{ attempt: signalingAttempts.current > 0 ? t('attempt_num', { num:signalingAttempts.current + 1 }) : '' }));
t('Getting_remote_session_description',{
attempt:signalingAttempts.current > 0 ? t('attempt_num',{num:signalingAttempts.current + 1}) : ''
})
);//Getting remote session description... ${signalingAttempts.current > 0 ? `(attempt ${signalingAttempts.current + 1})` : ""}`,
const res = await api.POST(sessionUrl, { const res = await api.POST(sessionUrl, {
sd, sd,
// When on device, we don't need to specify the device id, as it's already known // When on device, we don't need to specify the device id, as it's already known